In SpriteKit, I want to position a spaceship sprite so that:
(a) Rotates clockwise, or counterclockwise.
(b) The sprite rotates and it's nose always pointing to the centre, regardless of where it is on the circle.
Currently I have this output:
...
My ideal output is as shown
My code now follows:
class GameScene: SKScene {
lazy var circleNode:SKShapeNode = {
var circle = SKShapeNode(circleOfRadius: 200)
circle.position = CGPoint(x: frame.midX, y: frame.midY)
circle.strokeColor = SKColor.purple
circle.lineWidth = 10.0
circle.glowWidth = 2.0
circle.physicsBody?.isDynamic = false
return circle
}()
lazy var shipNode: SKSpriteNode = {
var sprite = SKSpriteNode(imageNamed: "ship")
sprite.position = CGPoint(x: circleNode.frame.minX, y: circleNode.frame.minY)
sprite.xScale = 2
sprite.yScale = 2
sprite.zPosition = 1
return sprite
}()
class func newGameScene() -> GameScene {
// Load 'GameScene.sks' as an SKScene.
guard let scene = SKScene(fileNamed: "GameScene") as? GameScene else {
print("Failed to load GameScene.sks")
abort()
}
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
return scene
}
func setUpScene() {
self.addChild(circleNode)
self.addChild(shipNode)
}
override func didMove(to view: SKView) {
self.setUpScene()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if let location = touch?.location(in: self){
if location.x > shipNode.position.x {
let moveToRight = SKAction.moveBy(x: 1, y: 0, duration: 5)
let forever = SKAction.repeatForever(moveToRight)
shipNode.run(forever, withKey: "move")
}else{
let moveToLeft = SKAction.moveBy(x: -1, y: 0, duration: 5)
let forever = SKAction.repeatForever(moveToLeft)
shipNode.run(forever, withKey: "move")
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
shipNode.removeAction(forKey: "move")
}
}
I tried to add a SKAction.follow
func setUpScene() {
self.addChild(circleNode)
self.addChild(shipNode)
let circularMove = SKAction.follow(circleNode.path!, asOffset: false, orientToPath: true, duration: 5)
shipNode.run(SKAction.repeat(circularMove,count: 2))
}
But the problem here is it is animating by itself around the path, which is not what I'm after. Instead, only user touches should make the ship move clockwise or counterclockwise.
How do I ensure:
(a) The sprite sits on the circular path (b) The sprite's nose is always pointing to center of circle
Many thanks
You can achieve this by adding your ship to a container (an SKNode
), positioning the ship on a point on the circle (at zero degrees), pointing the ship toward the center of the circle, and then rotating the container. Here's an example...
let sprite = SKSpriteNode(imageNamed:"your_ship_name")
let container = SKNode()
override func didMove(to view:SKView) {
let numRotations:CGFloat = 100
let circleRadius:CGFloat = 200
addChild(container)
// Rotate so the ship initially points to the center
sprite.zRotation = CGFloat.pi/2
sprite.position = CGPoint(x: circleRadius, y: 0)
container.addChild(sprite)
let rotate = SKAction.rotate(byAngle: 2 * CGFloat.pi * numRotations, duration: 5 * TimeInterval(numRotations))
container.run(rotate.reversed())
}