sceneKit dynamic physic body fall through floor - ios

I have a cube with dynamic physical body and a plane with kinematic physic body.When I place a cube above plane, it will fall onto plane and a bounce is expected.
The PROBLEM is: when the cube is small or light, it just go through plane.For instance, cube has 0.1*0.1*0.1 work fine but 0.05*0.05*0.05 sucks.In this case I still get physical body contacting notification.
this is my code for creating geometry:
//cube
//when dimension is 0.1 everything is fine
float dimension = 0.05;
SCNBox *cube = [SCNBox boxWithWidth:dimension height:dimension length:dimension chamferRadius:0];
cube.materials = #[material];
SCNNode *node = [SCNNode nodeWithGeometry:cube];
node.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeDynamic shape:nil];
node.physicsBody.mass = 1;
node.physicsBody.categoryBitMask = phsicBodyCategoryCube;
node.physicsBody.collisionBitMask = phsicBodyCategoryPlane;
node.physicsBody.contactTestBitMask = phsicBodyCategoryPlane;
//plane
self.planeGeometry = [SCNBox boxWithWidth:100 height:0.01 length:100 chamferRadius:0
plane.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeKinematic
shape: [SCNPhysicsShape shapeWithGeometry:self.planeGeometry options:nil]];
plane.physicsBody.categoryBitMask = phsicBodyCategoryPlane;
plane.physicsBody.collisionBitMask = phsicBodyCategoryCube;
plane.physicsBody.contactTestBitMask = phsicBodyCategoryCube;

I’m surprised you’re getting collisions at all. See the SCNPhysicsBodyType docs – the kinematic type is for bodies that you move (by setting their position, etc) to cause collisions, but that aren’t themselves affected by other bodies colliding with them.
If you set the floor’s type to static, you’ll probably see better results. A static body doesn’t move (either as a result of physics interactions, or by you setting its position), so the physics engine can more accurately check for other bodies colliding with it.
edit: Other things to look into:
Use a SCNPlane rather than a SCNBox for your floor. (Note that you can create physics bodies with shapes different from their visible geometry, if that helps.) I'm not sure about SceneKit's, but it's easier for a lot of physics engines to check "has some object passed this infinite boundary since the last frame?" than "is some object inside this finite region on this frame?"
Enable precise collision detection for your moving objects.

Finally I found this is all about SceneKit's physical simulation. If the cube falls too fast, It will make a large penetration with plane In physical simulation steps. In this case sceneKit just let it fall through plane instead of collision. When I change cube's velocity to a small value It collided with plane.
My solution is to give cube a upward velocity when large over-penetration happens, which is the 30% of fall velocity. The trick is adjusting cube's velocity until a collision happens.

Works only for spherical physics shapes
For this issue SCNPhysicsBody has special attribute: continuousCollisionDetectionThreshold
For example, in a game involving projectiles and targets, a small
projectile may pass through a target if it moves farther than the
target's thickness within one time step. By setting the projectile's
continuousCollisionDetectionThreshold to match its diameter, you
ensure that SceneKit always detects collisions between the projectile
and other objects.

Related

Setup golf ball physics in Scenekit

I am developing a simple Golf game as shown in the below image.
I am facing below issues:
Even if I apply small amount of force, the ball continuous move along the grass? Grass friction is not stopping the ball.
Sometimes, the ball speed is increased after colliding with the walls instead the ball speed should decreased after collision with the walls. The walls are having box collider.
Sometimes, the ball reverses its direction after colliding with walls.
Code:
Physics properties of the ball:
ball.physicsBody.affectedByGravity = true;
ball.physicsBody.mass = 0.0450;
ball.physicsBody.restitution = 0.8;
ball.physicsBody.friction = 0.3;
ball.physicsBody.allowsResting = true;
Physics properties of the grass:
golf.physicsBody.friction = 0.8;
Physics properties of the walls:
leftWall.physicsBody.friction = 0;
leftWall.physicsBody.restitution = 0.8;
I have set the physics world gravity value to -9.8.
I am looking for suggestions to fix the above listed issue. Thank you.
To stop rolling, in a 3D physics world, you need angular damping, or linear damping, or a bit of both.
The friction component, when dealing with a rapidly spinning ball, can transpose to increased rate of movement, upon collisions.
A ball spinning in the reverse direction to its travel vector may have enough angular momentum to reverse its direction of travel when its friction is sufficient for it to gain traction on surfaces it collides with.

Notice when node position enters certain bounding box in scene kit?

is there a way to trigger a function, when a node (e.g. a tossed ball) enters a certain bounding box (e.g. a basket) in SceneKit / ARKit? If not, how would you implement this problem?
The way I would probably approach this. After obtaining a basketball hoop 3D dae model.
https://3dwarehouse.sketchup.com/model/fa42320b3def2c6b4741187cebbc52b3/Basketball-Hoop
I would first setup up the physicsShapes for the different elements.... backboard, pole & ring/hoop, floor & ball. I would then work out the cylinder size to fit inside the ring.
Using:
let cylinder = SCNCylinder(radius: 1.0, height: 0.1)
This becomes the physicBody for the hoop.
hoopNode.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry:cylinder))
I would then workout the collisions the ball has with each different basketball element/node.
Don’t forget to use the debug feature
SceneView.debugOptions = .showPhysicsShapes
This will help to visually debug the collisions with the physics shapes & make sure the physic shapes are accurately scaled and in the correct position.
How to do setup collisions has already been answered in a previous post here...
how to setup SceneKit collision detection
You probably want the ball to bounce off the backboard, pole and ring, but if it hits the hoop physic shape... you might want to make the ball disappear and create a nice spark/flame animation or something. You could then have a score that registers as well.
This Arkit game on github will give you a nice template for handling all those things, collisions, animations & scoring
https://github.com/farice/ARShooter
You have to implement it using the ball's world position and the basket world position + bounding box.
Calculate the size of the basket using it's bounding box:
var (basketBoundingBoxMin, basketBoundingBoxMax) = (basket?.presentation.boundingBox)!
let size = basketBoundingBoxMax - basketBoundingBoxMin
Use this size and the basket's world position to calculate:
Basket's minimum x,y,z
Basket's maximum x,y,z
Then check if ball's world position is inside the basket's minimum and maximum position.

Move along uneven physics body with Sprite Kit

I have a physics body that is uneven but not dynamic (the terrain) and a physics body (character) that is dynamic and is on top of the terrain, and I want this character to move along the terrain simulating kind of a "walking" action where it will keep going up the terrain but it won't fall back (or move back) like a ball because of gravity, and to set a maximum tilt so that it does not tip over.
My attempt was to add a force in the direction I want the character to move but this is causing the character to fall back due to gravity, and I don't want to disable gravity because then character won't fall down when going down the terrain.
Thank you very much
this is why using a physics engine for a platforming game is very difficult and not always a great approach..
you can try sprite.physicsBody.allowsRotation = false
might help
Create SKAction to move your character to destination point or dx and dy. Run that SKAction from your character node with the runAction. Like
SKAction.moveByX(...
When the action is finished, gravity will bring the character down.
If the movement is slow, play with the character's physicsBody friction and/or mass.
You can also change the the character's physicsBody.velocity = CGVectorMake(
And your terrain will be better with edgeLoop physicsBody which won't be dynamic.
And with uneven you mean inclined but smooth? If not smooth and with edges, your character may get held up at an edge depending on center of gravity of character and if you are allowing rotation.

Detecting when a circle really intersects a node

I use ball.frame.intersects(bar.frame), where ball = SKShapeNode(circleOfRadius: BALL_RADIUS) and bar = SKShapeNode(rectOfSize: <Some CGSize object>)
While this works, there is an invisible square in which the circle is inscribed. The diameter of the circle is the same as the side of the square. This square is what ball.frame is, so sometimes, the ball will act like it's intersecting the bar, but visually it's not.
In this screenshot you can see that the ball is stopped, and therefore the game is over because ball.frame.intersects(bar.frame) returned true, even though visually the ball isn't even touching the bar.
So how do I check if the ball is really intersecting the bar, and not if the ball's frame is intersecting?
SpriteKit has decently powerful collision detection in its physics subsystem — you don't have to roll your own.
Create SKPhysicsBody objects for the ball and the bars, using init(circleOfRadius:) for the former and init(rectangleOfSize: for the latter.
Then, you can either:
Drive all the movement yourself, and use SKPhysics only to test for collisions. In this case you need to set your scene's physicsWorld.gravity to the zero vector, and call allContactedBodies() on the ball when you want to see if it's contacting a bar.
Let SKPhysics drive the movement, by setting velocities or applying impulses. In this case you'll need to set a contact delegate for your physics world, and then you'll get a callback whenever a collision occurs.
For more details on either approach, see the docs.
After detecting that ball frame intersects box frame:
Determine the radius of the ball
Determine the point on the line that is the edge of the ball from the center of the ball to the edge of the box. (Hint: pythagorean theorem - hypotenuse = radius)
Is this point inside the box's rect?
Repeat for each point in the box.

Two Box2D Sprite Geometries Travel Different Distances With Same Impulse

I've created a box2d body that is attached to a second box2d body with a weld joint. The first box2d sprite associated with the body is in the shape of a stick. The second box2d body is a person that throws the first box2d body. The first box2d body is initialized as a polygon shape with a specified density, friction, and restitution. Depending on the game state, the first box2d body may get changed to a different sprite (but the box2d body remains the same). The new sprite is in the shape of a box. When the change to a new sprite is made, the original weld joint is destroyed and the new sprite is substituted. A new weld joint is created to reattach the box2d body to the second box2d body (i.e. reattached to the person). In addition, the box2d fixture of the first body is changed to have more friction and less restitution because I don't want the second type of sprite to bounce and slide as much as the first type of sprite.
In each case, I have an impulse that I apply to the first box2d body when I programmatically break the weld joint. With the second sprite (the box), the distance traveled after applying the impulse is much farther than the first sprite (the stick). I don't understand why there is such a difference since I've only changed the "look" of what is being thrown. The density and mass is the same. When I step through the code, the linear velocity appears to be the same in the box2d structure. There is apparently something in the physics that I don't understand.
My goal is to have both sprite types travel to the same location if given the same impulse. Is it possible to enable each sprite type behave the same? Please provide some guidance to achieve my goal.
Below is the code where I remove the old sprite and reattach the new sprite (note that "attachedBody" is the box2D body that was previously defined with the old sprite):
b2WeldJoint *myJoint;
// break the existing joint
// Destroy joint so the attachedBody will be free from the player
world->DestroyJoint(myJoint);
// Substitute the existing sprite with a new sprite. Also transform the position of the new sprite so that it is still touching the players hand
Box2DSprite *sprite = (Box2DSprite *) attachedBody->GetUserData();
[sprite setDisplayFrame: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: #"newSprite.png"] ];
attachedBody->SetTransform(teamA.foreArmBody->GetWorldPoint(b2Vec2(65.0/100.0, -25.0/100.0)), -40.0f); // move new sprite to the players hand. Rotate the angle by 40.
// Make this new sprite stick when it lands
attachedBody->GetFixtureList()->SetFriction(8.0);
attachedBody->GetFixtureList()->SetRestitution(0.0);
// Create a new weld joint with the players hand and the new sprite
b2WeldJointDef weldJointDef;
weldJointDef.Initialize(attachedBody, teamA.foreArmBody, teamA.foreArmBody->GetWorldPoint(b2Vec2(6.0/100.0, -10.0/100.0)));
weldJointDef.collideConnected = false;
myJoint = (b2WeldJoint*)world->CreateJoint(&weldJointDef);
After digging deeper to answer the above comments, I found that I was not comparing apples and oranges. My problem is that in one case, the first body (the stick) had zero velocity when I applied the impulse. When I substituted the sprite of the first body with a new sprite and then gave it the same impulse, the body had a non-zero initial velocity. Therefore it travelled much farther. My solution is simple. I just need to set the velocity to zero before applying the impulse to cause the two different sprites to travel the same distance. For example:
attachedBody->SetLinearVelocity(b2Vec2(0,0));

Resources