How to handle (near)insta-hit bullets
How to handle (near)insta-hit bullets
I think the next hardest thing, after jumping, my game requires is going to be this.
We have bullets that need to be shot and hit the other side of the level almost instantly (very quickly). Right now, we have a sphere shot out really quickly (and we still want it to be faster). The problem is, the faster the sphere moves, the less likely it is going to actually collide with an object (including a player and the level mesh itself). In fact, we don't even have the sphere collide with the level, as the level is a mesh, and I haven't figured out how to check for collision between a sphere and the mesh (but it is easy to check if the sphere collides with the characters sphere, or a box or some shape).
I guess the thing I need help on is: How to shoot a fast bullet and know when it collides with something, and be able to tell what that something is, whether it be the level mesh or a shape? Is this when ray casting should be used? If so, are there any good tutorials and/or examples for beginners in that area? Is there a better way?
We have bullets that need to be shot and hit the other side of the level almost instantly (very quickly). Right now, we have a sphere shot out really quickly (and we still want it to be faster). The problem is, the faster the sphere moves, the less likely it is going to actually collide with an object (including a player and the level mesh itself). In fact, we don't even have the sphere collide with the level, as the level is a mesh, and I haven't figured out how to check for collision between a sphere and the mesh (but it is easy to check if the sphere collides with the characters sphere, or a box or some shape).
I guess the thing I need help on is: How to shoot a fast bullet and know when it collides with something, and be able to tell what that something is, whether it be the level mesh or a shape? Is this when ray casting should be used? If so, are there any good tutorials and/or examples for beginners in that area? Is there a better way?
Re: How to handle (near)insta-hit bullets
Setting the entity's PositionUpdateMode to continuous will prevent it from missing collisions entirely. Contacts are generated between a sphere and a mesh like any other pair of objects. They'll show up in the entity.CollisionInformation.Pairs.Contacts list.The problem is, the faster the sphere moves, the less likely it is going to actually collide with an object (including a player and the level mesh itself). In fact, we don't even have the sphere collide with the level, as the level is a mesh, and I haven't figured out how to check for collision between a sphere and the mesh (but it is easy to check if the sphere collides with the characters sphere, or a box or some shape).
That said...
I guess the thing I need help on is: How to shoot a fast bullet and know when it collides with something, and be able to tell what that something is, whether it be the level mesh or a shape? Is this when ray casting should be used? If so, are there any good tutorials and/or examples for beginners in that area? Is there a better way?
Ray casting is indeed a better approach here. The most direct way to do this is to just use the Space.RayCast method. There's a variety of overloads- some have maximum lengths, some take filters, some output multiple hits.
The hit data includes the location, the normal direction at the impact point (not necessarily normalized for performance reasons if I remember correctly), and the 't' parameter (distance along the ray in units of the ray's length). The ray cast also reports the hit object in the form of a BroadPhaseEntry.
A BroadPhaseEntry is any object which lives in the BroadPhase. Examples of BroadPhaseEntry objects include Terrain, StaticMesh, InstancedMesh, and EntityCollidable (and all of its children). EntityCollidables are collision detection proxies owned by entities. So, if you can determine that a BroadPhaseEntry is an EntityCollidable, you can cast it to check its Entity property to get the owner.
Note that all BroadPhaseEntry objects have a Tag property. This is convenient for linking the entry to game logic objects. This Tag is separate from the Entity class's Tag property, so they can be set independently.
If additional control over ray casting is required- perhaps some special type-specific ray cast, for example- you can bypass the Space.RayCast convenience functions. The BroadPhase.QueryAccelerator supports queries including ray casts. The returned broad phase entries are any entries which have bounding boxes which overlap the query object as opposed to actual ray cast hits. The Space.RayCast uses that method and then calls each BroadPhaseEntry's ray cast method.
There are no tutorials specifically tailored for ray casting, but you can see it in use in various places in the demo. The grabber relies on it, as does the vehicle chase camera.
Re: How to handle (near)insta-hit bullets
I do realize that ray casting would be the best way to do this, but I have never messed with ray casting yet, and need to get this done ASAP (The Beta is due in a week). So, in the future, I will change this to ray casting. But for now, I have to do the quick and dirty way of checking the pairs (if this works).
I realized what my problem was with mesh collision: The entity must have a mass. So now that I can effectively check the collision pairs, how do I check what was hit?
I realized what my problem was with mesh collision: The entity must have a mass. So now that I can effectively check the collision pairs, how do I check what was hit?
Re: How to handle (near)insta-hit bullets
Every pair has a BroadPhaseOverlap property which contains the two broad phase entries which are overlapping. There's also an OverlappedCollidables convenience property which goes through all the pairs and enumerates the 'other' collidables for you.So now that I can effectively check the collision pairs, how do I check what was hit?
Once you have the 'other' broad phase entry/collidable, it works exactly the same as ray casting as far as identifying the object goes.
Re: How to handle (near)insta-hit bullets
Is there an example somewhere?
Re: How to handle (near)insta-hit bullets
Here's an example:
Code: Select all
foreach (var c in entity.CollisionInformation.OverlappedCollidables)
{
//Broad phase entries can have tags. Tags can contain any object, such as user data objects.
var someGameLogicObject = c.Tag as SomeGameLogicObject;
if(someGameLogicObject != null)
{
//Do something!
someGameLogicObject.Poot();
}
//Is this an entity?
//(The entity's CollisionInformation is an EntityCollidable which is a Collidable which is a BroadPhaseEntry.)
var entityCollidable = c as EntityCollidable;
if(entityCollidable != null)
{
//We can get the entity associated with an entity collidable using the Entity property.
//An entity's tag is separate from the broad phase entry tag.
StaticPoot.Tootify(entityCollidable.Entity.Tag);
}
}
Re: How to handle (near)insta-hit bullets
Awesome, that works great with entities!
Just one more thing... Now how do I check if it is colliding with the level mesh? I have tried:
But mesh == levelMesh evaluates to true even if the ball is not colliding with the mesh.
Just one more thing... Now how do I check if it is colliding with the level mesh? I have tried:
Code: Select all
var mesh = c as StaticMesh;
if (mesh != null)
{
if (mesh == levelMesh)
{
....
}
}
Re: How to handle (near)insta-hit bullets
A CollidablePairHandler is created for any pair of collidables with bounding boxes which overlap. That pair handler then checks the actual shape geometries to see if there are contacts. Every CollidablePairHandler has a Contacts list. If the list's Count is greater than zero, there's been a collision.
(Technically, the existence of contacts does not guarantee the existence of a current collision. The engine uses a form of speculative contacts which can have negative penetration depth. In the current implementation, these are not used for CCD, so they do not occur until after an initial collision. The end result is that for first-impact detection, having nonzero contacts means collision. In the more general case, at least one contact with nonnegative penetration depth implies a collision. So, for one-hit bullets, the contact count method is fine. However, more complex things like the CharacterController must be aware of speculative contacts.)
(Technically, the existence of contacts does not guarantee the existence of a current collision. The engine uses a form of speculative contacts which can have negative penetration depth. In the current implementation, these are not used for CCD, so they do not occur until after an initial collision. The end result is that for first-impact detection, having nonzero contacts means collision. In the more general case, at least one contact with nonnegative penetration depth implies a collision. So, for one-hit bullets, the contact count method is fine. However, more complex things like the CharacterController must be aware of speculative contacts.)
Re: How to handle (near)insta-hit bullets
And there we go!! Thank you for baring with me! You have been a lot of help yet again. 

Re: How to handle (near)insta-hit bullets
Ok, running into a few bugs that may be fixed if I switch to ray casting.
1) Precision of collisions seems dramatically off. When I shoot a player, the ball is colliding when it is nearly 5X the player's collision away (sometimes).

As you see, the balls around him should be where the hit box actually is. All of the other balls are hitting him, but shouldn't be. Is ray casting precision more precise?
EDIT:
Testing more, the projectiles are more precise the further the player is from the target.
2) You can see the ball bounce before it is removed since it is moving so quickly. Is there a way to make the ball stick instead? If I did this with ray casting, would I basically cast a ray (or 6 around the edges of the circle), find out if it hits, then just move the ball from the starting point to the end point and remove it so the bouncing didn't actually happen?
3)Since the ball is shot from where the camera is, and the camera is positioned slightly above the circle for the offset but still inside, the ball is shooting through the player and colliding with them. Now, I made this so it doesn't hurt them in game and isn't removed, but the problem comes if the shoot it at the right angle, the ball will make them bounce back. And the player could essentially rocket jump if you time it right. This isn't that big of a problem. Is there a way to make it so the ball doesn't collide with the player at all (remove the collision between two or more objects in the space)?
1) Precision of collisions seems dramatically off. When I shoot a player, the ball is colliding when it is nearly 5X the player's collision away (sometimes).

As you see, the balls around him should be where the hit box actually is. All of the other balls are hitting him, but shouldn't be. Is ray casting precision more precise?
EDIT:
Testing more, the projectiles are more precise the further the player is from the target.
2) You can see the ball bounce before it is removed since it is moving so quickly. Is there a way to make the ball stick instead? If I did this with ray casting, would I basically cast a ray (or 6 around the edges of the circle), find out if it hits, then just move the ball from the starting point to the end point and remove it so the bouncing didn't actually happen?
3)Since the ball is shot from where the camera is, and the camera is positioned slightly above the circle for the offset but still inside, the ball is shooting through the player and colliding with them. Now, I made this so it doesn't hurt them in game and isn't removed, but the problem comes if the shoot it at the right angle, the ball will make them bounce back. And the player could essentially rocket jump if you time it right. This isn't that big of a problem. Is there a way to make it so the ball doesn't collide with the player at all (remove the collision between two or more objects in the space)?
Re: How to handle (near)insta-hit bullets
That level of imprecision is not expected unless there are truly immense values involved. Convex casts use iterative methods which suffer in the presence of extreme numerical conditions (particularly with long thin shapes, which nigh-infinite rays are1) Precision of collisions seems dramatically off. When I shoot a player, the ball is colliding when it is nearly 5X the player's collision away (sometimes).
...
As you see, the balls around him should be where the hit box actually is. All of the other balls are hitting him, but shouldn't be. Is ray casting precision more precise?


A more immediately noticeable problem with velocities high enough to trigger that level of imprecision would be horrific performance issues. The bounding box of one frame of motion would be large enough to cover a large portion/all of the environment. Every overlapped triangle would need to be tested.
Ray casts are indeed more accurate in general. An infinite ray cast is perfectly acceptable because the algorithms are significantly different. Additionally, rays are tested against the acceleration structures directly rather than wrapping them in a bounding box so only objects truly near the ray need to be considered, providing much better performance for long casts.
However, there's also a possibility that the picture isn't actually showing numerical issues in a convex cast, but some other problem that ray casting won't automatically fix.
Here's the update-by-update look at what's happening here:2) You can see the ball bounce before it is removed since it is moving so quickly. Is there a way to make the ball stick instead?
Update 1:
Update Contacts: no contacts yet; it hasn't collided
Perform Collision Response: no contacts to solve yet
Perform CCD: no impending collision
Update Position: advance all the way through the frame's motion
Update 2:
Update Contacts: no contacts yet; it hasn't collided
Perform Collision Response: no contacts to solve yet
Perform CCD: can only advance 60% of the total motion because a collision was found
Update Position: move up to the collision time
Update 3:
Update Contacts: the objects are in collision and here's the contacts
Perform Collision Response: new velocities computed because of contacts
Perform CCD: newly computed velocities will stop the objects from going through each other, no CCD needed
Update Position: update position with new velocities, sending it flying off in some new direction
So, in the first frame where there exist contacts, the object's position is already moved. To avoid visualizing the bounce, the renderer should not display the projectile body after contacts have been found.
There should not be a need to make the projectile physically 'stick.' Once the projectile is found to hit an object by checking the contacts, the physical body can be removed and then you can do whatever is desired as far as graphics are concerned. If a point of impact is needed to spawn particles, the contact position would suffice.
When using ray casting, any projectile body would be a purely graphical object so you could choose to do whatever you want with it. There would be no bouncing because rays are not physical; they are a query.If I did this with ray casting, would I basically cast a ray (or 6 around the edges of the circle), find out if it hits, then just move the ball from the starting point to the end point and remove it so the bouncing didn't actually happen?
Yup, collision rules. Check out the CollisionFilteringDemo in the BEPUphysicsDemos to see it being used. A variety of other demos also use them to set up the simulation (robot arm demo and ragdoll, for example).3)Since the ball is shot from where the camera is, and the camera is positioned slightly above the circle for the offset but still inside, the ball is shooting through the player and colliding with them. Now, I made this so it doesn't hurt them in game and isn't removed, but the problem comes if the shoot it at the right angle, the ball will make them bounce back. And the player could essentially rocket jump if you time it right. This isn't that big of a problem. Is there a way to make it so the ball doesn't collide with the player at all (remove the collision between two or more objects in the space)?
I would recommend just switching over to ray casts to avoid all the complexities involved with making a physical object move at extremely high speeds. It'll end up being quite a bit simpler in the end

Re: How to handle (near)insta-hit bullets
Even though it will take more time, my team will have to deal with it. To your response to question 1, the further you are away, the more precise it is. You really only get that bad of precision when about at that distance, maybe a bit further. The speed is only 8000 (remember though, my level is scaled up by 10, I think they did that to fit the animation models, and I do the ApplyScale function in the demo you provided). Here is the code:
Could the problem be the same type of problem with the level I was having above, where I need to check the contacts count between the two?
2) I was removing the ball from the rendering but I then realized the server is re-adding the ball to the client for another frame. But I will be switching to raycasting, so this won't be a problem anymore.
Code: Select all
foreach (var c in proj.mEntity.CollisionInformation.OverlappedCollidables)
{
var entityCollidable = c as EntityCollidable;
if (entityCollidable != null)
{
if (entityCollidable.Entity is Box)
{
foreach (GameObject trap in traps)
{
if ((Box)entityCollidable.Entity == trap.mEntity)
{
...
}
}
}
else if (entityCollidable.Entity is Sphere)
{
foreach (GameObject player in players)
{
if (proj.OwnerID != player.objectID && (Sphere)entityCollidable.Entity == player.mEntity)
{
...
}
}
}
}
2) I was removing the ball from the rendering but I then realized the server is re-adding the ball to the client for another frame. But I will be switching to raycasting, so this won't be a problem anymore.
Re: How to handle (near)insta-hit bullets
Yup. At 8000 units per second and 60 updates per second, each frame's bounding box is somewhere between 76 and 134 units across in some dimension. If it only checks for pair existence instead of contact existence, anything within that rather big bounding box will be 'hit' improperly. Since the bounding box is axis aligned, certain directions (closer to X, Y, or Z) will appear to be more precise.Could the problem be the same type of problem with the level I was having above, where I need to check the contacts count between the two?