Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question After a certain amount of time raycast ignores a hit with an enemy

Discussion in 'Physics' started by Polarfist1, Sep 12, 2021.

  1. Polarfist1

    Polarfist1

    Joined:
    Aug 16, 2021
    Posts:
    15
    I have a game with a gun, which activates a raycast to detect collisions whilst firing. If the raycast collides with an enemy transform , the enemy will take 10 damage (enemy has 100 base health) until it gets destroyed after around ten hits..

    Once I was play-testing, and a sum of time passed since the first enemies spawned, I realised that the raycast started to ignore detecting those enemy and detected the ground instead in the console menu (basically the raycast went straight through the enemy and detected the ground).

    Im not sure why the raycast is going straight through the enemy transform and is stopping at the ground instead, especially when this behaviour only happens after around 8 seconds. Does anybody know why this happens?

    Plus, this only started happening once I gave the enemies a script and NavMesh Agent to give them AI to follow the player's cylinder position, so that might be linked to this problem.

    This is the gun and enemy damage code (from a tutorial):

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Gun : MonoBehaviour
    4. {
    5.     public float damage = 10f;
    6.     public float range = 100f;
    7.     public float fireRate = 15f;
    8.  
    9.     public Camera fpsCam;
    10.     public ParticleSystem muzzleFlash;
    11.  
    12.     private float nextTimeToFire = 0f;
    13.  
    14.     // Update is called once per frame
    15.     void Update()
    16.     {
    17.         if(Input.GetButton("Fire1") && Time.time >= nextTimeToFire)
    18.         {
    19.             nextTimeToFire = Time.time + 1f / fireRate;
    20.             Shoot();
    21.         }
    22.     }
    23.  
    24.     void Shoot ()
    25.     {
    26.         muzzleFlash.Play();
    27.  
    28.         RaycastHit hit;
    29.         if (Physics.Raycast(fpsCam.transform.position, fpsCam.transform.forward, out hit, range))
    30.         {
    31.             Debug.Log(hit.transform.name);
    32.  
    33.             Enemy enemy = hit.transform.GetComponent<Enemy>();
    34.             if(enemy != null)
    35.             {
    36.                 enemy.TakeDamage(damage);
    37.             }
    38.         }
    39.     }
    40. }
    The Enemy enemy = hit transform.GetComponent part of the code is getting the script I believe from the actual enemy (The Enemy's script is called Enemy).

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Enemy : MonoBehaviour
    4. {
    5.     public float health = 100f;
    6.  
    7.     public void TakeDamage (float amount)
    8.     {
    9.         health -= amount;
    10.         if (health <= 0f)
    11.         {
    12.             Die();
    13.         }
    14.     }
    15.  
    16.     void Die ()
    17.     {
    18.         Destroy(gameObject);
    19.     }
    20.  
    21.     private void OnCollisionEnter(Collision collision)
    22.     {
    23.         if(collision.gameObject.tag == "Player")
    24.         {
    25.             Destroy(collision.gameObject);
    26.         }
    27.     }
    28.  
    29. }
    30.  
    This is also the EnemyFollow code just incase it is needed;

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.AI;
    5. public class EnemyFollow : MonoBehaviour
    6. {
    7.     public NavMeshAgent enemyAI;
    8.  
    9.     // Start is called before the first frame update
    10.     void Start()
    11.     {
    12.      
    13.     }
    14.  
    15.     // Update is called once per frame
    16.     void Update()
    17.     {
    18.         enemyAI.SetDestination(GameObject.Find("Cylinder").transform.position);
    19.     }
    20. }
    21.  
     
  2. Polarfist1

    Polarfist1

    Joined:
    Aug 16, 2021
    Posts:
    15
    Nevermind, I fixed this by turing is Kinematic on for the enemies.
     
  3. Peeling

    Peeling

    Joined:
    Nov 10, 2013
    Posts:
    404
    For anyone curious: The reason for this happening is that there is nothing physical to stop the rigidbodies accelerating under gravity, but the navigation system keeps forcing the position of the enemy back to the surface. This means that at first, the update loop does this:

    Enemy: <doesn't move>
    Raycast: <works>
    Navmesh: <forces enemy to surface>

    Enemy: <moves down a little>
    Raycast: <works>
    Navmesh: <forces enemy to surface>

    Enemy: <moves down a little more, since it's still accelerating under gravity>
    Raycast: <works>
    Navmesh: <forces enemy to surface>

    But after a while:

    Enemy: <moves down more than its own height in a single frame>
    Raycast: <misses>
    Navmesh: <forces enemy to surface>

    Enemy: <moves down more than its own height in a single frame>
    Raycast: <misses>
    Navmesh: <forces enemy to surface>

    So you never see the enemy falling, but the physics constantly misses.