Search Unity

Bullet Penetration Bug

Discussion in 'Scripting' started by Aidenjl, Oct 26, 2014.

  1. Aidenjl

    Aidenjl

    Joined:
    Jan 5, 2014
    Posts:
    81
    Hello, I've recently tweaked the bullet penetration script on my code so that it can tell the thickness of the object that it passes through. However this is all working well untill I shoot an object that is close to another one.

    The bullet appears to register going through the front of the first object and the coming out the back of the second object. Like so:

    (The red line represents the visual path of the bullet, ie where it leaves bullet holes. The bullet does actually travel through the middle it just doesn't register that it has)

    Code:
    Code (JavaScript):
    1.  
    2. #pragma strict
    3. #pragma implicit
    4. #pragma downcast
    5.  
    6.  
    7.  
    8. //BULLET Particles
    9. var Untagged : GameObject;                   // default bullet hole
    10. var Concrete : GameObject;                    // concrete bullet hole
    11. var Wood : GameObject;                        // wood bullet hole
    12. var Metal : GameObject;                        // metal bullet hole
    13. var Dirt : GameObject;                        // dirt/sand bullet hole
    14. var Blood : GameObject;                        // blood bullet hole
    15. var Glass : GameObject;                        // glass bullet hole
    16. var Snow : GameObject;                        // Snow bullet hole
    17. var Water : GameObject;                        // water bullet hole
    18.  
    19.  
    20. var IsTracer : float;
    21. var Tracer : boolean = false;
    22. var TrailScript : GameObject;
    23.  
    24. var lifeTime : float = 2.0;                        // bullet life Time
    25. var mask : LayerMask = 1;
    26. var Gravity : float = 2;
    27. var distance : float;
    28. var DamageDropoff : float;
    29. var FinalDamage : float;
    30. var RawDamage : float;
    31. var DropCurve : AnimationCurve = new AnimationCurve();
    32.  
    33. var debugDamage : boolean = false;
    34.  
    35. private var hitCount : int = 0;                    // hit counter for counting bullet impacts for bullet penetration
    36. private var damage : float;                        // damage bullet applies to a target
    37. private var force : float;
    38. private var maxHits : float = 3;                    // number of collisions before bullet gets destroyed  
    39. private var impactForce : float;                // force applied to a rigid body object
    40. private var maxInaccuracyHIP : float;            // maximum amount of inaccuracy
    41. private var spread : float;                        // used in machineguns to decrease accuracy if maintaining fire
    42. private var speed : float;                        // bullet speed
    43. private var hit : RaycastHit;
    44. private var hit2 : RaycastHit;
    45. private var player : GameObject;
    46. var Rotation : Transform;
    47. var ExitPoint : Vector3;
    48. var Width : float;
    49. var EntryPoint : Vector3;
    50. //private var goWind:GameObject;
    51. var MaximumPenetration : float = 2;
    52.  
    53. private var velocity : Vector3 = Vector3.zero;  // bullet velocity
    54.  
    55. private var hasHit : boolean = false;            // has the bullet hit something?
    56. private var ignore : Collider = null;            // ignore this collider
    57. private var direction : Vector3;                // direction bullet is travelling
    58. private var direction2 : Vector3;
    59. private var newPos  : Vector3;
    60. private var oldPos : Vector3;
    61. var startPos : Vector3;
    62. var endPos : Vector3;
    63. var dist : float;
    64.  
    65. private var isTracer : boolean = true;
    66. private var bulletInfo : float[] = new float[2];
    67.  
    68.  
    69. function SetUp(bulletInfo : float[] ){            // information sent from gun to bullet to change bullet properties
    70.     damage = bulletInfo[0];                      // bullet damage
    71.     force = bulletInfo[1];                         // force applied to rigid bodies
    72.     maxHits = bulletInfo[2];                     // max number of bullet impacts before bullet is destroyed
    73.     maxInaccuracyHIP = bulletInfo[3];           // max inaccuracy of the bullet
    74.     spread = bulletInfo[4];                      // current inaccuracy... mostly for machine guns that lose accuracy over time
    75.     speed = bulletInfo[5];                       // bullet speed
    76.     IsTracer = bulletInfo[6];                   // Is it a tracer? (Trail Renderer)
    77.    
    78.     newPos = transform.position;                   // bullet's new position
    79.     oldPos = newPos;                               // bullet's old position
    80.    
    81.    
    82.     velocity = speed * transform.forward;         // bullet's velocity determined by direction and bullet speed  
    83.    
    84.     // drection bullet is traveling
    85.     direction = transform.TransformDirection(Random.Range(-maxInaccuracyHIP, maxInaccuracyHIP) * spread, Random.Range(-maxInaccuracyHIP, maxInaccuracyHIP) * spread, 1);
    86.    
    87.     Destroy(gameObject, lifeTime);
    88. }
    89.  
    90.  
    91.  
    92. function Start() {
    93. GetComponent(MeshRenderer).enabled = false;
    94. yield WaitForSeconds(0.01);
    95. GetComponent(MeshRenderer).enabled = true;
    96. //goWind = GameObject.Find("Wind");
    97.  
    98. if (IsTracer == 1){
    99. Tracer = true;
    100. }
    101. if (Tracer == true){
    102. TrailScript.GetComponent(TrailRenderer).enabled = true;
    103. }
    104. startPos = transform.position;
    105. }
    106.  
    107.  
    108. function FixedUpdate(){
    109. newPos += (velocity + direction) * Time.deltaTime;
    110. oldPos = transform.position;  // set old position to current position
    111. transform.position = newPos;  // set current position to the new position
    112. if(hasHit)
    113. return;
    114.    
    115.     // Check if we hit anything on the way
    116.     var dir : Vector3 = newPos - oldPos;
    117.     dist = dir.magnitude;
    118.     var fwd = transform.TransformDirection (Vector3.forward);
    119.     var back = transform.TransformDirection (Vector3.back);
    120.    
    121.  
    122.    
    123.         // normalize
    124.          dir /= dist;
    125.        
    126.     if(Physics.Raycast(newPos - (newPos - oldPos), fwd, hit, dist)){
    127.             newPos = hit.point;
    128.                // notify hit
    129.             OnHit(hit);
    130.             EntryPoint = newPos;
    131.             if (hitCount >= maxHits) {
    132.                 hasHit = true;
    133.                    Destroy(gameObject);
    134.           }
    135.     }
    136.  
    137.     if (Physics.Raycast(newPos + (newPos - oldPos), back, hit2, dist)) {    // send a ray behind the bullet to check for exit impact  
    138.                 ExitPoint = hit2.point;
    139.                 Width = Vector3.Distance(EntryPoint, ExitPoint);
    140.                 Debug.Log("Width is: " + Width);
    141.                 ExitPoint = Vector3.zero;
    142.                 EntryPoint = Vector3.zero;
    143.                
    144.                 OnBackHit(hit2); // send rear impact and check what to do with it
    145.         }
    146.        
    147.     velocity.y -= Gravity * Time.deltaTime;
    148.     Rotation.transform.rotation = Quaternion.LookRotation(dir);
    149.    
    150. }
    151.  
    152. function OnHit(hit : RaycastHit){
    153.  
    154.     hitCount++; // add another hit to counter
    155.     var contact : Vector3 = hit.point;     // point where bullet hit
    156.     var rotation : Quaternion = Quaternion.FromToRotation(Vector3.up, hit.normal); // rotation of bullet impact
    157.     var direction2 = gameObject.transform.TransformDirection(Vector3(Random.Range(-0.01, 0.01) * spread, Random.Range(-0.01, 0.01) * spread, 1));
    158.    
    159.     var hitHeight : float = 0.008;
    160.    
    161.     endPos = transform.position;
    162.     distance = Vector3.Distance(startPos, endPos);
    163.     DamageDropoff = distance / 10;
    164.     RawDamage = damage - DamageDropoff;
    165.     FinalDamage = Mathf.Round(RawDamage);
    166.    
    167.     if(FinalDamage < 10){
    168.     FinalDamage = 10;
    169.     }
    170.    
    171.     if (hit.rigidbody)
    172.     hit.rigidbody.AddForceAtPosition(force * direction2, hit.point);
    173.    
    174.     hit.collider.SendMessageUpwards("ApplyDamage", FinalDamage, SendMessageOptions.DontRequireReceiver);
    175.     hit.collider.SendMessageUpwards("PlayerDamage", FinalDamage, SendMessageOptions.DontRequireReceiver);
    176.    
    177.        
    178.     if (hit.transform.tag == "Untagged" && Untagged != null) {
    179.         var untaggedHole : GameObject = Instantiate(Untagged, hit.point, rotation) as GameObject;
    180.         untaggedHole.transform.localPosition += hitHeight * hit.normal;
    181.         untaggedHole.transform.parent = hit.transform;
    182.     }
    183.    
    184.     if (hit.transform.tag == "Concrete" && Concrete != null) {
    185.         var concreteHole : GameObject = Instantiate (Concrete, hit.point, rotation) as GameObject;
    186.         concreteHole.transform.localPosition += hitHeight * hit.normal;
    187.         concreteHole.transform.parent = hit.transform;
    188.     }
    189.    
    190.     if (hit.transform.tag == "Wood" && Wood != null) {
    191.         var woodHole = Instantiate (Wood, hit.point, rotation) as GameObject;
    192.         woodHole.transform.localPosition += hitHeight * hit.normal;
    193.         woodHole.transform.parent = hit.transform;
    194.     }
    195.    
    196.     if (hit.transform.tag == "Metal" && Metal != null) {
    197.         var metalHole = Instantiate (Metal, hit.point, rotation) as GameObject;
    198.         metalHole.transform.localPosition += hitHeight * hit.normal;
    199.         metalHole.transform.parent = hit.transform;
    200.     }
    201.        
    202.     if (hit.transform.tag == "Enemy" && Blood != null) {
    203.         var bloodHole = Instantiate (Blood, hit.point, rotation) as GameObject;
    204.         bloodHole.transform.localPosition += hitHeight * hit.normal;
    205.         bloodHole.transform.parent = hit.transform;
    206.         return;
    207.     }
    208.    
    209.     if (hit.transform.tag == "Player" && Blood != null) {
    210.         var playerHole = Instantiate (Blood, hit.point, rotation) as GameObject;
    211.         playerHole.transform.localPosition += hitHeight * hit.normal;
    212.         playerHole.transform.parent = hit.transform;
    213.         return;
    214.     }
    215.    
    216.     if (hit.transform.tag == "Snow" && Snow != null) {
    217.         var snowHole = Instantiate (Snow, hit.point, rotation) as GameObject;
    218.         snowHole.transform.localPosition += hitHeight * hit.normal;
    219.         snowHole.transform.parent = hit.transform;
    220.     }
    221.    
    222.     if (hit.transform.tag == "Dirt" || hit.transform.tag == "Grass"|| hit.transform.tag == "Sand" && Dirt != null) {
    223.         var dirtHole = Instantiate (Dirt, hit.point, rotation) as GameObject;
    224.         dirtHole.transform.localPosition += hitHeight * hit.normal;
    225.         dirtHole.transform.parent = hit.transform;
    226.     }
    227.    
    228.     if (hit.transform.tag == "Water" && Water != null) {
    229.         var waterHole = Instantiate (Water, hit.point, rotation) as GameObject;
    230.         waterHole.transform.localPosition += hitHeight * hit.normal;
    231.         waterHole.transform.parent = hit.transform;
    232.     }
    233.    
    234.     if (hit.transform.tag == "Glass" && Glass != null) {
    235.         var glassHole = Instantiate (Glass, hit.point, rotation) as GameObject;
    236.         glassHole.transform.localPosition += hitHeight * hit.normal;
    237.         glassHole.transform.parent = hit.transform;
    238.     }
    239.    
    240.     if(debugDamage){
    241.         Debug.Log("Start Damage: " + damage);
    242.         Debug.Log("Hit Distance: " + distance);
    243.         Debug.Log("Damage Drop-Off: " + DamageDropoff);
    244.         Debug.Log("Raw Damage: " + RawDamage);
    245.         Debug.Log("Current Damage is : " + FinalDamage);
    246.     }
    247. }
    248.  
    249. function OnBackHit(hit : RaycastHit){
    250.     var contact : Vector3 = hit.point;     // point where bullet hit
    251.     var rotation : Quaternion = Quaternion.FromToRotation(Vector3.up, hit.normal); // rotation of bullet impact
    252.     var hitHeight : float = 0.008;
    253.     width = 0;
    254.    
    255.         //if(Width > MaximumPenetration){
    256.         //Destroy(gameObject);
    257.         //return;
    258.         //}
    259.    
    260.     if (hit.transform.tag == "Untagged" && Untagged != null) {
    261.         var untaggedHole : GameObject = Instantiate(Untagged, hit.point, rotation) as GameObject;
    262.         untaggedHole.transform.localPosition += hitHeight * hit.normal;
    263.         untaggedHole.transform.parent = hit.transform;
    264.     }
    265.    
    266.     if (hit.transform.tag == "Concrete" && Concrete != null) {
    267.         var concreteHole : GameObject = Instantiate (Concrete, hit.point, rotation) as GameObject;
    268.         concreteHole.transform.localPosition += hitHeight * hit.normal;
    269.         concreteHole.transform.parent = hit.transform;
    270.     }
    271.    
    272.     if (hit.transform.tag == "Wood" && Wood != null) {
    273.         var woodHole = Instantiate (Wood, hit.point, rotation) as GameObject;
    274.         woodHole.transform.localPosition += hitHeight * hit.normal;
    275.         woodHole.transform.parent = hit.transform;
    276.     }
    277.    
    278.     if (hit.transform.tag == "Metal" && Metal != null) {
    279.         var metalHole = Instantiate (Metal, hit.point, rotation) as GameObject;
    280.         metalHole.transform.localPosition += hitHeight * hit.normal;
    281.         metalHole.transform.parent = hit.transform;
    282.     }
    283.        
    284.     if (hit.transform.tag == "Enemy" && Blood != null) {
    285.         var bloodHole = Instantiate (Blood, hit.point, rotation) as GameObject;
    286.         bloodHole.transform.localPosition += hitHeight * hit.normal;
    287.         bloodHole.transform.parent = hit.transform;
    288.     }
    289.    
    290.     if (hit.transform.tag == "Dirt" || hit.transform.tag == "Grass" && Dirt != null) {
    291.         var dirtHole = Instantiate (Dirt, hit.point, rotation) as GameObject;
    292.         dirtHole.transform.localPosition += hitHeight * hit.normal;
    293.         dirtHole.transform.parent = hit.transform;
    294.     }
    295.    
    296.     if (hit.transform.tag == "Glass" && Glass != null) {
    297.         var glassHole = Instantiate (Glass, hit.point, rotation) as GameObject;
    298.         glassHole.transform.localPosition += hitHeight * hit.normal;
    299.         glassHole.transform.parent = hit.transform;
    300.     }
    301. }
    302.  
    303.  
    304.  
    The specific bit of the code that handles registering the bullet exit hole:
    Code (JavaScript):
    1.     if (Physics.Raycast(newPos + (newPos - oldPos), back, hit2, dist)) {    // send a ray behind the bullet to check for exit impact  
    2.                 ExitPoint = hit2.point;
    3.                 Width = Vector3.Distance(EntryPoint, ExitPoint);
    4.                 Debug.Log("Width is: " + Width);
    5.                 ExitPoint = Vector3.zero;
    6.                 EntryPoint = Vector3.zero;
    7.                
    8.                 OnBackHit(hit2); // send rear impact and check what to do with it
    9.         }
    10.        
    So the actual problem is that it doesn't leave an exit hole on the first object or an entrance hole on the second, I'm assuming that this is because the bullet is moving to quick for the code to keep up. But that seems bizzare to me.

    Anyway any help would be much appreciated.

    Thanks - Aiden Leeming
     
  2. RJ-MacReady

    RJ-MacReady

    Joined:
    Jun 14, 2013
    Posts:
    1,718
    Tip #1 - Don't post 300 lines of code and then go grab a coke, expecting your problem to be solved when you get back. Without even looking at it, are you using Physics.RaycastAll?

    Because a Physics.Raycast is only going to retrieve the first hit. You must also understand that there are instances that a Physics.Raycast will NOT register a hit, it must pass through a mesh perpendicularly AND it must pass through the mesh from outside-in, you can't get a Hit from the back side of a mesh.You'd do well to actually fire a RaycastAll in the bullet firing direction and then from the stop point of the RaycastHit back toward the origin point.

    Good luck. :)

    I just saw your picture. But, here's the concept that comes to my mind. We need to fire a RaycastAll to get every hit. Wherever there's a hit, leave a bullet hole. The rest is just a matter of refinement.
     
    Last edited: Oct 26, 2014
  3. Aidenjl

    Aidenjl

    Joined:
    Jan 5, 2014
    Posts:
    81
    Thank you very much, the RaycastAll is working.

    Sorry for all of the lines of code though.