Reputation: 682
I'm trying to make a snake game (like the one in old nokia phones) using SpriteKit. The problem is, when the snake's direction changes, the snake moves in a still vertical block, and doesn't get the L-shape (as shown in pic). To get into the context, I have a class named SKDSpriteNode
, which is the same SKSpriteNode, with an additional direction
property; the Snake
class has direction
and length
properties. There is a snakeBody
property, of type [SKDSpriteNode]
, containing the nodes of the snake body.
Snake's direction is assigned for .up
when game starts, and then it is assigned by the user's swipe.
And btw, the changeDirection
methods gets called when snake's direction changes (with didSet
). Here's the code and the pic:
extension ClassicLevelScene {
func startGame() { snake.direction = .up; moveSnake() }
func checkPlacement(for node: SKDSpriteNode) -> SKAction {
return SKAction.run({
if !(node.isInsideFrame(of: self)) { self.gameOver() }
})
}
func getMovement(for node: SKDSpriteNode) -> (once: SKAction, repetitive: SKAction) {
let movement = SKAction.move(by: node.direction.getVector(withIntensity: movementSpeed), duration: 0.5)
let moveAction = SKAction.sequence([movement, checkPlacement(for: node)])
let repetitiveMoveAction = SKAction.repeatForever(moveAction)
return (moveAction, repetitiveMoveAction)
}
func moveSnake() {
for node in snakeBody {
node.removeAllActions()
node.run(getMovement(for: node).1)
}
}
func moveOnce() {
for node in snakeBody {
node.removeAllActions()
node.run(getMovement(for: node).0)
}
}
func changeDirection() {
for i in 0..<snake.length {
if i == 0 {
snakeBody[i].direction = snake.direction
snakeBody[i].run(SKAction.move(by: snakeBody[i].direction.getVector(withIntensity: movementSpeed), duration: 0.5))
} else {
snakeBody[i].direction = snakeBody[i-1].direction
snakeBody[i].run(SKAction.move(to: snakeBody[i-1].oldPosition, duration: 0.5))
}
}
}
Upvotes: 2
Views: 128
Reputation: 16827
I need to post as an answer to show you code, but you should be only moving the head, and let the tail drag behind. Now there are better ways to do this, but for simplicity with code you have already written, here is what it should look like
extension ClassicLevelScene {
func startGame() { snake.direction = .up; moveSnake() }
func checkPlacement(for node: SKSpriteNode) -> SKAction {
return SKAction.run({
if !(node.isInsideFrame(of: self)) { self.gameOver() }
})
}
func getMovement(for node: SKDSpriteNode) -> (once: SKAction, repetitive: SKAction) {
let movement = SKAction.move(by: node.direction.getVector(withIntensity: movementSpeed), duration: 0.5)
let moveTail = SKAction.run({self.moveTail()})
let moveAction = SKAction.sequence([movement, moveTail,checkPlacement(for: node)])
let repetitiveMoveAction = SKAction.repeatForever(moveAction)
return (moveAction, repetitiveMoveAction)
}
func moveTail()
{
for i in 1..<snake.length {
snakeBody[i].direction = snakeBody[i-1].direction
snakeBody[i].position = snakeBody[i-1].oldPosition
}
}
func moveSnake() {
let head = snakeBody[0] {
head.removeAllActions()
head.run(getMovement(for: head).1)
}
}
func moveOnce() {
let head = snakeBody[0] {
head.removeAllActions()
head.run(getMovement(for: head).0)
}
}
func changeDirection() {
let head = snakeBody[0] {
head.removeAllActions()
head.direction = snake.direction
head.run(SKAction.move(by: head.direction.getVector(withIntensity: movementSpeed), duration: 0.5))
}
}
Upvotes: 2