1
votes

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?

2
A lot of issues here…You shouldn't use Timer. It is not paired with a game loop. Second, you shouldn't apply a new action 60 times per second in order to implement target and a seeker behaviour Next, a good thing to keep in mind is that actions, once created, can't be modified. Means, that when you set action's parameters once, you can't modify them later. Also, your Enemy variable is global, which doesn't make sense for me. It only keeps a reference to last enemy added. What I mean to say, is that your logic is probably wrong in that case too...Whirlwind

2 Answers

2
votes

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")
-1
votes

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.