I have a small object (hockey puck). When it’s velocity is too great, it doesn’t react with the box colliders for the ice surface, the end boards or the players.
I’ve tried playing around with the time values in the project settings, but it is hit and miss.
Is there anything I can do to get the physics engine to ‘catch’ the collisions of a small object at high speeds?
Should I scale everything up in size? But then I would have to scale up the speed as well.
I’m stumped. Any advice would be greatly appreciated.
If you create a denser mesh, ie more polygons/verts, that will increase colision detection. this may solve your problem.
AC
Edit-I guess your using a mesh collider for your puck and need to use primitives for your level. Try having 4 or 8 box colliders side by side where you currently have one…HTH
How are you moving the object. I know when moving something at a high speed by directly changing it’s location, or using the translation, it will often not collide.
I’d probably raycast in the direction the puck is traveling in, and the length of the raycast should be the distance the puck would travel in one physics frame (which you’d get from the velocity’s magnitude). If the raycast hits anything, move the puck to the raycast hit location. That way it should collide 100% of the time. Otherwise the puck can pass though objects from one physics frame to the next and thus not register a collision, which you already know but I said it anyway.
Not such a good idea if so…I used a mesh collider for the coin in Unity Invaders, but had to limit the velocity (you can “throw” the coin around), or else it would do some really wacky things. For Unitroids, I switched the coin’s collider to a group of 8 box colliders instead, which works about 95% as convincingly as the mesh collider but doesn’t have any problems.
I would use a raycast instead too. You don’t even need to have a rigidbody envolved. And if your hockey sticks actually collide with the puck as it is now, it would be simple to create a hockey stick script that fakes collisions with the puck.
Generally anything that is too small/fast for the physics engine should be raycasted.
There might be problem raycasting as the ball is moving on a dynamic curved path (I believe), so you probably need to precalculate the end of the path (or any points in the air if there is collision in the air), and check for collision there, and then you could use raycasting after it lands. Here’s how to use Raycasts: http://unity3d.com/Documentation/ScriptReference/Physics.Raycast.html?from=RaycastHit
I’ll try using a raycast - I’m learning Unuty as I go - so I’ll give it my best.
One question though - I am using rigidbody.AddForce to move the puck. If I use a raycast to catch collisions - how should I use that info to move the puck? Do I cancel out the rigidbody.velocity for the physics frame that involves a collision and move the puck’s transform.position via coding?
Well, no, you’d just get the forward velocity of the ball. My idea is to look forward a small bit (the distance between physics frames) as it’s moving. This avoids the “passing through obstacles” effect. With all due respect to the mighty Yogster, I’d stick with rigidbodies because you want the puck/ball to bounce around and stuff, and objects can change between the time you hit the puck/ball and the time it hits something. Unlike a bullet where you just look along a straight line to the hit point and it goes more or less instantly.
But as far as the soccer ball, try increasing the physics timestep first. I don’t think you’re doing much physics, so you should be fine increasing it from .02 to .01 (which makes physics go 120fps instead of 60fps). If that doesn’t work, then we’ll try the raycasting.
So, the solution is to not use the built in phyics engine and script all the physics?
Anyway to do this utilizing the physics engine?
By the way - I am seeing some odd behavior with the physics engine. I have a puck with a box collider and a rigidbody attached. I let it drop from 100 meters high onto a flat plane.
The puck falls due to gravity - it bounces once - goes up, then back down - and then it FALLS through the plane.
Why would it register a collision on the first impact and not the second? The velocity is greater on the first hit (having fallen 100 meters) than on the 2nd bounce.
Why would the physics engine catch the collision on the faster velocity and not the slower velocity?
I think I may have a solution. The issue seems to be the small size of the box collider around the puck. If I make the box collider larger, it can handle the collisions at higher speeds.
But that kind of looks odd - the collision happens before the puck actually touches anything (the box collider is larger then the puck mesh).
But I can offset the box collider so that the leading edge of the puck is up against the edge of the box collider in the direction it is traveling.
And that looks and works perfect. I’ve been doing this all via the inspector. Once I code something that works, I’ll post it.
If the collider happens to intersect with another collider that frame, no matter how fast it’s going, then you’ll get a collision. But if the collider happens to just miss intersecting with another collider even if it’s going slower, it won’t collide. So it can be kind of random. But faster speeds are more likely to result in misses.
Anyway, you seem to have a pretty nifty solution. If that works, go for it. If you’d still like to use raycasting, try this:
private var diameter : float;
function Start() {
// Use "diameter = collider.radius * 2" for sphere colliders
diameter = collider.extents.y * 2; // Should be smallest axis
}
function FixedUpdate() {
var distanceThisFrame = rigidbody.velocity.magnitude * Time.deltaTime;
// If the distance is less than the diameter, just let the physics engine handle collision detection
if (distanceThisFrame > diameter) {
var hit : RaycastHit;
var direction = rigidbody.velocity.normalized;
// If we would hit something this frame, move to that position to ensure it
if(Physics.Raycast(transform.position, direction, hit, distanceThisFrame)) {
transform.position = hit.point;
}
}
}
DaveyJJ, that works well for soccer balls…note the comment in the Start function.
If you’d like to try something that approximates a cylinder for the hockey puck so that it might have more realistic reactions to collisions, make some box colliders as children of the puck, as shown below.
And make sure the collider(s) are on the Ignore Raycast layer, or else the raycast will detect the puck/ball itself, and then bad things can happen.
Question! Why doesn’t Ageia do this anyway? After a certain point, increasing the rate FixedUpdate fires has diminishing returns. Checking lines between previous and current positions isn’t a perfect solution, but it’s better than missing entirely when you go through something.
Just checking the lines is not a completely robust solution. If the object is mostly spherical, you’d have to check the capsule (“swept sphere”) - because a ray from current position to future position might pass, but object should have collided with something just a bit “off the center”.
It gets more complicated with non-spherical objects, i.e. how would you robustly check a box that is moving, while rotating at the same time? The proper way would be colliding something like a “screw” shape…
Thanks for the help, Eric. I’m still learning Unity, so Ignore RayCast layer is new to me.
But I think a combination of dynamically changing the size of the box collider size and center with respect to velocity works well in combination with Physics.Raycast.
Pseudo code:
if (Physics.Raycast hit.distance <= velocity.magnitude)
adjust box collider to register the collision
else
reset box collider to original state
I’m working on the code now - I have the box collider size and center adjusting dynamically to velocity and it works great, but I anticipate side effects such as a collision registering behind the puck if a player should skate in behind the puck.
So I will now try the raycast conditional statement.
Will post some code soon.
Mitch
PS - Your code looks a lot simpler than my crazy solution. Might just go with your code. Thanks again.
It’s also useful for when you have invisible trigger areas that block effects like lens flares. In this case you just put the triggers on Ignore Raycast and the effects will show through properly. Also if you have objects or triggers blocking other objects that you want to react to OnMouseOver etc. events, then put the blocking objects on Ignore Raycast and mouse events will go through them.
As far as raycasting, it might be useful to cast several rays from the edges of the object instead of one from the center. That should take care of perfect spheres, although it still wouldn’t account for possible tumbling of any other shape. But I think you could assume that objects aren’t going to tumble enough from one physics frame to the next to make any real difference, especially since Max Angular Velocity defaults to a quite low value. Effectively I think several raycasts would cover almost all real situations.
But I guess at some point you have to say “good enough”…at those extreme speeds I doubt you’d be able to tell visually if the puck (or whatever) should have clipped something or not anyway. The big concern is having objects just pass right through stuff they obviously shouldn’t, so even one ray prevents that.
I guess it just seems that even a non-robust solution would be better than none. Currently, it’s very easy for small things to go through big ones, and checking a few lines could prevent most of the instances I’ve seen.
I’m trying to learn from your coding example, but it’s just not working. I’m dropping the puck from 1000 meters so by the time it reaches the playing surface, it’s gained a lot of velocity.
With your script attached - it just passes right through.