- Home /
OverlapSphere not detecting target
I have an automatic turret I would like to aim at specific enemies and prioritize shooting the closest enemy in its OverlapSphere. I got it to aim at the enemies just fine but it doesn't seem to be picking them up in the Inspector. Did I get everything right in my script?
using UnityEngine;
using System.Collections;
public class Cannon : MonoBehaviour {
private GameObject target;
public float Range = 5;
private Quaternion targetRotation;
public bool Aiming = false;
public Collider[] Targets;
// Update is called once per frame
void Start () {
target = GameObject.FindWithTag("Enemy");
}
Transform FindTargets(){
Transform nearest = null;
Collider[] Targets = Physics.OverlapSphere(transform.position, Range);
foreach (Collider hit in Targets){
if(hit && hit.tag == "Enemy"){
float dist = Vector3.Distance(transform.position, hit.transform.position);
if(dist < Range){
Range = dist;
nearest = hit.transform;
}
}
}
return nearest;
}
void Update(){
if(Aiming){
Vector3 look = target.transform.position - transform.position;
look.z = 0;
targetRotation = Quaternion.LookRotation (look);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2.0f);
Transform enemy = FindTargets ();
if(enemy){
Debug.Log("BANG");
}
}
}
}
Have to ask, have you remembered to set the "Enemy" tag on the object?
Try this debug: foreach (Collider hit in Targets){ Debug.Log("Hitted:"+hit.transform.name);
Answer by robertbu · Aug 18, 2013 at 04:02 AM
I see three problems with your code.
You declare 'public Collider[] Targets' on line 10, then on line 22, you declare 'Collider[] Targets'. The second one is local to FindTargets() and therefore overrides the one on line 10. This mean the one on line 10 is never accessed. That is why you don't seen any values in the inspector. You need to remove the 'Colider[]' from the one on line 22 in order for the one on line 10 to be assigned.
On line 27, you write, 'Range = dist'. This code means that you are overwriting the value of 'Range' set in the inspector. The first time through the value gets dropped to the distance to the nearest object. After that, Physics.OverlapSphere() will only change if other objects are nearer the the nearest object. That is, it will not find targets that are within the original range but further than the last nearest target even if previous nearest target no longer exists or has moved out of range.
In Update() you never assign the results of 'FindTargets()' to 'targtet', therefore the code never finds any target but the first one.
Here is a bit of a rewrite:
Transform FindTargets(){
float maxDist = Range;
Transform nearest = null;
Targets = Physics.OverlapSphere(transform.position, Range);
Debug.Log (Targets.Length+","+Range);
foreach (Collider hit in Targets){
if(hit && hit.tag == "Enemy"){
float dist = Vector3.Distance(transform.position, hit.transform.position);
if(dist < maxDist){
maxDist = dist;
nearest = hit.transform;
}
}
}
return nearest;
}
Note when you rewrite Update(), make sure you assign null values returned by FindTargets() to be assigned to 'target'. If you don't, your gun will continue to track the last target even if it is out of range, and it will also attempt to track the last target even when all the enemies are destoryed. Of course if you allow null values for 'target', you will need to avoid accessing target when it is null.
Thank you so much! I was aware of solutions 1 and 2, but I wasn't sure if those lines needed to be re-stated or not so I figured better safe than sorry. Not in this case it seems.
As far as the third solution, is there a better way to keep track of targets than assigning null values? I've seen some examples of OverlapSpheres using for() statements but I don't understand their use. The only targets the turret will be ai$$anonymous$$g at are children of an empty object prefab that instantiates when another object is destroyed.
Null is fine. I don't know your game mechanic, but I expect the turret to stop tracking if the player is out of range. If so, then your logic will be something like (pseudo-code):
target = FindTargets();
if (target != null) {
// do the rotating and firing stuff;
}
This way, the turret stops firing if all the player object are out of range or they are all destroyed, and it immediately starts firing and tracking if any move back in range.
$$anonymous$$essing around a little bit, everything seems to be working as intended. The new update is void Update(){
Transform target = FindTargets();
if(target != null){
Vector3 look = target.transform.position - transform.position;
look.z = 0;
targetRotation = Quaternion.LookRotation (look);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2.0f);
}
}
As far as I can tell the turret appears to be changing targets correctly. So thanks a bunch!
Your answer
Follow this Question
Related Questions
HELP! i want to write to look at the target and give a force to follow 3 Answers
Does OverlapSphere() return the colliders in any particular order? 1 Answer
Destroy objects within ordered Array by line of sight 1 Answer
targeting multiple enemys 1 Answer
OverlapSphere ignoring all colliders when I use the layerMask parameter. 1 Answer