Search Unity

OnCollisionEnter2D is destroying my game objects and I cannot figure out why?!

Discussion in '2D' started by jleven22, Jul 15, 2019.

  1. jleven22

    jleven22

    Joined:
    Mar 26, 2019
    Posts:
    421
    I started setting up my health system today, but I've encountered an interesting issue.

    To be clear, no error codes or anything. Just a seemingly random event.

    When my player touches an enemy, the enemy game object is destroyed. I've tried debugging a little but cannot find the issue. So I'm here hoping someone can tell me wth I'm doing wrong.

    Player health script:
    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. public class PlayerHealthManager : MonoBehaviour
    6. {
    7.     public int playerMaxHealth;
    8.     public int playerCurrentHealth;
    9.     // Start is called before the first frame update
    10.     void Start()
    11.     {
    12.         playerCurrentHealth = playerMaxHealth;
    13.     }
    14.     // Update is called once per frame
    15.     void Update()
    16.     {
    17.         if(playerCurrentHealth <= 0)
    18.         {
    19.             gameObject.SetActive(false);
    20.         }
    21.     }
    22.    
    23.     public void HurtPlayer(int damageToDeal)
    24.     {
    25.         playerCurrentHealth -= damageToDeal;
    26.     }
    27.     public void SetMaxHealth()
    28.     {
    29.         playerCurrentHealth = playerMaxHealth;
    30.     }
    31. }
    32.  

    Enemy damage script:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class HurtPlayer : MonoBehaviour
    6. {
    7.  
    8.     public int damageToDeal;
    9.  
    10.     // Start is called before the first frame update
    11.     void Start()
    12.     {
    13.        
    14.     }
    15.  
    16.     // Update is called once per frame
    17.     void Update()
    18.     {
    19.        
    20.     }
    21.  
    22.     void OnCollisionEnter2D(Collision2D other)
    23.     {
    24.         if (other.gameObject.tag == "Player")
    25.         {
    26.             if (other != null)
    27.             {
    28.  
    29.                 Debug.Log("Hurt player");
    30.                 other.gameObject.GetComponent<PlayerHealthManager>().HurtPlayer(damageToDeal);
    31.             }
    32.         }
    33.     }
    So um... what?
     
  2. MSplitz-PsychoK

    MSplitz-PsychoK

    Joined:
    May 16, 2015
    Posts:
    1,278
    Nothing should be getting destroyed if you don't call Destroy() or unload any scenes.

    Are you sure they're actually getting destroyed? Maybe the physics pushes one of the objects out of the camera's view? Maybe you could try putting a breakpoint inside an "OnDisable" function to get a look at the call stack if they are actually getting destroyed.
     
  3. jleven22

    jleven22

    Joined:
    Mar 26, 2019
    Posts:
    421
    You might have to help me understand how to put a breakpoint in a function like that...

    However, I went ahead and disabled both the above scripts, nothing changed. I went ahead and disabled the enemy movement script, commented out anything that could possibly be applicable in the player script, nothing changed.

    So far the only thing that seems to work slightly is decreasing the radius on the enemy collider2D. I've got it set up so that the game pauses if collision is made, and if the player approaches VERY slowly, the game pauses. Any speed higher than that, the enemy game object is deleted from the hierarchy.

    Now I'm at a complete loss because I've sifted through all code. Anything else this could be?
     
  4. jleven22

    jleven22

    Joined:
    Mar 26, 2019
    Posts:
    421
    So I have gone through everything... and I mean EVERYTHING. I have removed and re-added components & scripts. I have recreated prefabs. I can only isolate it to one thing:

    If my enemy has a collider on it, and the player touches it, it is completely removed from the hierarchy and the game (until reset).

    Here's the thing though... removing the collider on the player does not affect this. The enemy game object is still deleted. Only removing the enemy collider does keeps this from happening, but I need the colliders on the enemies for obvious reasons.

    I'm going to add my player script here for reference, but the fact is that I have changed nothing on this script in weeks, so I cannot figure out why this would be happening.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Rewired;
    5.  
    6.  
    7.  
    8.  
    9. public class BitchFaceController : MonoBehaviour
    10. {
    11.  
    12.     public int playerId = 0;
    13.     private Player player;
    14.     public bool useController;
    15.     public Rigidbody2D rb;
    16.     public GameObject arrowPrefab;
    17.  
    18.     //Animations
    19.     public Animator topAnimator;
    20.     public Animator bottomAnimator;
    21.     public GameObject crossHair;
    22.  
    23.     //Movement and Aiming
    24.     Vector2 movement;
    25.     Vector2 aim;
    26.     private float lastDirX;
    27.     private float lastDirY;
    28.     private float currDirX;
    29.     private float currDirY;
    30.     bool isAiming;
    31.     bool endAiming;
    32.     public float speed;
    33.     public float arrowSpeed;
    34.  
    35.     //LERP Dodge Roll
    36.     public bool isDodging;
    37.     private float fracJourney;
    38.     public Vector2 startMarker;
    39.     public Vector2 endMarker;
    40.     public float dodgeSpeed;
    41.     public float dodgeDistance;
    42.     public float animationSpeed;
    43.  
    44.     //Combat System
    45.     public static int health;
    46.  
    47.  
    48.  
    49.  
    50.     private void Awake()
    51.     {
    52.         Debug.Log("PlayerId is " + playerId.ToString());
    53.         player = ReInput.players.GetPlayer(playerId);
    54.  
    55.         Cursor.lockState = CursorLockMode.Locked;
    56.         Cursor.visible = false;
    57.     }
    58.  
    59.     private void Start()
    60.     {
    61.         rb = this.GetComponent<Rigidbody2D>();
    62.         arrowSpeed = 3;
    63.         health = 3;
    64.     }
    65.  
    66.     // Update is called once per frame
    67.     void Update()
    68.     {
    69.         ProcessInputs();
    70.         AimAndShoot();
    71.         Animate();
    72.     }
    73.  
    74.     private void FixedUpdate()
    75.     {
    76.         Move();
    77.         Dodge();
    78.     }
    79.    
    80.  
    81.     //Moving
    82.     private void Move()
    83.     {
    84.         //transform.position = transform.position + movement * speed * Time.deltaTime;
    85.         rb.MovePosition(rb.position + (movement * speed * Time.fixedDeltaTime));
    86.         rb.velocity = new Vector2(movement.x, movement.y);
    87.     }
    88.  
    89.  
    90.     //Dodging
    91.     private void Dodge()
    92.     {
    93.         if (!isDodging && Input.GetKey(KeyCode.Space) && (rb.velocity.x != 0 || rb.velocity.y != 0))
    94.         {
    95.             isDodging = true;
    96.             fracJourney = 0;
    97.    
    98.             //startMarker = transform.position;
    99.             startMarker = rb.position;
    100.             endMarker = rb.position + movement * dodgeDistance;
    101.             //endMarker = rb.MovePosition(rb.position + (movement * dodgeDistance));
    102.  
    103.             topAnimator.SetBool("Dodge", true);
    104.         }
    105.  
    106.         if (isDodging)
    107.         {
    108.             fracJourney = fracJourney + Time.deltaTime * dodgeSpeed;
    109.            
    110.  
    111.             if (fracJourney > 1)
    112.             {
    113.                 fracJourney = 1;
    114.                 isDodging = false;
    115.  
    116.                 topAnimator.SetBool("Dodge", false);
    117.                 //this.Archer_Bottom.enabled = true;
    118.             }
    119.  
    120.             rb.MovePosition(Vector2.Lerp(startMarker, endMarker, fracJourney));
    121.         }  
    122.     }
    123.  
    124.     //Processing Inputs, Aiming, and Walk Animation
    125.     private void ProcessInputs()
    126.     {
    127.         //if (useController)
    128.         //{
    129.         //    movement = new Vector2(Input.GetAxis("MoveHorizontal"), Input.GetAxis("MoveVertical"));
    130.         //    aim = new Vector2(player.GetAxis("AimHorizontal"), player.GetAxis("AimVertical"));
    131.         //    aim.Normalize();
    132.         //    isAiming = player.GetButton("Fire");
    133.         //    endAiming = player.GetButtonUp("Fire");
    134.         //    //isDodging = player.GetButton("Dodge");
    135.         //}
    136.         //else
    137.         //{
    138.             movement = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
    139.             Vector2 mouseMovement = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
    140.             aim = aim + mouseMovement;
    141.             if (aim.magnitude > 1.0f)
    142.             {
    143.                 aim.Normalize();
    144.             }
    145.             isAiming = Input.GetButton("Fire1");
    146.             endAiming = Input.GetButtonUp("Fire1");
    147.         //}
    148.  
    149.  
    150.         if (movement.magnitude > 1.0f)
    151.         {
    152.             movement.Normalize();
    153.         }
    154.  
    155.         //Set direction parameters for moving and idling
    156.         if (Input.GetKey(KeyCode.W))
    157.         {
    158.             currDirX = 0;
    159.             currDirY = 1;
    160.             lastDirX = 0;
    161.             lastDirY = 1;
    162.         }
    163.         else if (Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.A))
    164.         {
    165.             currDirX = -1;
    166.             currDirY = 1;
    167.         }
    168.         else if (Input.GetKey(KeyCode.A))
    169.         {
    170.             currDirX = -1;
    171.             currDirY = 0;
    172.             lastDirX = -1;
    173.             lastDirY = 0;
    174.         }
    175.         else if (Input.GetKey(KeyCode.A) && Input.GetKey(KeyCode.S))
    176.         {
    177.             currDirX = -1;
    178.             currDirY = -1;
    179.         }
    180.         else if (Input.GetKey(KeyCode.S))
    181.         {
    182.             currDirX = 0;
    183.             currDirY = -1;
    184.             lastDirX = 0;
    185.             lastDirY = -1;
    186.         }
    187.         else if (Input.GetKey(KeyCode.S) && Input.GetKey(KeyCode.D))
    188.         {
    189.             currDirX = 1;
    190.             currDirY = -1;
    191.         }
    192.         else if (Input.GetKey(KeyCode.D))
    193.         {
    194.             currDirX = 1;
    195.             currDirY = 0;
    196.             lastDirX = 1;
    197.             lastDirY = 0;
    198.         }
    199.         else if (Input.GetKey(KeyCode.D) && Input.GetKey(KeyCode.W))
    200.         {
    201.             currDirX = 1;
    202.             currDirY = 1;
    203.         };
    204.    
    205.  
    206.     }
    207.  
    208.  
    209.  
    210.  
    211.     private void Animate()
    212.     {
    213.         //Moving Legs
    214.         bottomAnimator.SetFloat("MoveHorizontal", movement.x);
    215.         bottomAnimator.SetFloat("MoveVertical", movement.y);
    216.         bottomAnimator.SetFloat("MoveMagnitude", movement.magnitude);
    217.  
    218.         //Moving Body
    219.         topAnimator.SetFloat("MoveHorizontal", currDirX);
    220.         topAnimator.SetFloat("MoveVertical", currDirY);
    221.         topAnimator.SetFloat("MoveMagnitude", movement.magnitude);
    222.  
    223.         //Aiming
    224.         topAnimator.SetFloat("AimHorizontal", aim.x);
    225.         topAnimator.SetFloat("AimVertical", aim.y);
    226.         topAnimator.SetFloat("AimMagnitude", aim.magnitude);
    227.         topAnimator.SetBool("Aim", isAiming);
    228.  
    229.         //Idle Direction
    230.         topAnimator.SetFloat("LastMoveX", lastDirX);
    231.         topAnimator.SetFloat("LastMoveY", lastDirY);
    232.     }
    233.  
    234.     private void AimAndShoot()
    235.     {
    236.         Vector2 shootingDirection = new Vector2(aim.x, aim.y);
    237.  
    238.         if (aim.magnitude > 0.0f)
    239.         {
    240.             crossHair.transform.localPosition = aim * 0.4f;
    241.             crossHair.SetActive(true);
    242.  
    243.             shootingDirection.Normalize();
    244.             if (endAiming)
    245.             {
    246.                 GameObject arrow = Instantiate(arrowPrefab, transform.position, Quaternion.identity);
    247.                 Arrow1 arrow1Script = arrow.GetComponent<Arrow1>();
    248.                 arrow1Script.velocity = shootingDirection * arrowSpeed;
    249.                 arrow1Script.player = gameObject;
    250.                 arrow.transform.Rotate(0.0f, 0.0f, Mathf.Atan2(shootingDirection.y, shootingDirection.x) * Mathf.Rad2Deg);
    251.                 Destroy(arrow, 1.0f);
    252.             }
    253.         }
    254.         else
    255.         {
    256.             crossHair.SetActive(false);
    257.         }
    258.     }
     
  5. MSplitz-PsychoK

    MSplitz-PsychoK

    Joined:
    May 16, 2015
    Posts:
    1,278
    This all seems very strange. Nothing should be able to get destroyed without calling "Destroy" in code or unloading the scene. Try doing a ctrl+shift+f to "find all" and search for the word "Destroy".

    In your enemy script, add the following code:
    Code (CSharp):
    1. void OnDisable()
    2. {
    3.     int i = 0;
    4. }
    After that, just put a breakpoint on the line
    int i = 0;
    . Run the game with the debugger attached, then when your enemy automatically gets destroyed, the game should pause and your code editor should highlight the line of code and show you a call stack, which is the list of functions that were called to get the that line of code.

    If you're unfamiliar with breakpoints and still don't understand, here is a manual page about it. The most useful section is the "Debugging in the Editor" section. https://docs.unity3d.com/Manual/ManagedCodeDebugging.html
     
  6. jleven22

    jleven22

    Joined:
    Mar 26, 2019
    Posts:
    421
    So I got some great advice on Reddit from user AverageArmadillo that I wanted to share and solved my issue.

    "If you are using VS hit control + shift + F and under the search function change current document to entire solution to search your entire game solution. Look for Destroy.

    Something... somewhere is making a call to destroy on collision. Remember that even inactive game objects with colliders can call collision on triggers. So if your player has some form of projectile they fire (I see an arrow in your scripts) if that arrow is not active in the hierarchy but present then it's trigger can still get fired. There is a chance that is happening.

    I see it too in my game when bullets disabled still cause damage to enemies. The solution to that if it is the case was to add a check if object is active in hierarchy to the collision actions."

    Turns out it was an issue with an old script in my archive folder that was calling a similar function to my new "hurt player" script.