How to create detonation time for grenade projectile.

Hello everyone, I have problems with setting the time of detonation and destruction of the grenade projectile. Since the enemy creates grenades with a cooldown that is shorter than the detonation time, as you might guess, the next instance of the projectile will set the default detonation time. Luckily, I was able to fix this problem by setting the detonation time in the launch function, but with this approach, when the detonation time reaches 0, only the last grenade created will be destroyed. Any help is appreciated! Code, it’s a little messy, but you need the start and fixUpdate functions:

private AttackDetails attackDetails;
     public GameObject player;
     [Tooltip("Position we want to hit")]
     public Vector3 targetPos;
    
     [Tooltip("Horizontal speed, in units/sec")]
     public float speed = 25;
    
     [Tooltip("How high the arc should be, in units")]
     public float arcHeight = 6;
     private Vector3 nextPos;
     PlayerMovement playerMovement;
     Rigidbody2D rb;
     private bool arrowHitPlayerPos = false;
     Vector3 startPos;
     private bool hasHitGround;
     Vector2 velocityVector;
     [SerializeField]
     private LayerMask whatIsGround;
     [SerializeField]
     private LayerMask whatIsPlayer;
     [SerializeField]
     private Transform damagePosition;
     [SerializeField]
     private float damageRadius;
     private float timeOfDetonation = 3;
     private float explosionRadius = 2;
     Collider2D damageHit;
     void Start() {
         // Cache our start position, which is really the only thing we need
         // (in addition to our current position, and the target).
         startPos = transform.position;
         playerMovement = FindObjectOfType<PlayerMovement>();
         rb = GetComponent<Rigidbody2D>();
         targetPos = playerMovement.groundPlayerPosVector;
         timeOfDetonation = 3;
         Debug.Log(timeOfDetonation);
        
     }
    
     void Update() {
         // Compute the next position, with arc added in
        
         Debug.Log(timeOfDetonation);
         float x0 = startPos.x;
         float x1 = targetPos.x;
         float dist = x1 - x0;
         float nextX = Mathf.MoveTowards(transform.position.x, x1, speed * Time.deltaTime);
         float baseY = Mathf.Lerp(startPos.y, targetPos.y, (nextX - x0) / dist);
         float arc = arcHeight * (nextX - x0) * (nextX - x1) / (-0.25f * dist * dist);
         nextPos = new Vector3(nextX, baseY + arc, transform.position.z);
         velocityVector = nextPos - transform.position;
         timeOfDetonation -= Time.deltaTime;
        
        
         // Rotate to face the next position, and then move there
         transform.rotation = LookAt2D(nextPos - transform.position);
         if(hasHitGround != true || rb.velocity.y <=0)
         rb.velocity = velocityVector * speed;
        
     }
     private void FixedUpdate()
     {
         if (!hasHitGround)
         {
             if(timeOfDetonation <=0)
             {
                 Collider2D damageHit = Physics2D.OverlapCircle(damagePosition.position, explosionRadius, whatIsPlayer);
                 Destroy(gameObject);
             }
            
             Collider2D groundHit = Physics2D.OverlapCircle(damagePosition.position, damageRadius, whatIsGround);
             if (damageHit)
             {
                 damageHit.transform.SendMessage("Damage", attackDetails);
                
             }
             if (groundHit)
             {
                 hasHitGround = true;
             }
         }       
     }
    
      private void OnDrawGizmos()
     {
         Gizmos.DrawWireSphere(damagePosition.position, damageRadius);
         Gizmos.DrawWireSphere(damagePosition.position, explosionRadius);
     }
     ///
     /// This is a 2D version of Quaternion.LookAt; it returns a quaternion
     /// that makes the local +X axis point in the given forward direction.
     ///
     /// forward direction
     /// Quaternion that rotates +X to align with forward
     static Quaternion LookAt2D(Vector2 forward) {
         return Quaternion.Euler(0, 0, Mathf.Atan2(forward.y, forward.x) * Mathf.Rad2Deg);
     }

I apologize but maybe i am not quite understanding properly. I think your problem is: The enemy throws a few grenades, but only the last one explodes/gets destroyed when the detonation hits 0, is this correct?

I think you get it right.

So you code is a bit messy, but i cannot seem to find out why only one grenade explodes and not the others. My suggestion is to break these things out and add Debug.Logs to them. So part of this is to start practicing clean code: What Is Clean Code?. Lessons learned from the bible of… | by Severin Perez | Medium

There are many benefits but i think the best one that applies here is so you can Debug each part of the code so you can more accurately find out what is going wrong. One of the principles is to encapsulate each part of the code to its own function, aka, Make a clearly name function that only handles what it is supposed to. All of your math happening in Update, I would throw that into a function at the bottom called CalculateVelocity or something. Then, call that CalculateVelocity in Update instead. Throw a Debug.Log in CalculateVelocity so you know it is being called.

void Update() {
         // Compute the next position, with arc added in
      
         Debug.Log(timeOfDetonation);
         CalculateVelocity();
         timeOfDetonation -= Time.deltaTime;
      
      
         // Rotate to face the next position, and then move there
         transform.rotation = LookAt2D(nextPos - transform.position);
         if(hasHitGround != true || rb.velocity.y <=0)
         rb.velocity = velocityVector * speed;
      
     }

void CalculateVelocity()
{
float x0 = startPos.x;
         float x1 = targetPos.x;
         float dist = x1 - x0;
         float nextX = Mathf.MoveTowards(transform.position.x, x1, speed * Time.deltaTime);
         float baseY = Mathf.Lerp(startPos.y, targetPos.y, (nextX - x0) / dist);
         float arc = arcHeight * (nextX - x0) * (nextX - x1) / (-0.25f * dist * dist);
         nextPos = new Vector3(nextX, baseY + arc, transform.position.z);
         velocityVector = nextPos - transform.position;


}

For your If functions in FixedUpdate, you dont need to put them into their own function since they are 2 lines or less, but throw in some Debug.Logs in each If bracket to see if they get called.

If that still doesnt help you find what is going wrong, I would separate this script into another one that handles the detonationTimer. Just have a small script that sets the timer variable to 3, counts down with Time.deltaTime and when it hits 0 or less, destroy.

Hopefully this helps you get an idea of what i am trying to assist with. It make take a bit longer up front typing out multiple scripts, but it will saves you waaaay more time later when you are debugging.

1 Like

Thanks for your help, I also like to keep the code clean, but sometimes everything falls by their hands and you have to try many different options to solve the problem in the code, because of which the code becomes a bit messy.

1 Like