How can setKey for value be used with SpriteKit? - ios

I'm making a platform game with SpriteKit, and I'm trying to use the method setValue:forKey:
inside of the touchesMoved:withEvent method because I have a mess: I need to remove an animation of type SKAction. I run this SKAction animation in touchesMoved:withEvent with an if, checking all the needed conditions. One of these conditions is this:
if(NO ==[[self childNodeWithName:#"hero"] hasActions])
{
//code to run animation
}
I check if it has no actions, because I don't want to create more animations than needed.
The animation runs forever while I touch the screen with my finger, and it will remove only if I remove my finger from the screen, in the touchesEnded:withEvent method
So until I'm touching the screen, the hero animation will loop forever. The problem I have is if I move my finger from the right side of the screen to the left side of the screen, the animation is still the same: the hero running to the right, even if the sprite is moving to the left, because the if check if there is actions, and don't create the new animation to the left, and of course don't remove the right animation.
I think I can fix it setting a key for the animation action, and removing it in the same method with an if and using the location of the finger. The problem is that I don't know how to use the removeActionForKey method. I've tried reading documentation but I didn't find it very clear. Can anyone post me some code example of how to use it?

You need to use runAction:withKey: method:
// if direction == right
[node removeActionForKey:#"left"];
SKAction *animationRight = [SKAction animateWithTextures:......];
[node runAction:animationRight withKey:#"right"];
...........
// if direction == left
[node removeActionForKey:#"right"];
SKAction *animationLeft = [SKAction animateWithTextures:......];
[node runAction:animationLeft withKey:#"left"];

Related

Adding child SKNode to existing SKNode changes the touch area

I'm create a SKNode to the scene and logging touch events on each individual SKNode. I can add as many as I want and the touches work as expected, if I touch the node and only the visible node do I see the log messages. Now, if I add another SKShapeNode to any of the previous SKNode's the touch area expands to be more of a rectangle and now I see the log message even if I touch outside the origin SKNode.
The first picture shows the original touch area of the SKNode and the second is the new touch area after adding a child SKShapeNode to that SKNode. The SKShapeNode being added is 20x20 so it fits within the 20x100 bar.
The problem is I now get multiple touch events when touching the other bars since they overlap. Is there any way around this?
You appear to be using separate graphics for each angle of your line. Instead try using the same graphic with your line at 0 degrees and then using the zRotation to angle it. I have not tried this myself but I think it will fix your issue.
Alternately try using containsPoint for your touch recognition in the touchesBegan method. You can check if the touch is within any of the nodes and process accordingly.

How can I stop a UIView movement in Swift?

I'm messing around with Swift for the first time and have a square on the screen. The square starts by moving to the right. When I tap on it I want it to go up. I don't want it to continue to the right at all, I want it to just go straight up. Unfortunately the physics and gravity make it curve to the right some more before it goes up. What can I do to completely stop the gravity pull and acceleration of my object, before setting the gravity to the new value?
This turns the object in the right direction, but I need it to come to an instant stop before doing this.
if(self.gravity.gravityDirection.dx == 1){
self.gravity.gravityDirection = CGVectorMake(-1.0, 0.0)
}
The way to stop an item being affected by a behavior is to remove the item from the behavior or remove the behavior from the animator. For example, here you might remove self from the existing gravity behavior.

finding direction and angle of swipe in Xcode

I've just started work on a new game in which the player will fire a projectile by swiping in the direction he needs it to go in. I know how to detect if a swipe is left, right, up, or down using gesture recognizer, but I need to know how to get the angle of the swipe so the projectile can be fired in whatever direction and at whatever angle the player desires.
Sounds like you want to use a UIPanGestureRecognizer instead. Unlike the swipe recognizer, it's called continuously but with different states, so you could do something as simple as just handling the start and end states.
Docs:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIPanGestureRecognizer_Class/index.html

Cocos2d V3 and Spritebuilder - Timeline animation not running subsequent times

I have a CCB file with a timeline animation in it. I load the file like this.
CCSprite *spriteAnimation = (CCSprite*)[CCBReader load:#"MyGreatAnimation"];
spriteAnimation.paused = TRUE;
At some point later, I add it to the scene and run the animation
[MyScene addChild:spriteAnimation];
CCAnimationManager* animationManager = _deletionAnimaion.userObject;
[animationManager runAnimationsForSequenceNamed:#"Default Timeline"];
This is great. My animation runs. I then remove spriteAnimation from the scene until I need it again.
[spriteAnimation removeFromParent];
.
The problem
I can't figure out how to get the animation to run the next time I add it to the scene.
I've tried:
[animationManager jumpToSequenceNamed:#"Default Timeline" time:0];
And also..
[animationManager runAnimationsForSequenceNamed:#"Default Timeline"];
But the animation doesn't seem to run. If at this point I call:
spriteAnimation.userObject.runningSequenceName
to see the running sequence, it returns NULL.
.
My Question
How do I arbitrarily run a timeline animation repeatedly?
To be clear, I'm not asking about looping the animation. I want to start it from frame 1 whenever I need.
If you need it repeatedly, you shouldn't remove it from the scene:
[spriteAnimation removeFromParent];
Instead, just make the animation invisible for the time being:
spriteAnimation.visible = NO;
Later just make it visible again.
After all when you remove a node it is gone from the scene hierarchy unless you addChild: it back in which I can't see in your code above.

Is it possible to end an SKAction mid-action?

I have a subclass of SKSpriteNode (monsterNode). It automatically runs around the screen using vectors to follow the player. I am currently using the following action to make it run around:
SKAction *actionMove = [SKAction moveTo:actualDistance duration:time];
[self runAction:actionMove completion:^ {
_currentState = SVGMonsterStateIdle;
}];
I am wondering if its possible to make it so the monsterNode actually STOPS running the action if it hits the boundary of the iOS device screen. I currently have SKSpriteNode boundaries on the edges of the screen, linked with a contact delegate to notify if the monster and walls make contact. However, that means nothing if I can't actually stop the monster's actionMove action from going to completion. The monster needs to stop at the boundaries of the screen. If it is not possible to stop an SKAction mid-execution, is there a roundabout way to do so?
Look at the SKNode.h header file - it has two functions listed:
- (void)removeActionForKey:(NSString *)key;
- (void)removeAllActions;
The latter will work: [monsterNode removeAllActions];

Resources