SpriteKit - Change SKReferenceNode coordinate system - swift

I am currently working at a 2D endless runner in SpriteKit. I create new Level sequences using the Scene Editor and then add them as a SKReferenceNode to the main scene.
The problem is, that I need to get the position of the single nodes inside of the SKReferenceNode, but the ones I get, are relative to the SKReferenceNodes coordinate system and not the main one.
How can I get the position of the nodes relative to the main scene?

you'll want to use the convert func
func convert(_ point: CGPoint, to node: SKNode) -> CGPoint
Description
Converts a point in this node’s coordinate system to the coordinate system of another node in the node tree.
Parameters
point - A point in this node’s coordinate system.
node - Another node in the same node tree as this node.
Returns
The same point converted to the other node’s coordinate system.

Related

Need to SCNNode within restricted area

I have created a SCNNode object on a SCNPlane object. Both objects are added to the scene view root node, like below:
scView.scene.rootNode.addChildNode(ballNode)
scView.scene.rootNode.addChildNode(planeNode)
Now, my issue is that the ball node is moving out of the plane node boundary.
When I tried to add ballNode as planeNode's child then, the ball node is not getting added to a plane as expected. It behaves very strangely.
Basically, I need to restrict the movement of ballNode within planeNode area. How can I do it?
Great question!
When adding a child node to another node, there are no constraints being implicitly applied to the child, aside from existing within the infinite coordinate space of the parent node.
While changing the transform (eg position) of the parent node will directly apply to all child nodes, each child node can still freely transform within the parent nodes local coordinate space.
It'd be a good idea to read the SCNNode docs if you haven't already, as it covers the foundational aspects.
To do what you want, when moving the ball in your gameloop, you will need to manually check whether or not that ball is outside the boundary you are trying to enforce, and change its position accordingly.
Depending on your desired outcome, you may want to also check out SCNPhysicsBody as a way to construct your scene with implied physical boundaries.

Is it possible to place objects with hit test without plane detection?

Following Apple's Creating an Immersive AR Experience with Audio
, I thought it would be interesting to experiment and try to place objects anywhere and not just on a vertical and horizontal plane. Is it at all possible to place an object using touch without plane detection? I understand that plane detection would increase the accuracy of hit tests and ARAnchor detection, so would there be any way where one could perform hit tests on any other location in the scene?
If your AR scene already contains any 3D geometry in a current session you can definitely use hit-testing to place a new model there (a placement based on already contained 3D geometry), or you can use feature points for model's placement (if any).
If there's no 3D geometry at all in your AR scene, or there's a extremely sparse point cloud, what do you apply hit-testing method to? Hit-test is a projected 2D point from screen-space onto a 3D surface (remember, detected planes are hidden 3D planes), or onto any appropriate feature point.
So, in AR, plane detection is crucial when developer is using hit-testing.
func hitTest(_ point: CGPoint,
types: ARHitTestResult.ResultType) -> [ARHitTestResult]
Here you can see all the ARHitTestResult.ResultType available.
But pay attention to this, there's a hitTest method returning SCNHitTestResult:
func hitTest(_ point: CGPoint,
options: [SCNHitTestOption : Any]?) -> [SCNHitTestResult]
Usage:
let touchPosition: CGPoint = gesture.location(in: sceneView)
let hitTestResult = sceneView.hitTest(touchPosition,
types: .existingPlaneUsingExtent)
or:
let hitTestResult = sceneView.hitTest(touchPosition,
types: .featurePoint)
Also, hit-testing is actively used in 3D games but it's rather for VR there than for AR.

Clipping node to camera for only one axis

I would like to have a node in the scene, that is somehow clipped to camera node only for y axis. So that when camera moves, this node stays at the same y but moves in x and z with the rest of the scene. Is there some special way I could do something like this, or is the only way to movie the node every time camera moves?
You can use SCNTransformConstraint to have a blocked called at every frame that takes the node's transform and returns a new transform that satisfies your criteria.
There are conversion utils such as convertPosition:toNode: that will allow you to have the node's position in the coordinate system of the camera, and then back to coordinate system of the node's parent after you modified the y coordinate. Just remember to use the presentation nodes if there are animations, actions or physics in your scene.

SpriteKit SKNode visual position in parent(s) after parent(s) are rotated?

I have following hierarchy:
Scene -> Root node -> NodeA -> NodeB (anchor node that's rotated) -> NodeC
how can I figure out visual position of NodeC in Root node coordinate space?
I've tried several variants with convertPoint:toNode: and convertPoint:fromNode: but numbers i'm getting don't match.
I've also looked at Get visible location of SpriteKit node after parent rotation, which seems to be close to my issue, but no luck there either.
Found what I was missing - convertToPoint needs to be called from the node in which final CGPoint value will be represented in. So, this works:
// point is CGPointZero because it is center of NodeC
let point = rootNode.convertPoint(CGPointZero, fromNode: NodeC) as CGPoint!

SpriteKit Select Sprite node from CGPoint

First post,
I'm in Apple's SpriteKit framework...(new programmer) and I have a bunch of nodes that are stationary. How do I select/grab a particular node if I know the coordinates (CGPoints)? I basically want to say, grab that node at (x,y) and do something with it (i.e. change color)
Thanks
If you know the CGPoint, you use the command nodeAtPoint: However, this command only returns the deepest descendant that intersects a point. If you have the possibility of having more than one node at your CGPoint, you should use the command nodesAtPoint: instead.
Read up on the details in the SKNode Class Reference - section titled Determining If a Point Lies in a Node.
** Update **
CGPoint myPoint = CGPointMake(10, 10);
SKNode *myNode = [self nodeAtPoint:myPoint];
Where self either is or needs to be replaced with the parent node of the node you are looking for.