Pierre Courpron
Pierre Courpron

Reputation: 154

how to make an SKSpriteNode follow another SKSpriteNode

Running into some trouble with my code. I'm trying to make zombies follow my player around with the following code:

class GameScene: SKScene, SKPhysicsContactDelegate {
    func Enemies() {
        Enemy = SKSpriteNode(imageNamed: "Spaceship")
        Enemy.size = CGSize(width: 50, height: 50)
        Enemy.color = UIColor(red: 0.9, green: 0.1, blue: 0.1, alpha: 1.0)
        Enemy.colorBlendFactor = 1.0

        //physics
        Enemy.physicsBody = SKPhysicsBody(rectangleOf: Enemy.size)
        Enemy.physicsBody?.isDynamic = true
        Enemy.physicsBody?.affectedByGravity = false
        Enemy.name = "Enemy"

        Enemy.position.y = -frame.size.height/2
        let positionX = arc4random_uniform(UInt32(frame.size.width))
        Enemy.position.x = CGFloat(positionX)
        addChild(Enemy)
    }

    override func didMove(to view: SKView) {

        enemyTimer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(GameScene.Enemies), userInfo: nil, repeats: true)

    override func update(_ currentTime: TimeInterval) {
        Enemy.run(SKAction.move(to: ship.position, duration: 3))
    }

If I run this code, I can spawn the zombies, but they will not follow my main player, they will just go to the position that he was at when they were spawned (i.e. zombie spawned at time = 0 will go to the ship position at time = 0, zombie spawned at time = 1 will go to the ship position at time = 1, and so on). However, if I run this code while only spawning one zombie like so:

override func didMove(to view: SKView) {
    Enemies()
}

The lone zombie will follow my player around. Any idea why the code works for one zombie, but not for multiple zombies?

Upvotes: 1

Views: 862

Answers (2)

Knight0fDragon
Knight0fDragon

Reputation: 16827

I would not recommend constantly adding actions on your update cycle, you are going to suffer from performance loss due to all the things that happen behind the scenes. Instead, use an SKAction.customAction that you would only add to your sprite once.
Here is an example of a custom action that will do what you want, remember only assign it once. (Code is not tested, so may need edits)

let customActionBlock = 
{
  (node,elapsedTime) in 
  let dx = ship.x - node.position.x
  let dy = ship.y - node.position.y 
  let angle = atan2(dx,dy)
  node.position.x += sin(angle) * speedPerFrame
  node.position.y += cos(angle) * speedPerFrame

}

let duration = TimeInterval(Int.max) //want the action to run infinitely
let followPlayer = SKAction.customAction(withDuration:duration,actionBlock:customActionBlock)
Enemy.run(action:followPlayer,withKey:"follow")

Upvotes: 3

Alistra
Alistra

Reputation: 5195

Maybe you should removeAllActions() on Enemy before readding an action. It seems that you have actions that take 3 seconds, but you add an action every frame, so it has at most 180 actions for a node at once.

Upvotes: -1

Related Questions