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

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

Related

SceneKit Collada animation with child node

I have an imported DAE file in SceneKit and am trying to add a particle system to it. It's a cigar smoking character and I want smoke to appear from the end of his cigar. Like this:
The problem is, when his animation begins, the particle system doesn't move with the cigar, despite the fact it is a child of the cigar node.
What am I missing here?
I figured it out. Two things that need to happen:
The node has to be a child of the node that is being animated, which
in this case is the node with the bones as the character was rigged.
Also, in the particle system you need to make sure the emitter is set
to world space so it doesn't rotate with the parent node (smoke would
always rise vertically regardless of the rotation of the head).

Changing SCNNode scale has no effect

I'm new to ARKit and SceneKit. I have a rather complex scene coming from an 3D artist. He replaced some items with SceneKit objects. I now try to change the properties of one of the SCNNodes, in this case the scale property, in another case the position in space, and in yet another I have a SCNText where I change the string property:
feedScaler?.scale = SCNVector3Make(1.0, scale, 1.0)
feedText?.string = String(feedValue)
feedIndicator?.position.y = someNewValue
So, pretty straight forward. When I run the scene though, it seems that the changes here are only commited once, before the scene appears. Then nothing happens. Here's the thing:
the method which updates the properties runs once per frame
I print out the property values of the nodes to the console and they update each frame
the text updates, too, and is the only update which is actually rendered and visible.
Note: There's also animations in that scene that do not play unless I uncheck "Use scene time base". Maybe that is a hint regarding how the Scene's animations are handled...
I found the issue. I used a clone of the scene which caused the references to get lost. The documentation says:
Cloning or copying a node creates a duplicate of the node object, but not the geometries, lights, cameras, and other SceneKit objects attached to it—instead, each copied node shares references to these objects.
When the original gets lost all the references get useless.

SceneKit nodes aren't changing position with scene's root node

I'm using SceneKit with ARKit, and right now have a simple app where I tap on the screen and it adds an ARAnchor and a SCNNode to my scene.
At some point, I'm going to want to move the entire scene, so I tried changing sceneView.scene.rootNode.position.x += 10 to test this out. If I call this on any particular node, that node does move appropriately. But calling this on rootNode, nothing happens, where I'd expect every child node (which is every node in the scene) to move along with it.
Why are my other nodes not moving appropriately, and is there something I can do to fix this? Or am I thinking about this wrong?
Per the docs for SCNScene.rootNode:
You should not modify the transform property of the root node.
The root node defines the origin of the world coordinate system — all other measurements are relative to it. Hence, it's not meaningful (and is often problematic) to change its position, orientation, scale, or any other aspect of its transform.
If you want to move all the content in your SceneKit scene, create a new node to contain all of the others, and change that node's transform. (You can't do this for nodes added by ARSCNView, because ARKit makes those direct children of the root node, but the whole point of those is positioning them in world space.)

Can I move a node across the screen without SKAction?

I am developing the iPhone version of an Android game using SpriteKit and objective-c. The Android version was developed using libGDX. There the movement across the screen was done by updating the coordinate values whenever the predefined render method is called. While reading the docs in SpriteKit, I found that here the nodes are moved across the screen by using SKAction where the end coordinates and the duration is given and the action is applied to the node. Is this the only way the node can be moved? Or can I update the coordinates(in the update method according to the time interval) even after the adding the node to the parent node(without calling the SKAction anywhere)?
There are a couple of ways to make a node move.
Changing the node's coordinates myNode.position = CGPointMake(myNode.position.x+1, myNode.position.y); will move the node to the right. This method works with regardless on whether they have a physics body or not.
Apply velocity to the node's physics body myNode.physicsBody.velocity = CGVectorMake(100, myNode.physicsBody.velocity.dy); moves the node to the right. Your node requires a physics body for this to work.
Apply an impulse [myNode.physicsBody applyImpulse:CGVectorMake(100, myNode.physicsBody.velocity.dy)]; moves the node to the right. Your node requires a physics body for this to work.
Apply a force [myNode.physicsBody applyForce:CGVectorMake(100, myNode.physicsBody.velocity.dy)]; moves the node to the right. Your node requires a physics body for this to work.
When you apply force is like a motor pushing all the time. If you apply impulse it's like kicking a ball once.
Read up on each method in more detail in the SKPhysicsBody reference.
You can move a node by specifying the position property (see the SKNode
documentation)
node.position = CGPointMake(x, y);

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

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.

Resources