having 2 physics bodies changes the behavior of the node - sprite-kit

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.

Related

Move spritenode in a circle with controls

How would I be able to move a SKSpriteNode along a circle while controlling the movement. For example, there are two buttons, left and right, and each one will make the SKSpriteNode move either clockwise around the circle or counter clockwise.
This is a great example of what I trying to accomplish. Notice how you move 'Trump'.
http://www.trumpsimulator.com/
This is what I have tried so far:
let circularMove = SKAction.followPath(circle.CGPath, asOffset: false, orientToPath: true, duration: 5)
Don't move the sprite node at all.
Place the node onto a parent node. (Call it a layer or something).
Now rotate the layer.
If you place the sprite off centre then it will follow a circle with a radius of the distance of the sprite from the centre of the layer.
Now you don't need to worry about paths or anything. Just update the rotation angle each update.

Swift Sprite-kit SKPhyshicsBody

I have a few images that can detect when they get touched right now I am using
plane.physicsBody = SKPhysicsBody(circleOfRadius: plane.frame.height / 2)
but I need it so it is the boarder of the image not a circle or rectangle.
We have a plane and you want a physical body.
Your first approach is circleOfRadius (the physical representation is a circle with a given radius). You can use another shape, such a rectangle:
plane.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(100, height: 100))
As explained in the comments you can also use the shape of a sprite (texture) to create the shape of the physics body:
plane.physicsBody = SKPhysicsBody(texure: plane.texture!, size: plane.size)
But a good way to choose it's this: if you want your game to run smootly on many different devices, don't make sure the physics calculations become too complicated. In other words if you have many object around your plane with physical behavior moving around and colliding with each other, you may choose to use simplified shapes to deal with the physics more efficiently, especially if a shape already looks a lot like a rectangle or a circle.

Sprite kit impulse at point

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.

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.

Collision without sprites colliding

I have some simple code that adds a block sprite at the leftmost part of a tile like this :
block.position = CGPointMake((-self.size.width * 0.5), 0);
[self addChild:block];
Since the anchor point is in the middle of the block sprite. self refers to the actual tile.
This works fine and indeed adds the block on the left side of the tile sprite.
Now I also have a player sprite that can collide with that block if it tries to go through it. That also works just fine.
The problem happened when i tried to get the block sprite to show in the exact same spot using another anchor point (i need a new anchor point for a shrink effect i wanted to create - which appears to work fine btw).
The new code becomes :
block.position = CGPointMake(-(self.size.width * 0.5), -(self.size.width * 0.5));
block.anchorPoint = CGPointZero;
[self addChild:block];
The new block appears in a similar to the first case position (though not totally identical).
I am not sure why the position is not identical but i can fix that by adding/subtracting 1 or 2 from the x,y points.
The weird problem is that if my player sprite now tries to go below that block on the tile below (which is an open tile without any blocks), i get a contact between the player and the block.
I have even added debug paths with SKShapeNode to make sure that the player and block sprites do not actually collide. And they don't ! But i still get a collision event.
The player scale is (0.8, 0.9), but i don't think this would play much of a role.
I really don't get why this could be happening. Any ideas guys ?
Changing the sprite's anchor point have no effect on the physics body.
When talking about CGRect, the rect origin is at point {0, 0},
So what is happening is that you now have a sprite that its image is centred around anchor point {0, 0} but with a physics body, that starts at {0, 0} and is the size of the sprite, meaning that it is centred around {0.5, 0.5}.
So even that the player doesn't collide with the image of the sprite, it does collide with its physics body.
What is happening is that you have a physics body, that before had the same centre point as the sprite,
But as oppose to before, where the sprite anchor point were in the middle, which would 'fit' into the physics body,
Now the sprite's anchor point is {0, 0}, which causes the physics body centre point, to actually be the most bottom left point of the sprite.
To resolve this, you need to offset your physics body, so it will be centred around the new anchor point.
For example:
block.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:block.size center:CGPointZero];
CGPoint newCenter = CGPointMake(block.size.width, block.size.height);
block.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:block.size centre:newCenter];
Good luck mate.
EDIT- On a second thought, I think I got confused with the offset directions.
An edit has been made to correct it.