- Home /
Enemy AI help how to restart collision detection?
Hi, in my tower defense game, I have soldier units from barracks and theyare catching enemies.
My soldierAttack.cs applied on soldier units. It works very well but only for 1 enemy. After they killed they stop searching enemies. I couldnt figure it out how to restart void on trigger after they killed enemy. I need to restart void on trigger function, after this state is true; if(other.gameObject.getcomponent().health <=0) but i dont know where do i need to put?
edit: "Ground" tag is "enemy" tag.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SoldierAttack : MonoBehaviour {
private NavMeshAgent agent;
private bool contacted = false;
private NavMeshMove enemymove;
public float askerDamage;
public float timer = 0;
public float damageTime = 10;
private bool stayingContact = false;
private Collider enemy;
void Start() {
agent = GetComponent<NavMeshAgent>();
}
void OnTriggerEnter (Collider other){
Debug.Log ("contacted");
contacted = true;
if (stayingContact)
{
return;
}
if(other.gameObject.tag == "Ground" ){
stayingContact = true;
enemy = other;
agent.SetDestination(other.gameObject.transform.position);
enemymove = other.gameObject.GetComponent<NavMeshMove>();
enemymove.enabled = false;
other.gameObject.GetComponent<NavMeshAgent>().enabled = false;
}
}
void OnTriggerStay(Collider other){
if (enemy == null || enemy != other)
return;
if (other.gameObject.tag == "Ground") {
if (timer >= damageTime)
{
timer -= damageTime;
other.gameObject.GetComponent<Properties>().Hit(askerDamage);
}
}
timer += Time.deltaTime;
}
}
You gotta make some sort of targeting system bro.
Ok bare with me because the only Tower Defense game I played was Bloona by ninja kiwi, with the monkeys. Anyways.
They have this Circle for their $$anonymous$$onkey's Range, and when an enemy enters that range, the $$anonymous$$onkeys will then shoot at the enemy, that first entered. and when it exits the circle they will then not shoot.
So basically, just make another Box/Circle Collider, name it range and then child it to your soldier.
After that make your script have an OnTriggerEnter effect and an OnTriggerExit
When an Enemy Enters the Box Collider of the Soldier you should have this public(or non public) GameObject Named as Target, and when the enemy enters the collider the Target will then be the GameObject Target.
Here's the Script.
//It Enters
void OnTriggerEnter(Collision coll)
{
if (col.gameobject.tag == ("Enemy"))
{
Target = col.gameObject;
}
}
//It Exits
void OnTriggerExit(Collision coll)
{
if (col.gameobject.tag == ("Enemy"))
{
Target = null;
}
}
Oh btw You should make a tag called enemy or whatever to help detect the collision.
Hope that helps you out man!
Thank you man. I aprreciate it. But your script doesnt help. Let me explain so:)
I have towers and they are already shooting enemy. These soldiers are spawned from barracks, they are additional. $$anonymous$$y damage function works on OnTriggerStay. When enemy stay in collision with soldier units(because soldiers have melee attack), they are taking damage in time. That works great. But after an enemy killed by soldier, soldier do nothing. Actually it must search a new enemy but he does nothing. i dont know how to restart collision detection again.
If i make like in your script, they just pass the soldiers, and while they are passing they will take damage. I dont want this. What i've done above is ; when they encounter a soldier, they stop and fight. I hope its clear:)
Should the script attack multiple enemies at once or just one at a time?
Answer by acmeydan · Sep 20, 2015 at 09:22 PM
Ok. I found the answer by another friend;
just I add one line in script like this;
if(other.gameObject.Getcomponenet<enemyscript>(). health <=0)
{
enemy= null;
stayingContact = false;
}
thank you again for working my mind.
Answer by bubzy · Sep 20, 2015 at 02:38 PM
i wouldnt even bother using collisions for this, just a distance to enemy check should be sufficient.
make a statemachine for the soldiers,
isAttacking
isMoving
hasTarget
then check like
if (!hasTarget)
{
findTarget(); //here you could pick a target from list of available enemies
}
void findTarget()
{
//search through available enemies and pick one. if successful then set hasTarget to true and isMoving to true
}
if(isMoving)
{
if(distanceToTarget >= attackDistance)
{
moveToTarget(); // here you can select the enemies position that you chose and use pathfinding to get there
}
else //soldier is within attack range
{
isMoving = false;
isAttacking = true;
}
}
if(isAttacking)
{
if(enemyHealth > 0)
{
damageEnemy(); // or whatever your routine is
}
if(enemyHealth <=0)
{
hasTarget = false;
isAttacking = false;
isMoving = false;
}
//at this point you may want to see if the soldier returns to base or just continues to attack enemies
}
its all kinda pseudocode but i hope you can get the general idea from this.
Thank you. This make sense, but;
The only point is I dont know which method is better for performance, my game is mobile game, and i dont know is it too much for performance if I find all enemy objects in the game(probaly maximum number is 30-40) with "find game objects with tag" then list them with coordinates, and then calculate distances between soldier itself, then choose the closest one for target, repeat this coroutine for all soldiers spawned in game(lets say for 12 soldier). I always tought its long way. This is why I choose the collision method, because in this way; the only target is the game object which it has already contacted. But i dont know is there any huge differencies for mobile performance.
What do you think?
you could combine methods and have a "base" where the soldiers come out of, when an enemy enters the "range" of the base, it adds it to a list which the soldier references to check its distance.
so many ways of doing this, i guess the only way to test performance is to try a couple of methods.
good luck :)
Answer by MakakWasTaken · Sep 20, 2015 at 01:17 PM
If it is supposed to damage multiple at once use this:
float ViewDistance;
void Update() {
foreach (Collider collider in Physics.OverlapSphere(transform.position, ViewDistance))
{
if (collider.tag == "Ground") {
//ATTACK
}
}
}
If not use this:
float ViewDistance;
void Update() {
Collider col = Physics.OverlapSphere(transform.position, ViewDistance)[0];
{
if (col.tag == "Ground") {
//ATTACK
}
}
}
Thank you so much. But my script work well, I dont need to attack them. They already attack. But after enemy killed, they dont attack again. So i need to restart the collision functions. I think I should add a new boolean something like enemy death=true, maybe I should add a new void onEnemyDeath, something like this, I dont know how to do.