SpriteKit applyImpulse 不影响精灵

SpriteKit applyImpulse not affecting sprite

我有一个 Skier 类型的播放器节点,我想通过触摸和拖动绕 x 轴移动,类似于 this tutorial。我将我的播放器节点添加到场景中,它有一个 isDynamic 设置为 true 的物理体,但由于某种原因,当我触摸并拖动播放器时,它不会移动。我究竟做错了什么?这是我的 GameScene 和我的 Skier class:

滑雪者:

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
    }
}

游戏场景:

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)
    }
}

我发现我做错了什么。当我为 Skier class 设置我的物理体时,我为物理体分配了一个可选的:

self.physicsBody? = SKPhysicsBody(rectangleOf: size)

所以物理体实际上并没有分配给精灵。我通过将其更改为此来修复它:

self.physicsBody = SKPhysicsBody(rectangleOf: playerSize)

现在可以完美运行了。话虽这么说,对于任何其他试图通过手指拖动在场景中移动精灵来实现类似效果的人来说,我最终想出了一个更简单的解决方案。我的 touchesMoved 方法中有这个:

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)
}

它的工作原理完全不用担心更新、touchesBegan 或 touchesEnded 方法。更简单更容易。