Reputation: 1292
i have a player who's physicsBody is divided to parts (torso, legs, head, ect), now i have a button on screen that control the movement of the player, if the button is pressed to the right the player moves to the right, and that part works fine. the problem is every time the movement changes the walk() method is called and what it does is animate the player legs to look like its walking, but if the movement doesn't stop then is keeps calling the walk() without it finishing the animation, so it looks like its stuck back and forth. what i am trying to achieve is for the player to be able to walk constantly but for the walk() (animation method) to be called once, finish, then called again(as long as the button to walk is still pressed). here what i have so far:
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
}
}
}
Upvotes: 1
Views: 175
Reputation: 1202
First of all you can use SKAction.runBlock({ self.doSomething() })
as the last action in your actions sequence instead of using completion.
About your question, you can use hasAction
to determine if your SKNode
is currently running any action, and you can use the key mechanism for better actions management.
See the next Q&A checking if an SKNode is running a SKAction
Upvotes: 1
Reputation: 1292
I was able to solve this, however i'm still sure there is a better approach out there so if you know it be sure to tell. here is what i did: first i added a Boolean called isWalking to know if the walking animation is on(true) or off(false) and i set it to false. then i added the if statement to call walk() only if the animation is off(false) and it sets the boolean to 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()
}
}
}
and i changed walk() to use completions blocks and set the Boolean to off(false) again
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
})
}
}
Upvotes: 0