简体   繁体   中英

SpriteKit applyImpulse not affecting sprite

I have a player node that is of type Skier that I want to move around the x-axis with a touch and drag similar to this tutorial . I added my player node to the scene and it has a physics body with isDynamic set to true, but for some reason when I touch and drag the player doesn't move. What am I doing wrong? Here is my GameScene and my Skier class:

Skier:

class Skier: SKSpriteNode {
    let playerTexture = SKTexture(imageNamed: "snowmanFancy_NE")
    let playerSize = CGSize(width: 24, height: 40)

    init () {
        super.init(texture: playerTexture, color: UIColor.clear, size: playerSize)
        self.name = "player"
        setPhysics()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setPhysics(){
        self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        self.physicsBody? = SKPhysicsBody(rectangleOf: size)
        self.physicsBody?.categoryBitMask = PhysicsCategory.player
        self.physicsBody?.contactTestBitMask = PhysicsCategory.tree | 
        PhysicsCategory.rock | PhysicsCategory.cabin | PhysicsCategory.snowman | 
        PhysicsCategory.marker
        self.physicsBody?.collisionBitMask = 0
        self.physicsBody?.allowsRotation = false
        self.physicsBody?.angularDamping = 0
        self.physicsBody?.isDynamic = true
    }
}

GameScene:

class GameScene: SKScene, SKPhysicsContactDelegate {
    var lastTouch: CGPoint? = nil

    var world = SKNode()
    var cam = SKCameraNode()

    var player = Skier()
    let playerDefaultYInset : CGFloat = 350

    var sceneVelocity = CGVector(dx: 0, dy: -170)
    var zPositionCounter: CGFloat = 0

    override func didMove(to view: SKView) {
        //Set up the scene
        self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        backgroundColor = SKColor.white

        //Add top-level world node to the scene
        self.addChild(world)

        self.physicsWorld.contactDelegate = self

        //Add player to scene
        spawnPlayer()
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        if let location = touch?.location(in: self) {
            lastTouch = location
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        if let location = touch?.location(in: self) {
            lastTouch = location
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        lastTouch = nil
    }

    override func update(_ currentTime: TimeInterval) {
        // Only add an impulse if there's a lastTouch stored
        if let touch = lastTouch {
            let impulseVector = CGVector(dx: touch.x - player.position.x, dy: 0)
            // If myShip starts moving too fast or too slow, you can multiply impulseVector by a constant or clamp its range
            player.physicsBody?.applyImpulse(impulseVector)
        }
    }

    func spawnPlayer() {
        player.position = CGPoint(x: 0, y: (-self.frame.height / 2) + playerDefaultYInset)
        player.zPosition = CGFloat(Int.min)
        world.addChild(player)
    }
}

I figured out what I was doing wrong. When I set up my physics body for the Skier class, I assigned the physics body like this with an optional:

self.physicsBody? = SKPhysicsBody(rectangleOf: size)

so the physics body wasn't actually being assigned to the sprite. I fixed it by changing it to this:

self.physicsBody = SKPhysicsBody(rectangleOf: playerSize)

and now it works perfectly. That being said, for anyone else trying to achieve something similar to this effect with a finger drag moving a sprite around a scene, I ended up coming up with a much simpler solution. I have this in my touchesMoved method:

let touch = touches.first
    if let location = touch?.location(in: self) {
        let prev = touch?.previousLocation(in: self)
        let impulse = CGVector(dx: 0.02 * (location.x - (prev?.x)!), dy: 0)
        player.physicsBody?.applyImpulse(impulse)
}

And it works without having to worry about the update, touchesBegan, or touchesEnded methods at all. Much simpler and easier.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM