SKAction starting point - ios

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.

Related

SKSpriteNode follow CGPath plus adding SKAction

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.

sprite kit - Sprite randomly drifting upwards after rotation

For the sake of simplicity, the scene has a circle sprite and a square sprite. The square sprite is the child of an SKNode that follows around the circle sprite so that rotation of the square always happens around the circle. However, when the node is rotated, the square randomly drifts upwards. This behavior stops once the rotation makes its way all the way around. Here is the code:
_square = [SKSpriteNode spriteNodeWithImageNamed:#"square"];
_circle = [SKSpriteNode spriteNodeWithImageNamed:#"circle"];
_circle.position = CGPointMake(-200, 300);
[self addChild:_circle];
_rotateNode = [SKNode node];
_rotateNode.position = CGPointMake(300, 300);
[self addChild:_rotateNode];
[_rotateNode addChild:_square];
SKAction *moveBall = [SKAction moveTo:CGPointMake(1200, 300) duration:12];
[_circle runAction:moveBall];
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
SKAction *rotate = [SKAction rotateByAngle:-M_PI_2 duration:0.2];
[_rotateNode runAction:rotate];
}
-(void)update:(CFTimeInterval)currentTime {
_rotateNode.position = _circle.position;
double xOffset = (300 -_circle.position.x);
double yOffset = (300 - _circle.position.y);
_square.position = CGPointMake(xOffset, yOffset);
}
Anyone know why this is happening?
If I understand the question, you are asking why the square moves in unexpected ways? The circle is moving, but on every frame you are setting the rotateNode's position to be the same as the circle, and they both have the same parent: self, so we can ignore circle for any debugging because it just executes its action every frame to get a new position.
The oddness, most likely, comes in because you are manually repositioning rotateNode, which would then move all of its children, including square. But in every frame you are also repositioning square manually. So rotateNode rotates, changes the position of square because it rotated, and then you reposition square to have a fixed offset. Further complicated depending on whether your goal is to position the square in world space or in parent space. But it's not clear what your goal is there.

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].

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
]]]
]];
]]

Resources