How Make a Sprite Node Rotate Around Another Node? (One More Line) - swift

So, I am trying to challenge my self by recreating the popular App Store game, One More Line using SpriteKit and Swift 3; however, I am immediately having a big issue.
1)How do I get my node to rotate around another node when the user is tapping
2) I want my node to continue moving in the same direction it is facing when the user releases their finger (hope that makes sense...).
kinda like this
In my GameScene.sks I created a center node that is constantly rotating and a player. Then I did this:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
player.move(toParent: center)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
player.move(toParent: self)
}
override func update(_ currentTime: TimeInterval) {
let dx = 5 * cos(player.zRotation)
let dy = 5 * sin(player.zRotation)
player.physicsBody?.applyImpulse(CGVector(dx: dx, dy: dy))
}
player moves to the right and when I tap it circles around the node, when I release it continues to move to the right.
I know that I am going about this all wrong. Any help would be very much appreciated. Thanks!

I'm not sure I completely understand what you are looking for, but if you simply want a sprite to rotate evenly around a centre sprite, add the centre sprite, another centre sprite (invisible) and add your outer sprite to the invisible centre sprite. Then rotate your two centre sprites. Adjust the outerObject's x position to bring the outerObject closer or further from the centre object.
import SpriteKit
import GameplayKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
anchorPoint = CGPoint(x: 0.5, y: 0.5)
let centerObject = SKSpriteNode(texture: nil, color: UIColor.blue, size: CGSize(width: 20, height: 20))
addChild(centerObject)
let invisibleParent = SKSpriteNode()
addChild(invisibleParent)
let outerObject = SKSpriteNode(texture: nil, color: UIColor.red, size: CGSize(width: 50, height: 50))
outerObject.position.x = 100
invisibleParent.addChild(outerObject)
centerObject.run(SKAction.repeatForever(SKAction.rotate(byAngle: 1, duration: 1)))
invisibleParent.run(SKAction.repeatForever(SKAction.rotate(byAngle: -1, duration: 1)))
}
}

Related

Changing the angle of a SKSpriteNode during a rotation

I am trying to make a drifting game. In order for the car to drift, the car (when turning) needs to be at an angle. I have tried rotation, however this conflicts with the code I already have for turning the car. Here is my code, any help?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.previousLocation(in: self)
let position = touch.location(in: self)
let node = self.nodes(at: location).first
if position.x < 0 {
let rotate = SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(M_PI), duration: 0.8))
car.run(rotate, withKey: "rotating")
} else {
let rotate = SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(-M_PI), duration: 0.8))
car.run(rotate, withKey: "rotating")
}
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
car.position = CGPoint(x:car.position.x + cos(car.zRotation) * 3.0,y:car.position.y + sin(car.zRotation) * 3.0)
}
}
This code currently turns the car without adding any angle, or "drifting" effect.
one approach is you could nest your car inside another SKNode as a container. apply your steering rotation to the car node, as you're doing it now. then apply the drift rotation to the container node. the result effect will be the sum of the two.
//embed car inside a SKNode container so you can apply different rotations to each
let car = SKShapeNode(ellipseOf: CGSize(width: 20, height: 40)) //change to how you draw your car
let drift_container = SKNode()
drift_container.addChild(car) //embed car inside the container
self.addChild(drift_container) //`self` here is a SKScene
//apply angle rotation to the container
func drift(byAngle angle:CGFloat) {
let rotate = SKAction.rotate(toAngle: angle, duration: 0.2)
drift_container.run(rotate)
}
then in update be sure to update drift_container.position instead of the car's position

SKPhysicsJointFixed doesn't keep nodes together while moving one

I've created 2 SKSpriteNodes, and connected them by a SKPhysicsJointFixed, to keep them stuck together. The problem is when I apply a SKAction.move(by:, duration:) to the first, it moves alone. why is that, and how can I move them together? I've searched a lot, but can't seem to find any new or useful information. Please help. Thanks in advance.
Here's the code:
import SpriteKit
class myGame: SKScene {
var node1: SKSpriteNode!
var node2: SKSpriteNode!
func createNode(_ position: CGPoint, color: UIColor) -> SKSpriteNode {
let node = SKSpriteNode(color: color, size: CGSize(width: 50, height: 50))
node.position = position
node.physicsBody = SKPhysicsBody(rectangleOf: node.size, center: position)
node.physicsBody?.affectedByGravity = false
node.physicsBody?.allowsRotation = false
return node
}
func setup() {
node1 = createNode(.zero, color: .red)
node2 = createNode(CGPoint(x: 0, y: -50), color: .green)
self.addChild(node1)
self.addChild(node2)
let anchor = CGPoint(x: node1.size.width/2, y: -node1.size.height/2)
let joint = SKPhysicsJointFixed.joint(withBodyA: node1.physicsBody!, bodyB: node2.physicsBody!, anchor: anchor)
physicsWorld.add(joint)
}
override func didMove(to view: SKView) {
setup()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
node1.run(SKAction.move(by: CGVector(dx: 0, dy: 100), duration: 2))
}
}
This is very strange indeed, but I have encountered similar things before.
Its the AllowRotation on the physicsBody that creates the problem.
fix:
node.physicsBody?.allowsRotation = true
Note:
your physics body for the second node is a bit off. I suggest you do like this instead:
node.physicsBody = SKPhysicsBody(rectangleOf: node.size)
And your joint is currently in the right corner of the nodes, Fix:
let anchor = CGPoint(x: 0, y: -node1.size.height/2)
unless you want it to be like that ofc :)
One last tip if you don't already know it. set showPhysics in your gameViewController to see an outline of your physics bodies. it does help a lot when working with physics.
view.showsPhysics = true

SKCameraNode working weird

I'm trying to create a simple SpriteKit game. I have a player that starts from the bottom-center of the screen.
I added to my GameScene a camera to follow the player but it does not work. when I run it with this code:
class GameScene: SKScene {
let mPlayer = Player(circleOfRadius: 45, fillColor: myColors.blue, strokeColor: myColors.red)
let cameraNode = SKCameraNode()
override func didMove(to view: SKView) {
setup()
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
moveCamera()
Player.movePlayerUp(mPlayer: mPlayer)
}
func setup(){
mPlayer.position = CGPoint(x: self.frame.midX - PLAYER_WIDTH, y: self.frame.minY + PLAYER_HEIGHT)
self.camera?.position = mPlayer.position
self.camera = cameraNode
self.addChild(cameraNode)
self.addChild(mPlayer)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
mPlayer.run(SKAction.moveTo(x: location.x, duration: 0.1))
}
}
func moveCamera(){
let moveAction = SKAction.moveTo(y: mPlayer.position.y, duration: 0.1)
cameraNode.run(moveAction)
}
}
the player is starting from the bottom and immediately moves to the center of the screen like in this picture:
How can I make the camera to follow the player from the start and move with it to the top?
Hope my question is clear and sorry for the size of the picture.
This code works for me in a empty Xcode project. You are probably thinking its not because your background image is 1 color and you are only moving the player briefly.
Also in your update method you set to move the player constantly to the middle, which is not necessary.
Try adding some stripes to the background to make it easier to see if you move and than add this code to the update method do slowly move the player up constantly.
let action = SKAction.move(by: CGVector(dx: 0, dy: 5), duration: 1)
mPlayer.run(action)
You will see the camera is following the player correctly.
If you need to center your camera differently to the player e.g on the y axis than you just have to increase/decrease the y position of the camera.
let moveAction = SKAction.moveTo(y: mPlayer.position.y + 200, duration: 0.1)
cameraNode.run(moveAction)
Hope this helps

(Xcode Swift SpriteKit) How do I move a sprite in the direction it is facing

I have a sprite in the centre of the screen which can be rotated left or right which is determined by touching the left or right part of the screen.
What I would like to do is have the sprite continuously moving forwards but always in the direction it is facing. I know how to do basic movement with SKActions etc... but have no idea how I calculate the movement to be continuously in the direction that the sprite has rotated to?
Maths has never been my strong point so would very much appreciate some sample code to help me along.
var player = SKSpriteNode()
override func didMove(to view: SKView) {
player = SKSpriteNode(imageNamed: "4B.png")
player.setScale(0.3)
player.zPosition = 100
self.addChild(player)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let position = touch.location(in: self)
if position.x < 0 {
let rotate = SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(M_PI), duration: 2))
player.run(rotate, withKey: "rotating")
} else {
let rotate = SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(-M_PI), duration: 2))
player.run(rotate, withKey: "rotating")
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
player.removeAction(forKey: "rotating")
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
You will need to use sin and cos. An SKAction may not be the best thing for you, so I would just do this in the update method for now till you find a better spot:
sprite.position = CGPoint(x:sprite.position.x + cos(sprite.zRotation) * 10,y:sprite.position.y + sin(sprite.zRotation) * 10)
Where 10 is the magnitude that you want the sprite to move (aka move 10 pixels)
This assumes that angle 0 means the sprite is looking right, angle 90 (PI/2) is looking up, angle 180 (PI) is looking left, and angle 270 (3PI/2) is looking down.

swift 2: Sprite tilting effect

Looking for a method to tilt a sprite upwards on the right side when tapping the screen (like in flappy bird) Like a start of a rotation that returns to the place it were. I will use this as an effect of going faster then the sprite normally does.
I'll add the code I got so far below:
var player = SKSpriteNode()
override func didMoveToView(view: SKView) {
let playerTexture = SKTexture(imageNamed: "player")
player = SKSpriteNode(texture: playerTexture)
player.position = CGPoint(x: 200, y: 80)
player.physicsBody = SKPhysicsBody(texture: playerTexture, size: playerTexture.size())
player.physicsBody!.affectedByGravity = true
self.addChild(player)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
}