Fayyouz
Fayyouz

Reputation: 682

Snake moves in vertical block

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))
        }
    }
}

screenshot

Upvotes: 2

Views: 128

Answers (1)

Knight0fDragon
Knight0fDragon

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

Related Questions