How do I make an SKNode follow an SKShapeNode in Sprite Kit? - ios

I have a line, lets say a rounded rect, drawn on screen (SKShapeNode drawn from a CGPath). Now I want a node to follow that rounded rect, either clockwise or counter clockwise. I've done this with SKAction's followPath:asOffset:orientToPath:duration: method, which works fine if the node starts at the path's origin.
The thing is, the node can be placed anywhere on the rounded rect, and when I press and hold a button I want it to start following the rect from the point it's currently located. When I release the button the node stops where it is. Right now if I stop the node and start it again it follows a new rounded rect starting at the nodes point.
Is there an easy way of achieving this?

It seems that you may make use of newly introduced SKConstraint class (https://developer.apple.com/library/prerelease/ios/documentation/SpriteKit/Reference/SKConstraint_Ref/).
For a quick introduction take a look at session 606 from WWDC2014: "What's new in SpriteKit".
It's really quick and simple way to adjust position/rotation/distance of the sprite in relation to another sprite.
What you exactly need is
+ (instancetype)orientToNode:(SKNode *)node
offset:(SKRange *)radians

This is a difficult problem. I can think of two solutions:
Each time you press and hold, construct a new CGPath for the node to follow which starts at the point your node is currently stopped.
Keep a reference to the SKAction object that you're running. When you stop pressing on the screen, instead of stopping the action, set it's speed property to 0.0. This will effectively pause the animation. When you press down again, set the speed back to 1.0.

Related

Swift/IOS: SCNNode appeared to return to its original position after SCNAction is finished, but its actual position was changed by SCNAction

I am very new to Swift and IOS development so this could be a simple question, but I struggle to find the answer on the internet.
I was trying to animate a static DAE model by running a SCNAction on one of its nodes. However, after the SCNAction was completed (and the node was moved), the node position will appear to go back to its original position immediately (same position when the static DAE model was loaded). But when I print the node's position, I noticed that the node's position was actually changed because of the SCNAction. And when I ran the SCNAction again on the same node, the node will go back to the end position resulted from the last SCNAction and start the SCNAction from there. I wonder why there's such mismatch between the node's actual position and the position appeared in the scene.
Another interesting thing was when I put SCNActions in sequence ([action1, action2]), the node will not return to its original position between actions. But if SCNAction.wait was added in between ([action1, SCNAction.wait, action2]), the node will return to its original position during the wait, and will start action2 again from action1's end position.
I am trying to maintain the positions of all nodes at the end of SCNActions. Is there any way to prevent it from going back to the original position?
Not sure if the question is clear enough. Any thoughts and ideas are appreciated.
Have you verified that the node does not come with an animation from the Collada file? Animations and actions are evaluated one after the other. The actions may override the effect of the animation, until they are done (or paused).
Unlike actions, animations don't write in the model tree (node.position) but only in the presentation tree (node.presentationNode.position).

SpriteKit follow partial path

I've used CGPath to create a race track by stroking the path and offsets of it to draw the road and lines. My hope was that I could use this CGPath in SpriteKit so that I could make a car sprite follow the track. I can get a sprite to follow the entire path from start to finish using SKAction.followPath (screenshot added at bottom of post.)
However, my issue is I sometimes want a car sprite to move from the start to the half-way point (or 25% or some fraction of the path.)
I don't see a way of doing with with an SKAction so I was looking into a way of taking a CGPath and splitting it to whatever fraction of the path I needed but I've yet to find anything that seems to do that. I'm reasonably hopeful it can be done since in a CAShapeLayer you can set strokeStart and strokeEnd to specify where you want the path stroked from percent start to percent end so it looks like something like this has already been implemented.
Is there any way of either getting SpriteKit to set the start and end point of followPath or modifying a CGPath so that it returns a subpath?
car race screenshot

How to dissolve nodes in SpriteKit?

I have 2 SKSpriteNode objects, and I want to crossfade them.
One of the easiest way is to create a fadeOut SKAction and a fadeIn SKAction, and apply them to the SKSpriteNode objects. But the problem of this approach is that during the action both of them have the alpha under 1.0, which looks not so good.
For example, I'd like to dissolve the red square SKNode to a green round SKNode
If just fade out the red square and fade in the green round during the action it'll look like this
So you can see background through these 2 objects. I hope to dissolve these 2 objects like this:
In UIKit I can use UIView.transitionWithView but in SpriteKit I only found a similar method for presenting scenes (SKViewObject.presentScene: transition:). So is there anyway to make a dissolve transition for SKNodes?
There's little you can about the background coming through when adjusting the alpha settings on both nodes. A possible hack could be to temporarily insert a solid node in front of your background but behind both other nodes until the action is done. At which point you remove it.
The node should be in the shape of both nodes cross-section (pardon the sloppy artwork on my part):
I searched a lot for this question and I nearly decided to use a shader to do this kind of dissolve (since you can directly edit the pixel in a shader), but then I found that there's an unusual way to solve this problem. It may not be useful for every situation, but if your background doesn't do things like scroll or zoom, this approach may be the easiest. In simple words, just create a screenshot for the current screen and display it at the top, then change your node to the sprite you need, and at last fade out the screenshot you took.
So at first you have to make sure all the nodes are in the correct node tree. Then use SKViewObject.textureFromNode(rootNode) to create the screenshot, make a sprite node from this texture, and add it to your screen. Then, you can create the fade out SKAction to fade out this screenshot sprite. You may also remove it when the action ends.
Using this approach, during the fade out the screen will just look like this:

Apply an impulse to SKNode to move across screen and detect collision

I am making a basic app that pushes shapes across the screen and detects collision with Sprite Kit. My first attempt was using moveTo on the nodes. The issue I had was with collision, the objects would rotate around each other instead of bounce.
Therefore I found I need to use applyForce OR applyImpulse.
In this situation I have a circle for example that is position off screen at its start of life. We then determine a target exit point, and want to 'flick'/'push' the node in that direction.
I cannot figure out how to applyImpulse towards the target end position I have as a CGPoint. I need to get this to a CGVector but I am not sure what needs to be done. I had a look around and found some Ray tuts but they just show applyForce or moveTo. I am not sure how to calculate this.
I found a site that explains 2D physics well.
http://www.rodedev.com/tutorials/gamephysics/
With this I worked out what the angle needed to be and have a speed that I can control and it works well.
You can move an object by changing manually the x and y position so you can reach your end point. In the update function you change yourObject.position.x and yourObject.position.y if I have understood correctly your question. If not please be more explicit. Hope that helps.

Moving a node around a path incrementally without using SKAction followPath

I want to have a path that my node can travel around on demand.
For example, I want to have a circle in the middle of the screen and when i tap the left side of the screen, my SKSpriteNode will move in a counter-clockwise direction on the circle (and the same if i tap the right side of the screen).
From what I've researched, I can create the circular path using SKShapeNode, CGPathRef, or even UIBezierPath. Creating the path isn't the issue. In all the instances I've seen researching this topic, most people just use [SKAction followPath:path duration:1.0] and this makes the node go around the the circular path ENTIRELY in 1.0 seconds. I want to be able to tap left/right and only move incremental amount of space per tap. (If anyone's played Super Hexagon, think of the fluid circular motion of that game)
*Note: I only use a circular path as an example so I don't particularly need specific pointers on how to move around a circle per se, but more of ANY path of any shape.
You can create any kind path shape you want using CGPath. This gives you the ability to create only the path for which you need to move your node. To use your circle example, create a 90 degree arc path and your node will move 4 separate times to complete a full circle.
If you do not want to use a path, you can also use the SKAction moveBy x,y,duration command. Tie a couple of those together and use them in a block sequence and you have yourself a generic path function.

Resources