Reputation: 1098
I have a script which is used to control targeted enemies and another to control player attacks, the targeting script seems to work fine on its own until the first target is killed, so when I click Tab it targets my enemies in distance order but when my first target dies it cannot target another and I get the message:
MissingReferenceException: The object of type 'Transform' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object.
Also I am unable to attack anything except the first player whether it is targeted or not. I tried switching my playerattacks so it worked with a list just like my targeting script however I get all the same errors.
My targetting script is:
public class Targetting : MonoBehaviour {
public List<Transform> targets;
public Transform selectedTarget;
public string targetTag = "Enemy";
private Transform myTransform;
//Use this for initialization
void Start () {
targets = new List<Transform>();
selectedTarget = null;
myTransform = transform;
AddAllEnemies();
}
public void AddAllEnemies() {
GameObject[] go = GameObject.FindGameObjectsWithTag(targetTag);
foreach(GameObject enemy in go) {
AddTarget(enemy.transform);
}
}
public void AddTarget(Transform enemy) {
targets.Add(enemy);
}
private void SortTargetsByDistance() {
targets.Sort(delegate(Transform t1, Transform t2) {
return (Vector3.Distance(t1.position, myTransform.position).CompareTo)
(Vector3.Distance(t2.position, myTransform.position));
});
}
private void TargetEnemy() {
if(selectedTarget == null) {
SortTargetsByDistance();
selectedTarget = targets[0];
} else {
int index = targets.IndexOf(selectedTarget);
if (index < targets.Count -1) {
index++;
} else {
index = 0;
}
selectedTarget = targets[index];
}
}
//Update is called once per frame
void Update ()
{
if(Input.GetKeyDown(KeyCode.Tab))
{
TargetEnemy();
}
}
}
And my PlayerAttack Script is currently:
public class PlayerAttack : MonoBehaviour {
public enemyHealth eHealth;
public GameObject enemy;
private float MHCD; // MeleeHit CD
private float hitChance;
// Use this for initialization
void Start () {
}
void Update () {
hitChance = Random.Range (1, 100);
if (Input.GetKeyDown (KeyCode.Alpha1) && Time.time - MHCD > 1) {
if (hitChance > 0 && hitChance < 90) {
Attack1 ();
MHCD = Time.time;
}
}
}
void Attack1() {
float distance = Vector3.Distance (enemy.transform.position, transform.position);
if (distance < 4) {
eHealth.SendMessage ("MeleeHit");
} else {
Debug.LogWarning ("You are too far away!");
}
}
}
Basically what I am looking to do is to make both scripts work with eachother so when an enemy is targeted, it'll only deduct damage from the targeted enemy, and when an enemy is killed it is removed from the list 'targets'
Upvotes: 0
Views: 2040
Reputation: 12258
I completely agree with Joe's diagnosis that the key problem here is that you are not updating your List<Transform> targets
after calling Destroy()
on any its members' associated objects. I'm going to propose a slightly different fix to the problem, though.
When you attempt to sort the targets by their distance from the player with the following method:
private void SortTargetsByDistance() {
targets.Sort(delegate(Transform t1, Transform t2) {
return (Vector3.Distance(t1.position, myTransform.position).CompareTo)
(Vector3.Distance(t2.position, myTransform.position));
});
}
You're attempting to access the Transform
on each potential target for comparison, but aren't taking into account the possibility that the target may have already been destroyed (rendering its Transform
nonexistent). A simple fix to this is to remove all null references to Transform
objects before trying to sort targets
, by adjusting it to the following:
private void SortTargetsByDistance() {
targets.RemoveAll(target => target == null);
targets.Sort(delegate(Transform t1, Transform t2) {
return (Vector3.Distance(t1.position, myTransform.position).CompareTo)
(Vector3.Distance(t2.position, myTransform.position));
});
}
Hope this helps! Let me know if you have any questions.
(Although this is the most minimal change to your code, I do still support the idea of having a manager that keeps track of the enemies, like what Joe suggested. It'll save you some headaches in the long run, if your project keeps growing.)
Upvotes: 2