- Home /
Do I need to attach a Rigidbody to my enemy and/or projectile to get the collisions to work
In my tower defense game I have a turret that will shoot a projectile at the game object with the tag "enemy" and deal damage and destroy itself on collision. my projectile does spawn and heads to the enemy but my enemy's health will decrease before my projectile hits the enemy box collider nor will it destroy itself after health decreases. It makes me think my projectile doesn't recognize the collision or the collider. I should mention my enemy does move following a waypoint system like start at waypoint A and then move to waypoint B. And both my projectile and enemy have box colliders attached to them and neither of them have a Rigidbody attached to them. I've been reading that I need use Rigidbodys but don't know if I need to or how to use them properly so can anyone tell me what I can do to solve this problem.
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);
}
}
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);
}
}
I don't know if this has something to do with the problem but this my turret script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Turret : MonoBehaviour
{
// Our target will be the instantiated enemyPrefab
public Transform target;
private Enemy targetEnemy;
[Header("Bullets")]
// Range at which our turrets will detect the enemies
public float range = 15f;
public float fireRate = 1f;
private float fireCountdown = 0f;
public GameObject projectilePrefab;
[Header("Laser")]
public bool useLaser = false;
//Select the GameObject the LineRenderer will interact with >> Add Componet >> Type "LineRenderer"
public LineRenderer laserRenderer;
public ParticleSystem impactEffect;
public float slowImpact = 0.3f;
public int damageOverTime = 30;
[Header("Unity Setup Fields")]
// Tag we will assign our enemyPrefab so that the turret can know what to detect
public string enemyTag = "Enemy";
// Assign this to the head of the turret
public Transform partToRotate;
// rate at which the head will turn
public float turnSpeed = 10f;
public bool usePartToRotate = false;
public Transform firePoint;
// Start is called before the first frame update
void Start()
{
// Rather than update every frame in Update
// We can set our UpdateTarget() to call at a given rate
// in this case, 0.5f
InvokeRepeating("UpdateTarget", 0f, 0.5f);
}
void UpdateTarget()
{
// Assigns our enemies based on the Enemy Tag
GameObject[] enemies = GameObject.FindGameObjectsWithTag(enemyTag);
// As close to our turret as the enemies will get
float shortestDistance = Mathf.Infinity;
// Sets nearestEnemy to null until an enemy is within range
GameObject nearestEnemy = null;
// Creates the enemy Gameobject inside enemies[]
foreach (GameObject enemy in enemies)
{
// Distance from the turret to enemy
float distanceToEnemy = Vector3.Distance(transform.position, enemy.transform.position);
if (distanceToEnemy < shortestDistance)
{
shortestDistance = distanceToEnemy;
nearestEnemy = enemy;
}
}
// Determines the next closest enemy
if (nearestEnemy != null && shortestDistance <= range)
{
// Assigns our enemy as our target
target = nearestEnemy.transform;
targetEnemy = nearestEnemy.GetComponent<Enemy>();
}
if(shortestDistance > range)
{
target = null;
return;
}
}
// Update is called once per frame
void Update()
{
if (target == null)
{
if(useLaser)
{
if (laserRenderer.enabled)
laserRenderer.enabled = false;
impactEffect.Stop();
}
return;
}
if(usePartToRotate)
{
LockOnTarget();
if (useLaser)
{
Laser();
}
else
{
// if time til the last shot is less than or equal to 0
// resume shooting + restart fireCountDown
if (fireCountdown <= 0)
{
Shoot();
fireCountdown = 1f / fireRate;
}
// restarts fireCountdown
fireCountdown -= Time.deltaTime;
}
}
else
{
if (useLaser)
{
Laser();
}
else
{
// if time til the last shot is less than or equal to 0
// resume shooting + restart fireCountDown
if (fireCountdown <= 0)
{
Shoot();
fireCountdown = 1f / fireRate;
}
}
// restarts fireCountdown
fireCountdown -= Time.deltaTime;
}
}
void LockOnTarget()
{
// In the next few lines, we will tell our turret head to turn towards
// the enemy it is currently closest to
Vector3 dir = target.position - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Vector3 rotation = Quaternion.Lerp(partToRotate.rotation, lookRotation, Time.deltaTime * turnSpeed).eulerAngles;
partToRotate.rotation = Quaternion.Euler(0f, rotation.y, 0f);
}
void Laser()
{
targetEnemy.Slow(slowImpact);
targetEnemy.TakeDamage(damageOverTime * Time.deltaTime);
if (!laserRenderer.enabled)
{
laserRenderer.enabled = true;
impactEffect.Play();
}
laserRenderer.SetPosition(0, firePoint.position);
laserRenderer.SetPosition(1, target.position);
Vector3 dir = firePoint.position - target.position;
impactEffect.transform.position = target.position + dir.normalized * 0.5f;
impactEffect.transform.rotation = Quaternion.LookRotation(dir);
}
void Shoot()
{
GameObject bullet60 = (GameObject)Instantiate(projectilePrefab, firePoint.position, firePoint.rotation);
Projectile projectile = bullet60.GetComponent<Projectile>();
if (projectile != null)
{
projectile.Seek(target);
}
GameObject audioManagerObject = GameObject.Find("AudioManager");
AudioManager audioManagerScript = audioManagerObject.GetComponent<AudioManager>();
audioManagerScript.PlayFriendlyProjectile();
}
// Creates a visual representation of the range on our turret
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(transform.position, range);
}
}
Answer by cam74 · Apr 30, 2020 at 10:36 PM
Use raycasting!! Colliders and rigid body detection lead to so many detection problems because of the physicsupdate time. Go in unity documentation and look for Raycast, you'll find a perfectly working example that will perfectly fit to your project. If you need help about raycasting just ask again here.
Raycast is good if you have instant projectil , like bullet. but if your projectil can move during 1-2 second to get the target, I don't think that is the best option...
I'm also trying to search the good method for that :)
On a second note, it looks as if the they are trying to get the collision of an explosion radius and not a single point of contact.
Your answer
![](https://koobas.hobune.stream/wayback/20220612232939im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Internal collisions 1 Answer
Using a ghost object to place things 0 Answers
onParticleCollison not triggering 0 Answers
OnTriggerEnter2D being called by GameObject without the trigger 1 Answer
Colliders overlapping 2 Answers