I am trying to connect together two SKNodes which both have equal size circular physics bodies. They are positioned so as to be touching each other, and I want them to be locked together. From the documentation, it sounds like I want a SKPhysicsJointFixed, and I have tried creating one with the anchor point being the midpoint between the two nodes - like this:
let fixedJoint = SKPhysicsJointFixed.joint(withBodyA: atom1.physicsBody!, bodyB: atom2.physicsBody!, anchor:midPoint)
but this causes an odd behaviour where after the joint is made the top node falls through the bottom node - where before the joint existed the physicsbodies rested against each other.
If I use a pin joint instead with the same code - it works as expected ie:
let pinJoint = SKPhysicsJointPin.joint(withBodyA: atom1.physicsBody!, bodyB: atom2.physicsBody!, anchor:midPoint)
locks the bodies together as I want them to be. I guess this is a perfectly fine solution - but I'm confused something about what is going on. Why does my pin joint do what I thought the fixed joint would do, and why does the fixed joint not do what I thought it would?
Perhaps you were running into the same problem I ran into. I've found that SKPhysicsJointFixed behaves very strangely if the SKNode.zRotation property in the two nodes you're joining is different. Here's the behavior I was trying to get, having nodes of certain types stick together when they collide. Note how, after the collision, they rotate around their common center of mass.
But I was often getting this sort of thing, and often even stranger than this. Notice that not only does it not rotate as expected, it starts to wiggle as it approaches the wall.
As you can see, the difference between the two scenarios is that the zRotations are equal in the first case, unequal in the second case. Seems like a bug in SpriteKit, if you ask me.
One workaround is simply to explicitly set the two zRotations equal before you create the joint, but this was unacceptable for my purposes. Fortunately, as you already found, you can consistently get the expected behavior from SKPhysicsJointPin. Of course, if you want the pin joint to behave like a fixed joint, you'll have to set the joint's shouldEnableLimits property to true.
Related
I'm trying to create a simple chemistry simulator with atoms (circles) and bonds between them. The problem I'm having is that when atoms 'bond' using a pin joint, the circles rotate independently of the joint. I've tried using more than one pin joint, but the molecules end up oscillating, sometimes wildly, as they stretch and correct themselves. I would appreciate any ideas.
Have you tried to use a RotaryLimitJoint in addition to the PinJoint? It limits the relative rotation between the bodies: http://www.pymunk.org/en/latest/pymunk.constraints.html#pymunk.constraints.RotaryLimitJoint
My workaround is to create two pinjoints. One from the centres of each of the bodies, and one, very short (0.1), at the contact point of the two bodies. This results in the two bodies (atoms) being very close to each other, but they rotate as a single object. I can set collide_bodies = False for both joints, which reduces processing. There is a little movement when the constrained bodies collide with a third body, but overall the solution works well.
I have been using Unity for a while and still Im not sure about some things, I know there are like 5 different ways to move our character (not using prefabs like for 1st or 3rd person controller I mean just code from scratch) so far for moving a character on a terrain I think setting the speed of the rigidbody works overal for me, just setting the x and leaving the y component as what it was before assigning that, so that gravity effect is kept, overal it works, I manage to collide with wall and other objects, manage to go on terrain and could add jump later in same fashion, but the trouble I find is that my character flies when it steps over any small object like a stone on ground, if he goes over it he starts flying, not a big distance but definetly looks like walking on the moon maybe, also I see that if I have a bridge that is lower in the middle part of it (like U shape) well the character goes like flying from the begining almost until the middle or so, as said works like being on the moon, however gravity seems ok on other objects, I know I can change the gravity value to be higher but Im affraid I could be breaking all that so my question is, is there a better way to move a character on ground that will work better without changing the gravity value? I guess that it can work right without affecting this value, I used other method to change velocity and adding a certain value to the y component but again I see it not right as an apparent correct value for small stones and small objects makes it hard to go over slopes too, any help is greatly welcome =).
I want to set the transform of both a given scn:SCNNode and its current presentation node, to a new value. However, I'm having trouble setting the presentation node. I've tried four ways:
Set presentation node's transform:
scn.position = newVal
scn.presentation.position = newVal
scn.presentation.transform is read only -- it can't be set. (BTW, setting the presentation node's transform compiles with no errors, perhaps something to clean up)
Use resetTransform():
scn.position = newVal
scn.physicsBody.resetTransform()
does nothing. The docs say it "Updates the position and orientation of a body in the physics simulation to match that of the node to which the body is attached". But it isn't changed. Not clear why!
Remove the physicsBody while setting:
let pb = scn.physicsBody
scn.physicsBody = nil
scn.position = newVal
scn.physicsBody = pb
This sets the presentation transform to newVal ("yea!"), but Physics does not work ("boo!"). Perhaps one cannot reuse a physics body.
Add a new physics body after setting:
scn.position = newVal
scn.physicsBody = SCNPhysicsBody(type:.dynamic, shape:nil)
but alas, scn.presentation.position doesn't have newVal.
Thoughts?
I've been noticing this as well in my SceneKit-using project. The direct answer to your question is: “The presentation node automatically updates its transform to match the scene node's transform. If it doesn't seem to be updating, make sure the scene node's isPaused is set to false.” However, it's likely that your scene nodes are un-paused and/or you're not using animations at all, and yet this issue occurs.
I started noticing this issue happening intermittently on iOS 11 when everything in my project worked great on iOS 10. I haven't touched SCNAnimations or anything like that— I have my own animation system, so I just update my nodes' .position every renderer(_:, updateAtTime:).
So AFAICT, the issue here isn't anything you're doing— the issue is that SceneKit has always been buggy and poorly-written (some parts of the API still haven't been fully updated for Swift), and will likely remain buggy and poorly-written because it seems the SceneKit team has completely moved onto working on ARKit. So the solution to your problem seems to be “just try a bunch of stuff, setting .position more frequently than necessary, or at a different time in the update loop, or really hack-y solution that seems to work-around the issues in SceneKit”.
For me, personally, I'm slowly working towards abandoning SceneKit in my project— I've mostly switched to custom Metal shaders, and then I'll do my own scene render loop, and eventually I'll replace the scene graph and SCNNode usage leaving me with zero reliance on the buggy mess that is SceneKit.
I wish I had better news for you, but I've been dealing with the weirdness of SceneKit for 2 years now. It's unfinished garbage.
Update: I ended up “fixing” my presentation nodes misbehaving by using a dirty hack that adds a tiny amount of “wiggle” to the node's position each frame:
public func updateNode()
{
let wigglePositionValue = SCNVector3(
x: Float.random(in: -0.00001...0.0001),
y: Float.random(in: -0.00001...0.0001),
z: Float.random(in: -0.00001...0.0001)
)
self.scnNode.position = _locationModel.value + wigglePositionValue
}
Side-note: As expected, “jiggling” node positions like this also disallows SceneKit from doing some of its batching/rendering optimizations, and (in my experience) incurs a performance hit. It's a horrible hacky work-around, only intended for worst-case scenarios (“the client says we have to go live with the game this week or we don't get paid, and now this stupid SceneKit bug?!”)
So yeah… the real solution here is “don't use SceneKit”.
I have the same issue using ARKit. Because physicsBody adjust itself according to presentation node instead of the node itself, and because the presentation node doesn't update immediately when you change the node's transform, the physicsBody you get might be weird.
There is one solution I found recently:
To change presentation node's transform, use SCNAction. For example, if you want to set position, use node.runAction(SCNAction.move(by: SCNVector3, duration: 0)) instead of simply node.position = SCNVector3. This way, the presentation node immediately updates and you get the right physics.
In addition, this approach only works on the node itself (not applying to children). So if you run action on the node's child, you still can't get the right presentation node and physics. To change the child node's transform and presentation transform, use the node.position = SCNVector3 approach.
To sum up, when changing node's transform, run an action, and when changing the node's children' transforms, directly set the transform.
Here is what happens when I copy&paste a few thin boxes, and then vertex-snap them to the ground and each other:
Pressing "Play" leads to the stack toppling.
I tried reducing the BoxCollider y to 0.99 and 0.95. No luck still.
Does anyone have recommendations to easily get a stacked wall to just stay up (until a real force is applied)? Maybe there is some sort of "glue" component to prevent two faces separating until a force exceeds some threshold?
Try setting their positions manually so that they are right under each other.
You shouldn't expect to be able to make a stack of 20-30 box colliders stacked on their smaller faces because of physics simulation inaccuracies, floating point errors and so on. If that's your intention and/or the above doesn't work, try using Fixed Joints with a manually set Break Force and/or Break Torque.
You can also try increasing the Solver Iteration Count to something like 10 or 15 (which should do the trick in most cases), but it won't be good for performance in scenes with 1000s of objects.
Increasing the Sleep Threshold will also help in this specific case, but can cause problems like small objects sleeping when they have small (but not infinitesimal) velocities.
EDIT:
A similar thing happens with my own custom physics engine. Another workaround you can do is to align the bodies and set them to sleep in Start. That way they'll stay upright (not moving rather) and topple when something collides with them.
xcode 5 iOS7 sprite kit.
My wish is to make a sprite that has its own gravity.
Like a planet. If another sprite comes within a certain range of it, it will slowly pull the other sprite closer.
I have two sprites. One moving and one stationary. When the moving sprite gets in a given distance of the stationary sprite the stationary sprite gravity should slowly pull the other sprite towards it. This way the moving sprite would change its path in a soft curve.
My idea would be to calculate the distance from the stationary object to any other object and if close enough start pulling and if the moving object gets out of range ageing, then stop pulling.
Would probably need to research some vector calculation.
Thats my immediate thoughts.
Is this possible and how? Does it already exist?
A friend of mine did this for his physics dissertation. multibody gravity simulation. So yeah you can but you need to be willing to learn some maths. Apparently there is a clever optimisation to make it run decently nlog(n) rather than n^2). you probably want to ask this on the physics version of stack overflow to get a good answer. I have the code at home ... will post it later but you will want an explanation - i used it in an xna app. Its badass once you get it working - although if you want naturally orbiting objects then you will want to code them using parametric equations for easy and cool orbits. Simply because its hard to solve and with time even using double will result in some errors (the good implementations also work out the error and adjust - again will post later). But the real problem is solving for stable orbits. You then use the algorithm for free moving bodies such and player objects / npcs. Although solving accurate movement for npc in a changing field is v hard.
you want to look at this question: Jon Purdys answer is the one you want
multi body physics - gravity
and this one (which is linked from above) ...
https://gamedev.stackexchange.com/a/19404
There is not a dead-simple way of doing that in any platform as far as I know maybe except for some game engines/platforms that export for different platforms (cocos2d, construct 2 etc).
What you need is a physics engine whether you write one (which is a complicated but fun thing to do) or use an available one.
Luckily I've found a link describing the usage of the famous 2D physics engine "Box2D" on iOS.
This one explains how you can include Box2D in an openGL application (but you can apply this to other environments (sprite kit) I think altough I'm not an iOS guy);
http://www.iforce2d.net/b2dtut/setup-ios
Anyways, you now know what to look for...
For iOS 8.0+ : you have SKFieldNode : radialGravityField()
For iOS 8.0- : one solution could be : 3 to 9
add your sprite ( planet ) with its physics
add an invisible SKNode ( the gravity zone ) with its own physics, as a child of your sprite, but with a radius much more than your sprite's one
you have a little explanation about invisible node here : https://developer.apple.com/documentation/spritekit/skphysicsworld
both, your sprite and the invisible node are centered in a zero gravity world
we look for contact and not collision ( set correctly your bit masks )
when any object get in contact with the invisible node ( gravity zone ), first you remove any moving action or impulse from it and then we add to this object an SKAction to move it toward the center of your sprite ( planet )
at second contact between this object and your sprite ( planet ), you remove all actions again from the object with a velocity = zero