在不禁用触摸的情况下完成 SpriteNode 上的操作 运行

Finish action running on a SpriteNode without disabling touches

我有一个玩家的 physicsBody 分为多个部分(躯干、腿、头等),现在我在屏幕上有一个控制玩家移动的按钮,如果向右按下按钮玩家向右移动,那部分工作正常。问题是每次运动改变时都会调用 walk() 方法,它所做的是让玩家的腿看起来像在走路,但如果运动没有停止,那么就会继续调用 walk() 而不会完成动画,所以它看起来像是来回卡住。我想要实现的是让玩家能够不断地行走,但是 walk() (动画方法)被调用一次,完成,然后再次调用(只要仍然按下行走按钮)。这是我目前所拥有的:

func walk(){
    let leftFootWalk = SKAction.run {
        let action = SKAction.moveBy(x: 1, y: 0.1, duration: 0.1)
        let actionReversed = action.reversed()
        let seq = SKAction.sequence([action, actionReversed])
        self.leftUpperLeg.run(seq)
        self.leftLowerLeg.run(seq)
    }

    let rightFootWalk = SKAction.run {
        let action = SKAction.moveBy(x: 0.4, y: 0.1, duration: 0.1)
        let actionReversed = action.reversed()
        let seq = SKAction.sequence([action, actionReversed])
        self.rightUpperLeg.run(seq)
        self.rightLowerLeg.run(seq)
    }

    let group = SKAction.sequence([leftFootWalk, SKAction.wait(forDuration: 0.2), rightFootWalk])

    run(group)
}


extension GameScene: InputControlProtocol {
func directionChangedWithMagnitude(position: CGPoint) {
    if isPaused {
        return
    }

    if let fighter = self.childNode(withName: "fighter") as? SKSpriteNode, let fighterPhysicsBody = fighter.physicsBody {

        fighterPhysicsBody.velocity.dx = position.x * CGFloat(300)
        walk()

        if position.y > 0{
            fighterPhysicsBody.applyImpulse(CGVector(dx: position.x * CGFloat(1200),dy: position.y * CGFloat(1200)))
        }else{
            print("DUCK") //TODO: duck animation
        }
    }
}

我能够解决这个问题,但是我仍然确定有更好的方法,所以如果您知道,请务必告知。这是我所做的: 首先,我添加了一个名为 isWalking 的布尔值,以了解行走动画是开启(真)还是关闭(假),并将其设置为假。然后我添加了 if 语句以仅在动画关闭(false)时调用 walk()并将布尔值设置为 on(true)。

func directionChangedWithMagnitude(position: CGPoint) {
    if isPaused {
        return
    }

    if let fighter = self.childNode(withName: "fighter") as? SKSpriteNode, let fighterPhysicsBody = fighter.physicsBody {

        fighterPhysicsBody.velocity.dx = position.x * CGFloat(300)
        print(fighterPhysicsBody.velocity.dx)

        if !isWalking{
            isWalking = true
            walk()
        }
    }
}

并且我更改了 walk() 以使用完成块并再次将布尔值设置为 off(false)

func walk(){
    let walkAction = SKAction.moveBy(x: 5, y: 5, duration: 0.05)
    let walk = SKAction.sequence([walkAction, walkAction.reversed()])

    leftUpperLeg.run(walk) {
        self.rightUpperLeg.run(walk)
    }

    leftLowerLeg.run(walk) { 
        self.rightLowerLeg.run(walk, completion: { 
            self.isWalking = false
        })
    }
}

首先你可以使用SKAction.runBlock({ self.doSomething() }) 作为动作序列中的最后一个动作,而不是使用完成。

关于你的问题,你可以使用hasAction判断你的SKNode目前是否运行任何动作,你可以使用key机制更好的进行动作管理

看下一个问答 checking if an SKNode is running a SKAction