-7

I'm working on a Snake Game using swift and the library SpriteKit.

I reached the point where I have to create the tail of the snake. The code I made works with 2 arrays: snakeX and snakeY. Both of them are global empty arrays of type CGFloat. At every execution, I add to these arrays the X player position and the Y player position. If the score doesn't change, I delete the last element of both arrays. In this way, If the score is 0, I'll always have only one element for each array. But then, if the score changes, I don't delete the last element. Therefore, is the score increases by 1, I'll have 2 elements for each array... etc. etc.

The elements stored in snakeX and snakeY arrays represents the previous player position. In this way, I'll display the snake tail in this position and the tail will follow the head. But here's the problem. The snake's head moves 56 pixels every 0.1 seconds. BUT, at each run, it moves 8 pixels. Because of this, the "previous player position coordinates" stored in the snakeX and snakeY arrays are always 8 pixels less than the current player position. Basically... the tail will be covered for 1/7 by the snake's head.

To avoid this problem I thought I could just tell the program to wait for 0.1s before adding the previous player position coordinates to the snakeX and snakeY arrays, but the rest of the code keep running and when it will try to access to the element in position 0 of the array snakeX (or snakeY) it won't find anything because it will appear an element only after 0.1s. I also tried to call the function makeTail() only after 7 execution (8 pixel * 7 execution = 56 pixel ). This worked, but 60fps aren't enough and the tail keeps blitzing.

Here's the code I used to create the tail:

func makeTail(){
    snakeX.insert(player.position.x, at: 0)
    snakeY.insert(player.position.y, at: 0)
    if firstTime == false{ //this variable starts equal true. This avoids the error "out of index". Without this variable, with score = 0 the program would't find any item in the arrays
        if prevscore == score { //if the score doesn't change, remove
            snakeX.removeLast() //the last element of both arrays
            snakeY.removeLast()
        }
        else { //if the score changes, don't delete anything and just
            prevscore += 1 // add 1 to the previous score variable
        }
    }
    for i in 0...score{ //call the function "spawnTail" once if the
        spawnTail(index:i) // score is equal to 0, twice if the score is equale to 1... etc. etc.
    }
    firstTime = false
}

func spawnTail(index:Int){
    let tail = SKSpriteNode(imageNamed: "tail")
    let endPoint = CGPoint(x: player.position.x, y: player.position.y)
    tail.zPosition = 1
    tail.setScale(2)
    tail.position.x = snakeX[index]
    tail.position.y = snakeY[index]
    self.addChild(tail)

    //let waitToMove = SKAction.wait(forDuration: 0.1)
    let moveTail = SKAction.move(to: endPoint, duration:0.1/8)
    let deleteTail = SKAction.removeFromParent()
    let tailSequence = SKAction.sequence([moveTail, deleteTail])
    tail.run(tailSequence)
}
Jacopo
  • 123
  • 1
  • 10

3 Answers3

3

Use

DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
  test.append(number)
}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • why if I use this method, all variables inside this two braces needs ```self.``` before the variable name? – Jacopo Jan 03 '20 at 23:50
2
let number = 5
var test = [Int]()

@objc func addNumber() {
    test.insert(number, at: 0)
}

self.perform(#selector(addNumber), with: nil, afterDelay: 3.0)
Nilesh Mahajan
  • 607
  • 4
  • 16
1

You can also make global function and use,

func delay(interval: TimeInterval, closure: @escaping () -> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + interval) {
        closure()
    }
}

Then Use,

let number = 5
var test = [Int]()

//WAIT 3s

delay(interval:3.0, closure: {
   test.insert( number, at:0)
 })
Kishan Bhatiya
  • 2,175
  • 8
  • 14