- Home /
Help with distance between multiple objects
Hey guys so I am trying to figure out how to calculate the distances between x enemies and a cannon, so the cannon knows which enemy is closest to him. I tried doing something like:
for (int i = 0; i < maxNumberOfenemies; i++)
{
float enemyPositions[i] = GameObjects enemies[i].transform.position;
float fdistance = Vector3.Distance(enemyPositions[i], transform.position);
I tried to then figure out the distance but still cant, i am having problems
}
thanks in advance :)
Answer by aldonaletto · Oct 15, 2011 at 04:38 AM
The easier, faster and safer solution is to let Unity keep the enemy list for you. Create an empty object, name it "Enemies" and attach to it the enemy creator script. Every time a new enemy is created, make it a child of "Enemies".
In the cannon script, find "Enemies" at Start, and in Update, check the distance of all "Enemies" children to find the closest one, then rotate to it and shoot.
This is your enemy creator script (attached to the object named "Enemies") - the only modification is the "childing" of the new enemy to the creator:
private float fTimer = 0; private float fSpawnTime = 20;
private const int iEnemySpawnLocTotal = 7; private GameObject[] goEverySpawnLocation = new GameObject[iEnemySpawnLocTotal]; public GameObject enemy1;
void Start() { goEverySpawnLocation = GameObject.FindGameObjectsWithTag("enemySpawn"); }
void Update() { fTimer += Time.deltaTime; if(fTimer > fSpawnTime) { int randomNumber = Random.Range(0, iEnemySpawnLocTotal); fTimer = 0; GameObject myPrefab = (GameObject)Instantiate(enemy1); myPrefab.transform.position = goEverySpawnLocation[randomNumber].transform.position; // make the new enemy a child of this object ("Enemies") myPrefab.transform.parent = transform; } }
And this is the cannon script (assigned to each cannon):
private GameObject enemies; // reference to the Enemies object
void Start(){ enemies = GameObject.Find("Enemies"); }
void Update(){
float minDistance = Mathf.Infinity; // initiate distance at max value possible
Transform target = null; // use this to detect the no enemy case
foreach (Transform enemy in enemies.transform){
float enemyDistance = Vector3.Distance(enemy.position, transform.position);
if (enemyDistance < minDistance){ // if it's closer than the others...
minDistance = enemyDistance; // record its distance...
target = enemy; // and its transform
}
}
// target will still be null if no enemy exists
if (target){ // but if the closest enemy found...
// rotate towards the target transform and shoot
transform.LookAt(target);
// draw a line to the enemy found
Debug.DrawLine(transform.position, target.position, Color.green);
}
}
I appreciate your help, its on its way there but its still not working as it should. I put Debug.Log on the target's position and it starts out where the enemies empty is, and when a monster appears it offsets just a bit, and with every new monster that appears it offsets more and more and the target position is in the center of all the monsters + the enemies empty.
When I did tried doing this with only 1 enemy spawning, the Target and the $$anonymous$$Position all point to the actual enemy that spawns but the Target.transform.position = some random Vector3, but it seems as though its almost the center of the Empty Enemies and the enemy that spawns
thank you, I am trying to debug this for a while and when I have 1 enemy spawn what actually happens is the x,y,z positions between the Enemies Empty and the Enemy that spawns get added up. I have tried unparenting, and if tag = "enemy", and other such things but nothing seems to work.
I tested both scripts, and they worked fine after a few syntax corrections - maybe some of these errors may caused the strange behaviour you mentioned.
I added a debug line to the cannon script that draw a green line between the cannon and the enemy it choosed, and you can clearly see that each cannon finds the nearest enemy to shoot.
I fixed the answer; replace your scripts with these ones, and test it again. Remembering the setup: create the "Enemies" empty object and attach the first script to it, and attach the second script to each cannon you have.
Answer by Graham-Dunnett · Oct 14, 2011 at 09:17 PM
Use a minDistance variable set to a large value, and an enemy variable set to -1. Then, inside your loop, check to see if the fdistance is less than your minDistance. If it is, make a note of the value of i in your enemy variable. On exitting the loop, minDistance is the closest enemy, and enemy in the closest one.
Note that Vector3.Distance is an expensive operation if you have a lot of enemies. Instead, subtract transform.position from enemies[i].transform.position. This is the vector from the camera to the current enemy. Then use sqrMagnitude. The docs for the sqrMagnitude API have an example that you might care to look at.
the problem I am having with all of this too is that my enemies get instantiated and made 1 by 1 so i also get array out of bounds because there might only be 1 enemy on screen and maxNumberOfenemies is set to 25.... which doesn't make any sense really, I need to figure out how to dynamically allocate them.
How enemies[ ] and enemyPositions[ ] are created? Are they fixed size arrays (builtin) or dynamic arrays (like lists)?
So right now it my cannon is set up as this:
void update() {
GameObject enemy = GameObject.FindGameObjectWithTag("Enemy")
vEnemyPosition = enemy.transform.position;
fDistance = Vector3.Distance (vEnemyPosition, transform.position);
}
then I have a rotate towards target and shooting functions.
my enemies are set up on 7 spawn points:
private const int iEnemySpawnLocTotal = 7;
private GameObject[] goEverySpawnLocation = new GameObject[iEnemySpawnLocTotal];
public GameObject enemy1;
void Start() {
goEverySpawnLocation = GameObject.FindGameObjectsWithTag("enemySpawn");
}
void Update() { fTimer += Time.deltaTime;
if(fTimer > fSpawnTime) {
randomNumber = Random.Range(0, iEnemySpawnLocTotal);
fTimer = 0;
GameObject myPrefab = (GameObject)Instantiate(enemy1);
myPrefab.transform.position = goEverySpawnLocation[randomNumber].transform.position; } }
so what happens is, my cannons get an error until the first enemy shows up, then when more enemies spawn, all my cannons still target first spawned enemy until it dies and then they basically target the enemies in order until the last one is dead.
so my big question is, how can I set it up where, my cannons dont try to target anything until enemy spawns, and when more enemies spawn, if an enemy is closer to a cannon then all the other cannons, that cannon targets that enemy ins$$anonymous$$d of all cannons targeting the same enemy, if that makes sense. basically what my original question was except also for maybe dynamically allocating the number of enemies that are on screen or (alive).
Answer by Ppa0 · Oct 16, 2011 at 04:50 AM
I really appreciate your help, and thank you for all the help. I don't really understand why it is not working, however I have decided to go another route anyways. I have to get back to the drawing board and figure out my mechanics first because I keep changing my mind every few days. So anyways, thanks again.