SpriteKit - Changing anchorpoint on node changes position of all childnodes - ios

I'm so freaking confused about anchorpoint in SpriteKit.
If I have a Node consisting of multiple childnodes, and I change the anchorpoint of the Node, then all the childnodes gets misplaced. Is there any way around this?
I think it's really annoying to position nodes if I always use the default anchorpoint (0.5,0.5), so sometimes I change the anchorpoint to for example 1.0,0.0 so it's easily placed in the right lower corner. But if this node has childnodes, then they are all misplaced when I change the anchorpoint.
What am I missing?

Avoid changing the default anchorPoint whenever possible.
If you do change anchorPoint, make sure you do so only on nodes without children.
In your case (and in general) the fix is relatively easy. Instead of adding child nodes to the sprite node whose anchorPoint got changed, use a common parent node (SKNode). Add the sprite node to the parent node, change the sprite's anchorPoint but don't add any children to it. Instead add those children to the parent node. You can then use the parent node to position this branch of the node tree together.
Alternatively create a subclass of (or category on) SKSpriteNode with methods that allow you to align the node to a certain border, taking the sprite's frame size and anchorPoint into account. For example you could add two properties verticalAlign and horizontalAlign with center, left/top and right/bottom alignment. Whenever the position property is changed, the point is offset before being passed to super setPosition so that the alignment mode is adhered to.

Related

PhysicsBody stays after translation and rotation

I have a node with a cube attached which represents for example a door. The physicsbody type is .static. If i animate the node up, rotate it and animate it down to the orignial position of the physicsbody stays in the upper position.
In the debug mode the color of the phyisicsbody is first grey (i asume grey = .static), after the translation up, the physicsbody stays at the bottom. As soon as I rotate the node in the upper position, the physicsbody becomes green and moves up to the nodes position. After I translate the node down to the original position, the physicsbody stays in the upper position. Why is this behaviour? Is this because the type is .static?
I know if I set the physicsbody type to .kinematic (shown red in debug) mode it works as expected. The physicsbody adapts the translations and rotations. But with .static type I can place more objects before the fps drops than with .dynamic.
From the documentation for SCNPhysicsBodyTypeStatic we learn that it is
A physics body that is unaffected by forces or collisions and cannot move
However you can use resetTransform to explicitly tell the engine that the node has moved and that the physics body needs to be updated:
If you change the position or orientation of a node with an attached
static or dynamic physics body, call this method afterward to ensure
that the physics simulation incorporates the change. You need not call
this method for kinematic bodies.
Note that dynamic and physics bodies
are designed to be moved only by the physics simulation or not at all.
You may use this method to move them regardless of this restriction,
but at a cost to performance.

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

Change draw order of sprites within one sknode

I need to force/specify the drawing order of all children within node A. I have SKView.ignoresSiblingOrder = NO. If I start setting zPosition on the sprites inside node A (inside update: of the scene), the drawing order would also affect globally so that the children inside node A draws on top of/behind other nodes that are not children of node A, and this messes things up. So I specifically need to adjust the drawing order of the children within node A. How? I can't rearrange the order of the sprite in the children array in update: now can I (performance hit...)?
Update: judging from the SpriteKit reference, for complex scenes we probably have no choice but to set zPosition for everything. I'll do that for now, see if it holds.

Controlling movement of flying a vehicle with SceneKit

I currently have a scene which contains a central node at the root of the scene with earth-like geometry and a node representing a flying vehicle.
However I cannot find the right approach to control the movement of the vehicle. I need the ability to turn left and right while orbiting at a static altitude and speed.
I have tried many combinations of animations and physics body forces all leading to undesirable results.
The closest I've come is:
Setting the pivot property of the vehicle to the centre of the scene
Then setting an Action like below to control moving forward
[_vehicleNode runAction:[SCNAction repeatActionForever:[SCNAction rotateByX:-1 y:0 z:0 duration:10.0]]];
Then finally applying forces for turning left and right with
[_vehicleNode.physicsBody applyTorque:SCNVector4Make(0, 1, 0, 1) impulse:YES];
However I cannot seem to set the pivot and/or position to the right value to get the desired result.
Edit: It appears as the above method would be the solution I'm looking for, however for some reason when I add geometry to the vehicle node, it's position in the scene graph gets changed dramatically. When I add hardcoded buttons to change it's position to where it belongs it appears correct for only that single frame then straight back to being in the middle of nowhere.
Edit 2: After replacing all geometry with a primitive sphere for testing the node is now rotating as intended but is now unaffected by physics forces appearing to ignore it's declaration as a dynamicBody.
If I understand what you are trying to achieve correctly, you can try this:
add a first node to your scene, positioned at (0,0,0) and make it rotate forever along the Y axis using an SCNAction
add your ship node as a child of the first node. Position it at (X,0,0) so that it orbits around the earth
rotate your ship node along the X axis with an action or an animation

Best way to add a SKPhysicsJoint to an object

So I have a marionette I am making in Sprite Kit, and placing him in a scene. I have created a Marionette class, which is a subclass of SKNode, and when I create an instance of this class, I add a number of SKSpriteNodes to each other. This should give you an idea of how it works (I've snipped out the unnecessary lines):
[self addChild:self.head];
[self.head addChild:self.chest];
[self.chest addChild:self.leftLeg];
[self.chest addChild:self.rightLeg];
[self.leftLeg addChild:self.leftFoot];
[self.rightLeg addChild:self.rightFoot];
So, after doing this, I have my marionette showing up. I want to add a SKPhysicsJointPin to each of these connections. Code looks like this:
self.chestPin = [SKPhysicsJointPin jointWithBodyA:self.marionette.head.physicsBody bodyB:self.marionette.chest.physicsBody anchor:self.marionette.chest.anchorPoint];
At first I thought I could just set up all the pins inside the Marionette class, but that doesn't work (I get EXC_BAD_ACCESS if I recall). It turns out that I have to add the Marionette to the overall SKScene before I add the joints.
This make sense I guess, but I can't help thinking there should be some way I could just set everything up in the Marionette class, and then stick 2 lines of code in the scene to create a new Marionette, then addChild him to the Scene.
As it is, my SKScene subclass has a bunch of code now to add all the pins, and it doesn't feel like it fits in the Scene. Thoughts?
You don't want to use anchorPoint as anchor. The anchorPoint property is a factor which ranges from 0 to 1 and affects how the texture is offset from the sprite's position, ie the default 0.5/0.5 centers the sprite's texture on the sprite's position. In other words anchorPoint is not a position, and using that will anchor the body & head joint to the lower left corner of the screen.
Instead try using either chest or head's position as anchor, or the point in between the two.

Resources