Search Unity

Best Bullet Collision Method

Discussion in 'Physics' started by Michael_Waltham, Apr 6, 2017.

  1. Michael_Waltham

    Michael_Waltham

    Joined:
    Aug 20, 2014
    Posts:
    31
    Hi There,

    Our small team is currently working on a 3D shooter style game. Initially, all bullets used triggers as opposed to physical colliders. We then called the appropriate damage methods and such in the OnTriggerEnter function. The result of this was bullets exploding too far into objects as there is no physical collision to correct the bullet using Rigidbody continuous collision detection before the explosion occurs. Note that this even occurred with relatively slow moving bullets as seen in the image below.

    Our solution was then to use physical colliders on the bullets with continuous rigidbody collision detection, which seems to be what Unity did in the tanks demo. This is now causing many problems further down the line as bullets physically push enemies back on impact (due to mass) as well as many other related problems. It seems far more intuitive to make bullets use trigger colliders instead however this brings us back to square one as mentioned above.

    Any suggestions on this topic would be greatly appreciated.

    89682-collisions.jpg
     
  2. Svenberra

    Svenberra

    Joined:
    Nov 5, 2012
    Posts:
    4
    One method could be to raycast instead. Give the bullet object a rigid body but no collider. Add a script to the bullet that cast a ray between the bullet's previous position and current position. If your bullets must have a volume like in the picture you could use SphereCast instead of RayCast. Also this could be used for arrows. The current and previous position also gives you the movement direction so you could align the arrow(or bullet) model along the trajectory.
     
  3. Michael_Waltham

    Michael_Waltham

    Joined:
    Aug 20, 2014
    Posts:
    31
    Thanks for the feedback. We were just wondering that surely a raycast for every bullet every frame is a bit too expensive?
     
  4. Svenberra

    Svenberra

    Joined:
    Nov 5, 2012
    Posts:
    4
    Hmm, well i haven't really used raycasts in Unity so I don't know how efficient they are.
    When CCD is enabled for an object I've read that physx use an algorithm based on the velocity to determine if discrete collision detection can be used or not. Doing a spherecast every frame would probably be a bit slower since that would be like doing a CCD Sweeptest every frame.

    But perhaps a hybrid approach could be used.
    Use your first mentioned method, that is, flag the collider as a trigger and in OnTriggerEnter do a single raycast from the previous position to get the exact point of impact.
     
  5. Michael_Waltham

    Michael_Waltham

    Joined:
    Aug 20, 2014
    Posts:
    31
    I did try that hybrid approach. Here is a simplified bit of code describing how I went about it:

    Code (CSharp):
    1. Vector3 PreviousLocation;
    2.  
    3. void OnTriggerEnter(Collider Other)
    4. {
    5.     rb.isKinematic = true;
    6.     rb.velocity = Vector3.zero;
    7.     transform.position = PreviousLocation;
    8. }
    9.  
    10. void FixedUpdate()
    11. {
    12.    PreviousLocation = transform.position;
    13. }
    Ignoring any raycasting at this point, the above code moves the object to the previous location before the trigger happens. This previous location is still inside the colliding object which makes no sense. It seems as though the trigger was called a frame late.
     
  6. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,532
    I would just drop the bullet mass down until it didn't push anything.

    Before Unity fixed continuous detection one workaround was to do a raycast every frame from the last position to the goal position (after transform updates) and if the ray could reach the distance without hitting anything then nothing was in the way and the transform could occur. If it did hit something then it was stored and did the whole damage/despawn gig. This prevented the bullet-through-paper issue and bypassed rigidbody requirements on projectiles.

    Try not to overcomplicate it, give things a good try and adjust settings to truly see if something can work. If it does and performs well then there's really not a big demand to do something different.
     
  7. Michael_Waltham

    Michael_Waltham

    Joined:
    Aug 20, 2014
    Posts:
    31
    I have managed to find a preemptive solution which is keep bullets as physical colliders and to create 4+ layers including: EnemyHitbox, PlayerHitbox etc...

    Dropping the bullet mass was also a part of this solution.
     
  8. Zaddo67

    Zaddo67

    Joined:
    Aug 14, 2012
    Posts:
    489
    I have a shelved project for a FPS game that used projectiles. I found the Physics engine is not up to handling high speed objects.

    After a lot of trial and error and fine tuning I ended up using raycast's like Svenberra suggested above. I also calculated the projectiles trajectory and handled the projectile movement in code. I found the performance to be very good, but I did do a lot of optimising.

    If your game is going to be multiplayer, then you are going to have a lot more problems to solve with lag compensation.

    https://developer.valvesoftware.com/wiki/Lag_compensation
     
  9. Knoxxyy

    Knoxxyy

    Joined:
    Jul 19, 2021
    Posts:
    2
    I know this is an older Post, but I had a similar problem. What I found out is, that if you use the collision detection of Rigidbody, use OnCollisionEnter.
    All code written in that is executed before the "Energy" is transfered to the Object. If you do what you need to do, like make an explosion and delete the GameObject at the end of OnCollisionEnter, no Energy is transfered to the target that was hit.

    Edit: Also change the Collision detection in Rigidbody of your Bullet from descrete to continous. That Way, Bullets with High Velocity dont pass through the object thats been hit.

    Edit 2: The first part with no transfered impulse is wrong, I tested it again with different results.
     
    Last edited: Jul 25, 2021
    atassisha likes this.
  10. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    If you're saying that the impulses the solver calculates are applied after this call then you are mistaken. Both 2D and 3D physics callbacks happen at the end of the simulation step. They are telling you what already has happened.
     
  11. Knoxxyy

    Knoxxyy

    Joined:
    Jul 19, 2021
    Posts:
    2
    Yeah, my bad. I did a test before writing that, and it didnt change anything for the target hit.
    Now I redid the same test and the cube goes flying.

    Is the only way to not transfer an impulse by making the bullet have basically 0 mass?
     
  12. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    This is what a Kinematic body type is for.
     
  13. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,928
    Certainly not as expensive as using a rigidbody for each bullet. A raycast just finds the closest surface hit (if any) in a direction. By comparison a rigidbody does more complex stuff every timestep of its lifetime, as it has to detect and solve contacts against other objects.

    Id' use a rigidbody for relatively slow-moving, large bullets. Think of grenades, for instance. For very fast, small bullets (a typical gun bullet), raycasts are the way to go: both cheaper and more robust.

    Edit: if you don't want "instant" bullets that hit as soon as the user presses the trigger, but still pretty fast (star-wars style blasters) you can "slide" a raycast along a trajectory: raycast from point A to point B, next frame you update B by moving it forward along the trajectory and your new A is your old B. Rinse and repeat. Hope that makes sense.
     
    Last edited: Jul 28, 2021