SKSpriteNode follow CGPath plus adding SKAction - ios

I am making a game and I want an enemy to move in a circle but the enemy should have constant movement to the left as well. I have tried to create a circle path with CGPath and make it follow that path and then added a SKAction with constant left movement. But it seems that the node is just following the CGPath without left movement.
Is there any other way to make this possible?
This is my code at the moment:
CGMutablePathRef circle = CGPathCreateMutable();
CGPathAddArc(circle, NULL, 0, 0, 80, 0, 2*M_PI, true);
CGPathCloseSubpath(circle);
SKAction *followTrack = [SKAction followPath:circle asOffset:NO orientToPath:NO duration:1.5];
SKAction *forever = [SKAction repeatActionForever:followTrack];
[enemy runAction:[SKAction moveByX:-1000 y:0 duration:3.0]];
[enemy runAction:forever];

You can't move the same node with 2 move actions. What you can do is place the node in a container node. Then move the container node left while its child moves in a circle.
Another option is to not use SKActions and use something more dynamic and real-time by computing the centripetal velocity manually and shifting the centripetal point overtime. You can see an example of this in my answer here.

Related

SKAction to Change AnchorPoint?

I am creating a relatively complicated animation sequence. In it, a certain SKSpriteNode (shark) does two rotations. At the beginning of the animation, it rotates around a certain anchor point ap1, then later rotates around a different anchor point ap2. How should I change anchor points midway through an animation sequence?
Some initial thoughts:
I could change the anchor point outside of SKActions, in the update: loop perhaps.
I could use multiple SKSpriteNodes for the same shark sprite (with their respective anchor points), switching (hiding/showing) the sprite nodes when I need to change the anchor point.
Since changing a sprite's anchor point affects where it's rendered, you will likely need to make some sort of adjustment to prevent the sprite from appearing to suddenly move to a new location. Here's one way to do that:
Create action that changes the anchor point
SKAction *changeAnchorPoint = [SKAction runBlock:^{
[self updatePosition:sprite withAnchorPoint:CGPointMake(0, 0)];
}];
SKAction *rotate = [SKAction rotateByAngle:2*M_PI duration: 2];
Run action to rotate, change the anchor point, and rotate
[sprite runAction:[SKAction sequence:#[rotate,changeAnchorPoint,rotate]] completion:^{
// Restore the anchor point
[self updatePosition:sprite withAnchorPoint:CGPointMake(0.5, 0.5)];
}];
This method adjusts a sprite's position to compensate for the anchor point change
- (void) updatePosition:(SKSpriteNode *)node withAnchorPoint:(CGPoint)anchorPoint
{
CGFloat dx = (anchorPoint.x - node.anchorPoint.x) * node.size.width;
CGFloat dy = (anchorPoint.y - node.anchorPoint.y) * node.size.height;
node.position = CGPointMake(node.position.x+dx, node.position.y+dy);
node.anchorPoint = anchorPoint;
}
As Julio Montoya said, the easiest way to do this is to just "translate" code into an SKAction with the method [SKAction runBlock:myBlock].

SKAction starting point

How do you set the starting point for a SKAction? I am trying to animate a node in a circle, but I can't set the starting position. It always is set by default. Here is my code:
CGPathRef circle = CGPathCreateWithEllipseInRect(CGRectMake(self.frame.size.width/2-75,self.frame.size.height/2-75,150,150), NULL);
self.circlePathActionClockwise = [SKAction followPath:circle asOffset:NO orientToPath:YES duration:5.0];
self.circlePathActionClockwise = [SKAction repeatActionForever:self.circlePathActionClockwise];
//[self.ball runAction:self.circlePathActionClockwise];
self.ball.speed = 1.0;
The starting point of the circle, when trying to move it, is based on the circles position. Try setting the position property like so:
circle.position = CGPointMake(100,100);
The above will set the position of the circle to 100,100.
CGPointMake takes the first number as the x axis coordinate and the second number as the y axis coordinate. I hope that helps.

Inverted texture caused from SKAction following a CGPath

"orientToPath:YES" is causing the texture of an SKSpriteNode to be rotated 180 degrees while it follows the path. I still want the node's zRotation to adjust while following the path, but I want the texture to be facing its original direction.
SKAction *path = [SKAction followPath:cgpath asOffset:NO orientToPath:YES duration:5];
How can I fix this?
Setting your sprite node's yScale to -1 will flip the texture vertically. Your sprite should then be oriented correctly along the path.

SpriteKit MoveToX:duration from Current Stat

I am planning to move batch of sprite randomly accross x- axis from left to right say 0 to 320 and
right to left say 320 to 0 with some Constant duration,
Further each sprite i am placing at random position across x-axis,
but when i create my batch of sprite and apply that skaction on each one
SKAction *moveRight = [SKAction moveToX:320 duration:walkAnim.duration];
SKAction *moveLeft = [SKAction moveToX:0 duration:walkAnim.duration];
after some time the whole batch of sprites is moving in one direction, from left to right and then right to left
i know the problem is with my approach and to moveToX with Constant duration
I need Constant duration in my case, Is there something we have in moveToX like we do have in
[UIView setAnimationBeginsFromCurrentState:YES]
so that i can tackle the issue for batch sprites with random position across x-axis
Note when i give some space to call that action on each sprite, then its working fine, but i need all at one time.
One can get Sample app from here
EDIT
What i need i have updated the code here
but I need all the sprites present on the dice without any Timeinterval with the same actions applied on all of the sprites.
Any suggestion would be appreciated
thanks
Umer
To have a constant speed you will need to calculate the duration for the first move Action based on the current position of your sprite. after doing that first move, you can use your moveRight and moveLeft actions. Here is an example for starting to move Right.
CGFloat durationForFullDistance = walkAnim.duration;
CGFloat fullDistance = 320;
CGFloat firstDistance = fullDistance - sprite.position.x;
CGFloat durationForFirstMove = durationForFullDistance*firstDistance/fullDistance;
SKAction *firstMoveRight = [SKAction moveToX:320 duration:durationForFirstMove];
SKAction *moveRight = [SKAction moveToX:320 duration:durationForFullDistance];
SKAction *moveLeft = [SKAction moveToX:0 duration:durationForFullDistance];
SKAction *continousMove = [SKAction sequence:#[
firstMoveRight,
[SKAction repeatActionForever:[SKAction sequence:#[
moveLeft,
moveRight
]]]
]];
]]

follow path for SKAction not working

I have a CGMuatbleCGPathRef and I am trying to create a path ref to move my alien. I'm keeping it simple right now, but these will be complex later on.
I have the code below to move the SpriteNode to one point, but he never moves. Can someone point out what i'm doing wrong? I have an animation action running on him with repeat action also.
Method called first to start the animation texture frames ( works )
-(void)walkingBear
{
//This is our general runAction method to make our bear walk.
[spaceMosquito runAction:[SKAction repeatActionForever:
[SKAction animateWithTextures:moqFrames
timePerFrame:0.4f
resize:NO
restore:YES]] withKey:#"walkingInPlaceBear"];
return;
}
The Action to move the alien
-(void) normalStance {
CGMutablePathRef cgpath = CGPathCreateMutable();
CGPoint endPos = CGPointMake(300, 600);
CGPoint startPos = CGPointMake(700, 900);
CGPathMoveToPoint(cgpath, nil, startPos.x, startPos.y);
CGPathMoveToPoint(cgpath, nil, endPos.x, endPos.y);
[spaceMosquito runAction:[SKAction followPath:cgpath duration:5.0f ] withKey:#"moveme"];
CGPathRelease(cgpath);
}
You are not creating a path in your code! You are just moving the start of the path from start point to end point but no path is created.
Replace the second call of CGPathMoveToPoint by CGPathAddLineToPoint
The will create a line path your sprite could follow.

Resources