- Home /
I'm working on a tower defense game and my "enemy" game object is losing health before my "projectile" hits the box collider
In my tower defense game I have a turret that spawns a projectile that heads towards an game object with the tag "Enemy" when said enemy game object is in range of the turret but for some reason my enemy health will decrease before my projectile will hit the enemy collider I'm not to sure where my mistake is can someone tell me how I can fix this problem. I should mention that my enemy game object has a box collider and my projectile game object does not.
this is my projectile script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Projectile : MonoBehaviour
{
private Transform target;
public float speed = 70f;
public GameObject impactEffect;
public int damage = 10;
public float explosionRadius = 0f;
public void Seek(Transform _target)
{
target = _target;
}
// Update is called once per frame
void Update()
{
if (target == null)
{
Destroy(gameObject);
return;
}
Vector3 dir = target.position - transform.position;
float distanceThisFrame = speed * Time.deltaTime;
if (dir.magnitude <= distanceThisFrame)
{
HitTarget();
return;
}
transform.Translate(dir.normalized * distanceThisFrame, Space.World);
transform.LookAt(target);
}
void HitTarget()
{
GameObject effectIns = (GameObject)Instantiate(impactEffect, transform.position, transform.rotation);
Destroy(effectIns, 5f);
if(explosionRadius > 0f)
{
Explode();
}
else
{
Damage(target);
Destroy(effectIns);
}
}
void Explode()
{
Collider[] colliders = Physics.OverlapSphere(transform.position, explosionRadius);
foreach(Collider collider in colliders)
{
if(collider.tag == "Enemy")
{
Damage(collider.transform);
}
}
}
void Damage(Transform enemy)
{
Enemy e = enemy.GetComponent<Enemy>();
if(e != null)
{
e.TakeDamage(damage);
}
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, explosionRadius);
}
}
and this is my enemy script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Enemy : MonoBehaviour
{
public float startSpeed = 10f;
public float speed;
public float startHealth = 200f;
private float health;
public int moneyEarned = 10;
public GameObject deathEffect;
[Header("Health Bar")]
public Image healthBar;
void Start()
{
health = startHealth;
speed = startSpeed;
}
//enemy damage
public void TakeDamage(float amount)
{
health -= amount;
healthBar.fillAmount = health / startHealth;
if (health <= 0)
{
Die();
}
}
public void Slow (float pct)
{
speed = startSpeed * (1 - pct);
}
void Die()
{
GameObject audioManagerObject = GameObject.Find("AudioManager");
AudioManager audioManagerScript = audioManagerObject.GetComponent<AudioManager>();
audioManagerScript.PlayEnemyDeath();
//Enemy prefab >> Death effect >> plug in death effect
GameObject effect = Instantiate(deathEffect, transform.position, Quaternion.identity);
Destroy(effect, 1f);
PlayerStats.Money += moneyEarned;
WaveSpawner.EnemiesAlive--;
Destroy(gameObject);
}
}
Answer by icehex · May 05, 2020 at 07:08 PM
Could it be here?
if (dir.magnitude <= distanceThisFrame)
{
HitTarget();
return;
}
You call HitTarget before you update the projectile's position below that part. It's still in 1 frame so that should be not noticeable... but just to check you could try changing to:
void Update()
{
if (target == null)
{
Destroy(gameObject);
return;
}
Vector3 dir = target.position - transform.position;
float distanceThisFrame = speed * Time.deltaTime;
transform.Translate(dir.normalized * distanceThisFrame, Space.World);
transform.LookAt(target);
if (dir.magnitude <= distanceThisFrame)
{
HitTarget();
return;
}
}
To have your projectile be destroyed, it needs a call for Destroy on itself once it applies damage. This here should do it, or get you close:
void Damage(Transform enemy)
{
Enemy e = enemy.GetComponent<Enemy>();
if(e != null)
{
e.TakeDamage(damage);
Destroy(gameObject);
}
}
Also if you do the above, you need to correct your HitTarget function so the effect is Destroyed before your projectile destroys itself ---
void HitTarget()
{
GameObject effectIns = (GameObject)Instantiate(impactEffect, transform.position, transform.rotation);
Destroy(effectIns, 5f);
if(explosionRadius > 0f)
{
Explode();
}
else
{
Destroy(effectIns);
Damage(target);
}
}
Also the script only looks at the collider if explosionRadius is greater than zero. Otherwise it considers the enemy to be hit if the enemy's position is within the projectile's reach this frame. if you want to use collision, you'll need to take out the dir.magnitude
void OnCollisionEnter(Collision collision)
{
if (collision.collider.tag == "Enemy")
{
HitTarget();
}
else
{
// something other than the enemy was collided with
}
}
Answer by jjdoughboy · May 05, 2020 at 08:50 PM
@icehex I made the switch but its kind've hard to tell if it worked is there a place a can put a Debug.(Log) to see if it hit the collider. My projectile every other frame will go to the enemy position but the projectile is suppose to destroy itself after hitting the collider and deal damage so is there anything else I need to do at this stage to fix this
@icehex it seems that my original projectile script has my projectile go to the enemy game object 's position but doesn't destroy itself and will update to the enemy position again. your suggestion has made my projectile get to the enemy game object's position and the next frame the projectile will jump to a random position somewhat close to the enemy position so I think my original script will work better. I just need to figure out how to make my projectile recognize the enemy collider and deal damage and than destroy itself. I added a Debug.Log to tell me if the collider got hit like @boss2070301 suggested and never got the popup so my projectile doesn't hit the collider as if the projectile doesn't think the collider exists.
The script only looks at the collider if explosionRadius is greater than zero. Otherwise it considers the enemy to be hit if the enemy's position is within the projectile's reach this frame. if you want to use collision, you'll need to take out the dir.magnitude
void OnCollisionEnter(Collision collision)
{
if (collision.collider.tag == "Enemy")
{
HitTarget();
}
else
{
// something other than the enemy was collided with
}
}
@icehex just to be sure I would replace the following with the on collision enter function correct
if (dir.magnitude <= distanceThisFrame)
{
HitTarget();
return;
}
transform.Translate(dir.normalized * distanceThisFrame, Space.World);
transform.LookAt(target);
}
ok so my explosion Radius is what caused my projectile to actually hit the collider so now that works but now my projectile is not destroying itself after it hits the collider.
Hi, I think I know why your object isn't going away. Check out my answer above, for clarity/conciseness I've combined my recommendations into the answer.
Answer by boss2070301 · May 05, 2020 at 08:55 PM
@jjdoughboy I think you should put it here like so
foreach(Collider collider in colliders)
{
if(collider.tag == "Enemy")
{
Damage(collider.transform);
Debug.Log("I got hit!");
}
}
@boss2070301 I added the debug so now know that my projectile is not hit the collider even though my projectile is going to the enemy game object position.