Sprite kit impulse at point - swift

I'm trying to use two points on a spaceship to create a "tank like movement" were the space ship will move forward when both points get an impulse on the physicsBody (using the applyImpulse(CGVector, atPoint: CGPoint) method) and turn left/right when only one point gets an impulse.
I can move the space ship forward using the applyImpulse(CGVector) method without the atPoint parameter and it works, but i have issues using the atPoint parameter.
When trying to use the atPoint parameter the spaceship will move really randomly, even if i apply an impulse to both jet engine 1 and jet engine 2, but i'm not sure if i apply the forces at the right point (on the jet engine spots marked on the image), the documentation is very vague about this and i don't know how to get the position of the impulses right.
Does anyone know how to get the correct positions to apply the impulses to? It should be like the ones on the image. I'm using Swift but i can read Objective C so that doesn't really matter.
EDIT:
I have tried the following points:
CGPoint(x: 0, y: 0) and CGPoint(x: 1, y: 0)
CGPoint(x: 0, y: 0) and CGPoint(x: spaceship.size.width, y: 0)

Reviewing the documentation, the points you apply the impulses at must be in scene coordinates. What that means, is you need to determine the points in the coordinates of your sprite (probably coordinates like CGPoint(x: 0, y: 1) and CGPoint(x: 0, y: -1), but you may need to play with those), then convert those to scene coordinates using convertPoint(point, fromNode: ship).

A way to do this that's (possibly) going to give you a more "realistic" drag and thrust result is hanging two engine bodies off your fighter jet, and giving them both drag properties, and apply thrust from them when needed, as needed.
In this way you'll get the type of rotation common to one engine being on whilst the other is off, etc.

Related

I am trying to make my SCNNode rotate but I cannot seem to get it to work

My SCNNode is a compass that I want to rotate towards north.
compassNode = scene?.rootNode.childNodes[0]
I am successfully getting heading data and converting it to radians and storing it in a variable called angle.
angle = newHeading.trueHeading.toRadians
I have tried three methods now:
rotate = SCNAction.rotate(by: CGFloat(angle), around: SCNVector3(0, 1, 0), duration: 0.5)
compassNode?.runAction(rotate)
and
compassNode?.rotation = SCNVector4Make(0, 1, 0, Float(angle))
and
let oldTransform = compassNode?.transform
let newTransform = SCNMatrix4MakeRotation(Float(angle), 0, 1, 0)
SCNTransaction.begin()
SCNTransaction.animationDuration = 0.5
compassNode?.transform = SCNMatrix4Mult(newTransform, oldTransform!)
SCNTransaction.commit()
None of them makes any noticeable transformation to the compass. It appears to be still.
Running out of comment characters... Sry - have to put it in answer section.
Convert 90 degrees to radians, rotateTo that value. Rotating models can be confusing in 3D (for me anyway), sometimes it's easier to just use an SCNBox at first - it will have the correct rotation by default provided you're looking down -Z if you didn't change the camera view. You can turn on the the 3D outlines and sometimes that helps provide a better visual OR just texture map the box with different colors so that Red is the top, Green is front or whatever.
Then you can reshape the box, rotated it with different angles until you get the hang of rotateTo, rotateBy, rotateAround. I'm not a math guru, so unfortunately trial and error for me sometimes, but once I understand what's happening, then I can put the model in and know that my math works - then if I have to do some work on the model, such as pivot point or need to change the model - set Z-UP or whatever (this post: 59766878), then I'm focused on one thing at a time and not having a combination of problems to figure out.
I've also used lookAt and placed various (hidden) nodes at particular positions, so that I can see what X,Y,Z rotations look like at various points in a game and from different view points.

Does collision work during animation for SceneKit?

I wanted to do a simple asteroids games where the asteroids go from far to bypass you (z>0) in SceneKit.
let moveAction = SCNAction.move(to: SCNVector3(0, -10, 10), duration: 2)
rockNode.runAction(moveAction)
Says I have a spaceship in Z axis 0, even though I can visually see the asteroids pass through the spaceship, the collision detection does not occurred. The collision only happened if the end point of the moveAction ends in Z axis 0 and in the same location as the spaceship.
Does detection only occurred after the moveAction ended (thus will not detect collision)? If yes, what solution do I have in detecting the collision during the asteroids movement?
did you set the isDynamic to true on both of your objects? and they both need to have different categoryBitmasks otherwise SceneKit will treat them as the same objects (can't comment don't have 50 rep yet) if not then do so collision should happen even when moving an object programmatically
Make the physics body as: kinematic. So it can detect collision even during SCNAction.
eg:
rockNode?.type = .kinematic
Or you can set it from Physics Inspector
Keep coding....... :)

having 2 physics bodies changes the behavior of the node

I have a rectangle shaped node, I want this node to behave like a pool ball when it hit the wall, meaning it bounce of the wall in a reverse angle, just like the pool ball, here is what I did:
1- Added physicsBody rectangleOfSize, the behavior is not as it supposed to, the node hit the wall then moves along it instead of bouncing in the correct angle.
2- Added physicsBody circleOfRadius, the behavior is perfect, but the node is not circle shaped, it's rectangle.
3- Finally found the most logical solution, I added two bodies circleOfRadius, one at the top of the node and one at the bottom,this way I should get the bouncing behavior I want with the top one, and still give the node a practical physics body for collisions with the bottom one, but the behavior is like the rectangle shaped physics body rather than the circle shaped one.
let circle = SKPhysicsBody(circleOfRadius: size.width / 2, center: CGPoint(x: 1, y: size.height / 2))
let circle2 = SKPhysicsBody(circleOfRadius: size.width / 2, center: CGPoint(x: 1, y: -size.height / 3))
physicsBody = SKPhysicsBody(bodies: [circle, circle2])
Seems like the bottom circle body is affecting the behavior, I tried playing with its properties(allowsRotation, mass, etc) but it changed nothing.
Any idea how to make a rectangle shaped node behave physically like a circle shaped one?
Check out the section for "Working with Collision and Contacts" in the Apple Docs for a SKPhysicsBody. Basically you have do define a collisionBitMask for your circle node to only collide with your walls and your rectangle node to only collide with whatever you want it to collide with.

Scene Kit: How to make SCNNode only rotate horizontally in Swift 2.0

I managed to create a tree and the program is supposed to only allow users to rotate this tree horizontally.
After looking at the doc, I use the following code
treeNode.physicsBody?.angularVelocityFactor = SCNVector3Make(0, 0, 1.0)
But this didn't do anything, I was still able to rotate the tree in every direction.
What is the correct way to limit node rotation in only horizontal direction?
Are you really trying to restrict the node's rotation? Or do you want to restrict the camera's rotation?
If the former, you'll have to provide much more detail on your body's physics and structure. An approach using SCNPhysicsHingeJoint seems like it would work.
let joint = SCNPhysicsHingeJoint.init(body: treeNode,
axis: SCNVector3Make(0, 0, 1.0),
anchor: SCNVector3Make(xpos, ypos, zpos))
If you're just trying to control the camera, though, you should turn off allowsCameraControl for the SCNView. That's only useful for quick and dirty testing. Then you can implement the technique described here (Rotate SCNCamera node looking at an object around an imaginary sphere) and modified here (SCNCamera limit arcball rotation).

SceneKit won't scale a dynamic body

I have a sphere that is a dynamic body. I would like to animate the scale of this sphere so that it grows in size:
let sphere = SCNNode(geometry: SCNSphere(radius: 1))
scene.rootNode.addChildNode(sphere)
sphere.physicsBody = SCNPhysicsBody.dynamicBody()
sphere.runAction(SCNAction.scaleTo(10, duration: 1))
However, this does not seem to work. The sphere falls down due to gravity, but stays the same size. If I comment out the line that gives the sphere its physics body, then the scaling animation plays out like it should.
This strange phenomenon is even observed without an animation. Simply changing the scale of the sphere directly doesn't work:
let sphere = SCNNode(geometry: SCNSphere(radius: 1))
scene.rootNode.addChildNode(sphere)
sphere.physicsBody = SCNPhysicsBody.dynamicBody()
sphere.scale = SCNVector3(x: 10, y: 10, z: 10)
The sphere drops down but remains with a radius of 1. Unless the sphere is scaled before its physics body is added. In which case, the sphere starts out scaled to 10 and drops down, keeping its radius of 10.
Interestingly, upon further inspection by printing out the sphere's scale after the animation has supposedly run, it is observed that the scale has indeed changed, it's just not visible unless the physics body is removed:
let sphere = SCNNode(geometry: SCNSphere(radius: 1))
scene.rootNode.addChildNode(sphere)
sphere.physicsBody = SCNPhysicsBody.dynamicBody()
sphere.runAction(SCNAction.scaleTo(10, duration: 1), completionHandler: {() in
println(sphere.scale.x)
sphere.physicsBody = nil
})
Why is it not possible to change the scale of dynamic body? (Note that static and kinematic bodies will scale just fine.) Is it possible to achieve this in some way?
You wouldn't just need a "scaling velocity" to interact with other objects as one changes size, you'd need a "scaling force". How strongly should it push on things that it collides with while growing? And what happens if it's in a situation that depends on its mass, like balancing on a seesaw?
Game engines are already loose approximations of real-world physics, so asking them to figure out Ant-Man physics on their own is a bit of a stretch. If they could do that, they could probably also start building killer robots, and that'd kinda ruin your day. :)
Anyway, depending on how you want your expanding sphere to affect things, you have a few options. One is to delete and re-create the physics body at intervals:
let duration = 5.0
node.runAction(.customActionWithDuration(duration, actionBlock: { node, progress in
let scale = 1.0 + progress / CGFloat(duration)
node.physicsBody = nil
node.scale = SCNVector3(x: scale, y: scale, z: scale)
node.physicsBody = .dynamicBody()
}))
This does it every frame, which could be costly — you might want to throw some gating on progress in there so it happens less often. (And depending on what other effects need to happen as a result of the sphere changing size, you could set things like mass when you re-create the physics body.)
Another option might be to look at SCNPhysicsField. Use a radial gravity field to make a region that shoves everything out of its area of influence, then animate its parameters to change size and strength over time.
I ran into this when trying to scale a model I was importing from a .scn file. Just like rickster did, I ended up removing the physics body, scaled the shape & then re-attached the physics body. This was only done during startup, so not a big performance impact.
Physics simulation is a kind of animation in addition of implicit/explicit animations or actions. So when change the animatable property to a node physics affected, take special consideration of animation state of node.
on the other hand,sceneKit apply result of physics simulation to presentationNode, which represents node's current render state. you can check information of presentationNode to confirm why your animation sucks.