I import a 3D model into the ScenekKit, then change the Euler's angle of the limb and let the limbs do the action. However, at this time, clothes and limbs will penetrate. How can I handle this situation?
I think you have to use continuousCollisionDetectionThreshold instance property. This value gives you a minimum distance the body must travel for SceneKit to apply a more precise (but more CPU/GPU costly) algorithm to detect contacts with other bodies.
var continuousCollisionDetectionThreshold: CGFloat { get set }
SceneKit's physics engine can employ two kinds of collision detection:
With discrete collision detection, when SceneKit simulates physics before rendering each frame (see timeStep and SCNSceneRendererDelegate), it updates the position of each physics body based on the body's velocity during that time interval, then checks to see whether the body at its new position intersects other bodies.
With continuous collision detection, SceneKit calculates the volume that will be traversed by a body during each frame, then checks to see whether that volume intersects other bodies. This property's value defaults to 0.0, resulting in discrete collision detection at all times. When this value is nonzero, SceneKit applies continuous collision whenever the body travels more than the specified distance within one timeStep.
Discrete collision detection offers high performance, but can lead to inaccurate results for small, fast-moving bodies. Continuous collision detection has a performance cost and works only for spherical physics shapes, but provides more accurate results.
Related
How do I make my player move left/right at a constant speed until the user touches the screen again, which will then make the player change direction right/left and run that way at a constant speed etc..
I have tried looking at other answers but can't figure out a working answer.
I've set linearDamping to 0 already.
There are two basic ways to apply velocity.
One is by applying forces to physics bodies, or giving them velocities.
Two is positional transformations, usually done with SKActions.
They're not compatible.
Since you're using physics, you need to either apply force or set a velocity.
I think you should probably take the time to read this entire page:
https://developer.apple.com/documentation/spritekit/skphysicsbody
Here's the setting velocity cherry from it:
First, you can control a physics body’s velocity directly, by setting
its velocity and angularVelocity properties. As with many other
properties, you often set these properties once when the physics body
is first created and then let the physics simulation adjust them as
necessary.
And here's the outline on forces:
You can apply a force to a body in one of three ways: A linear force
that only affects the body’s linear velocity. An angular force that
only affects the body’s angular velocity. A force applied to a point
on the body. The physics simulation calculates separate changes to the
body’s angular and linear velocity, based on the shape of the object
and the point where the force was applied.
I'm trying to simulate a soccer game. I have a SCNPlane that simulates the court. I have imported a Soccer goal 3d model (.dae file) and also a ball model (.dae).
My ball has a dynamic physics body, the plane static and the goal is kinematic. I have set the categoryBitMask and contactTestBitMask for each one of the SCNNodes.
When I shoot the ball against the goal then sometimes the ball bounces and behaves as expected, but some other times the ball goes through the goal net and crosses it.
I have also assigned the SCNPhysicsContactDelegate and the didBeginContact is triggered when the ball bounces agains the goal but when the ball crosses it then the method is not called.
Do you know what might be happening?
Thank you!
Might be an issue with the ball moving too fast for the physics engine to calculate correctly. Try changing the "timeStep" value:
SceneKit processes the physics simulation and updates the state of all
physics bodies once per the time interval specified by this property.
The default value is 1/60 second (a rate of 60 Hz). A faster
simulation rate provides more accuracy in simulation results—such as
collisions between fast-moving objects—but at a higher cost in CPU
time (which may in turn slow down your app’s rendering frame rate).
Typically, you should set this property to match your target rendering
frame rate (as defined by the preferredFramesPerSecond property of the
SCNView object rendering your scene).
https://developer.apple.com/documentation/scenekit/scnphysicsworld/1512881-timestep
Instance property categoryBitMask defines which categories a physics body belongs to, and contactTestBitMask defines which categories of bodies cause intersection notifications with this physics body.
You need a collisionBitMask instance property that defines which categories of physics bodies can collide with this physics body.
var collisionBitMask: Int { get set }
When two physics bodies contact each other, a collision may occur. SceneKit compares the body’s collision mask to the other body’s category mask by performing a bitwise AND operation. If the result is a nonzero value, then the body is affected by the collision. Each body independently chooses whether it wants to be affected by the other body. For example, you might choose to avoid collision calculations that would make negligible changes to a body’s velocity.
The default value is all (a bit mask whose every bit is enabled), specifying that the body will collide with bodies of all other categories.
static var all: SCNPhysicsCollisionCategory { get }
all is default Type Property for a physics body’s collisionBitMask property.
I am making a Tetris kind of game, where I want my blocks to fall at a constant velocity. I want to achieve it using SpriteKit Physics Words Gravity.
Problem is that gravity is necessarily acceleration and hence block start to move faster as they fall. I know I can turn gravity off and use actions to move the block but I wish to do it with gravity.
Is there a way to make the gravitational force in SpriteKit world a linear constant velocity?
Using the default physics you will not achieve what you are looking for.
In the definition of Gravity in Spite Kit is clear that is a acceleration, so is no possible to achieve linear speed with it.
A vector that specifies the gravitational acceleration applied to
physics bodies in the physics world.
But, you can have some workarounds to achieve the behavior you want.
Gravity Acceleration 0, and add speed to the falling object.
Limit the maximum Speed of an Object.
Do you own physics
I Think the best way to do it, with gravity working as default, is by limiting the maximum speed.
2 - Limit the maximum Speed
Consulting this post.
In didSimulatePhysics(), you can verify the speed of the object, and limit it.
Like this (Credits to #Andrew, in the original post)
- (void)didSimulatePhysics {
if (node.physicsBody.velocity.x < MAX_SPEED_X) {
node.physicsBody.velocity = CGVectorMake(MAX_SPEED_X, MAX_SPEED_Y);
}
}
I'm working for a small bouncing ball game using the SpriteKit physics engine. My problem is:
When I apply a huge impulse on the bouncing ball to have it fall on ground fast, sometimes it may pass through the ground (very thin, height=2).
I find this in the Apple document, but it doesn't work.
Specify High Precision Collisions for Small or Fast-Moving Objects
When Sprite Kit performs collision detection, it first determines the locations of all of the physics bodies in the scene. Then it determines whether collisions or contacts occurred. This computational method is fast, but can sometimes result in missed collisions. A small body might move so fast that it completely passes through another physics body without ever having a frame of animation where the two touch each other.
If you have physics bodies that must collide, you can hint to Sprite Kit to use a more precise collision model to check for interactions. This model is more expensive, so it should be used sparingly. When either body uses precise collisions, multiple movement positions are contacted and tested to ensure that all contacts are detected.
ship.physicsBody.usesPreciseCollisionDetection = YES;
You can set your sprite's node.physicsBody.usesPreciseCollisionDetection = YES; but this will not guarantee a collision flag all the time as your sprite's velocity could simply be just too high.
You should apply a speed limit to your nodes as to prevent them from going too fast. Something like this:
if(node.physicsBody.velocity.dx > 200)
node.physicsBody.velocity = CGVectorMake(200, node.physicsBody.velocity.dy);
The above code example will limit the right movement, dx, of your node to 200 while keeping the dy (up/down) velocity as is.
Is it possible to accelerate an SKSpriteNode?
I know the velocity can be set easily with node.physicsBody.velocity but how hard would it be to set it's acceleration?
Working backwards from newtons second law a motion : F = m.a
You can achieve a desired acceleration by using applyForce where the force is the acceleration multiplied by the mass.
[node.physicsBody applyForce:CGVectorMake(node.mass*acceleration.dx,
node.mass*acceleration.dy)];
applyImpulse instantly imparts a quantity of energy (in Newton.seconds). Your object doesn't accelerate so much as instantly reach the desired speed. This is unlikely to look very natural as it implies near-infinite power (energy divided by time) therefore is only really suitable for explosions (shooting bullets for example).
applyForce applies a force (in Newtons) for the time-interval the simulation runs in (i.e.: 1/60th of a second). This allows you to correctly accelerate an object and simulate many different forces being applied simultaneously (gravity, wind, rocket boost etc.) in different directions.
Also worthy of note is applyForce:atPoint: this allows you to specify at which point of the object the force is applied. For example if you were simulating a balloon with a string, the string would apply its weight to the bottom of the balloon, whereas the lift of the base in balloon would be applied to the centre of the ballon. Applying a force elsewhere than at the centre of gravity will cause the object to rotate.
Lastly, you have the corresponding applyAngularImpulse: and applyTorque: which allow you to influence an object's rotation speed. This is useful for example if you want to keep an object upright despite various bounces: you could apply a torque proportional to the angle (or square it if you want to avoid oscillations).
All this is very well documented here: SKPhysicsBody
But if you need more information about the physics themselves then have a look at Wikipedia:
Newtonian Physics and associated pages (angular momentum for example).
If you want it to accelerate, then you should change the direction of gravity for the object
self.physicsWorld.gravity = CGVectorMake(dx,dy)
but this would make everything accelerate, if that is okay