swiftswiftuisprite-kitspritegame-development

SpriteKit Beginner: Mouse Node Not Moving to Random Locations


I’m a beginner playing around with SpriteKit, and I created a file called GameScene. It contains only one node called mouse. My goal is to animate the mouse and move it to random locations when the app starts. However, while the mouse appears on the simulator screen, it doesn’t move. I’m not sure what I’m doing wrong.

import Foundation
import SpriteKit


class GameScene: SKScene {
    
    override func didMove(to view: SKView) {
        // Load the SKScene from the file
        if let scene = loadSKscene() {
            // Present the scene
            self.view?.presentScene(scene)
            
            // Find the "mouse" node from the loaded scene
            if let mouse = scene.childNode(withName: "mouse") {
                print("Mouse OK!")
                moveMouseRandomly(mouse)
            } else {
                print("Error: Mouse node not found!")
            }
            print("Scene size: \(scene.size)")
        } else {
            print("Error: Failed to load GameScene.sks")
        }
    }
    
    func loadSKscene() -> SKScene? {
        // Load GameScene.sks from the file
        guard let scene = SKScene(fileNamed: "GameScene") else {
            return nil
        }
        scene.scaleMode = .resizeFill
        return scene
    }
    
    func moveMouseRandomly(_ node: SKNode) {
        // Generate a random position within the scene's bounds
        let moveToRandomPosition = SKAction.move(to: randomPosition(), duration: 1.5)
        let wait = SKAction.wait(forDuration: 0.5)
        let sequence = SKAction.sequence([moveToRandomPosition, wait])
        let repeatForever = SKAction.repeatForever(sequence)
        
        // Run the action on the mouse node
        node.run(repeatForever)
        print("animate")
    }
    
    func randomPosition() -> CGPoint {
        // Generate a random position within the scene's bounds
        let x = CGFloat.random(in: 0...size.width)
        let y = CGFloat.random(in: 0...size.height)
        return CGPoint(x: x, y: y)
    }
}


struct ContentView: View {
  
    @State var scene = GameScene()
  
    var body: some View {
        SpriteView(scene: scene)
            .ignoresSafeArea()
    }
}


Solution

  • you have two issues. first, SKAction objects get baked in early -- this is for efficiency. so your random positions aren't being recalculated. using SKAction.run will solve this. second, you should send the size into the action function since this value gets recomputed frequently.

    func moveMouseRandomly(_ node: SKNode, forSize scene_size:CGSize) {
        node.removeAction(forKey: "random movement")
        
        let moveToRandomPosition = SKAction.run {
            let x = CGFloat.random(in: 0...scene_size.width)
            let y = CGFloat.random(in: 0...scene_size.height)
            let p = CGPoint(x: x, y: y)
            node.run(SKAction.move(to: p, duration: 0.5))
        }
        let wait = SKAction.wait(forDuration: 1)
    
        let sequence = SKAction.sequence([moveToRandomPosition, wait])
        let repeatForever = SKAction.repeatForever(sequence)
    
        node.run(repeatForever, withKey: "random movement")
        print("animate")
    }
    

    and change didMove(to view: SKView) accordingly:

    moveMouseRandomly(mouse, forSize: scene.size)