Good afternoon everyone, when I load the game for the first time it works without problem I can damage the enemies and make their life bar decrease but if they kill me and load the scene again using a button again, then when I perform the attack to damage them no longer does them any damage. Could someone please help me, I’ve been investigating and trying to correct this error for several days but I can’t, I’m starting to learn this about video game development. Beforehand thank you very much.
The error message is the following:
MissingReferenceException: The object of type ‘SkeletonBasic’ 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. EkardController.AttackDamage () (at Assets/Scripts/EkardController.cs:296)
Line 296 is as follows:
var enemyPos = enemy.transform.position;
public void AttackDamage() {
foreach (var enemy in SkeletonBasic.Instances)
{
var enemyPos = enemy.transform.position;
if ((enemyPos - transform.position).sqrMagnitude < attackRange * attackRange)
It’s always difficult to know what’s going on when full code isn’t posted. But the long and short of it is when you reload a level, stuff is destroyed, if those destroyed objects are still referenced, like a static variable or a dontdestroyonload floating object and code tries to access it, you can get this error.
Always post full code for a script with code tags.
switch (newState)
{
case PlayerState.Idle:
PlayIdle();
break;
case PlayerState.Run:
PlayRun();
break;
case PlayerState.Attack:
PlayAttack();
break;
case PlayerState.Die:
PlayDie();
break;
case PlayerState.Roller:
PlayRoller();
break;
case PlayerState.Impact:
PlayImpact();
break;
case PlayerState.Attack_Two:
PlayAttackTwo();
break;
case PlayerState.LetsGo:
PlayLestGo();
break;
}
state = newState;
}
public void Hit(int damage)
{
Debug.Log(“Golpe a Ekard”);
public void PlayIdle()
{
animator.CrossFade(“idle”,0.1f);
}
public void PlayRun()
{
animator.CrossFade(“run”, 0.1f);
}
public void PlayAttack()
{
foreach(var trail in trailRenderers)
{
trail.SetActive(true);
}
animator.CrossFade(“attack”, 0.1f);
}
public void PlayRoller()
{
animator.Play(“place roll”);
}
public void PlayDie()
{
animator.CrossFade(“die 2”, 0.1f);
}
public void PlayImpact()
{
animator.Play(“impact”);
}
public void PlayLestGo()
{
animator.Play(“lets”);
}
public void PlayAttackTwo()
{
foreach (var trail in trailKicks)
{
trail.SetActive(true);
}
animator.CrossFade(“attack 2”,0.1f);
}
public void OnTriggerStay(Collider other)
{
if (other.CompareTag(“Terrain”))
{
To_Jump = true;
}
}
public void OnTriggerExit(Collider other)
{
To_Jump = false;
}
public void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag(“Plasma”))
{
UnityEngine.Debug.Log(“Collider with Plasma”);
panelMision.SetActive(true);
StartCoroutine(CountTextMision());
}
}
IEnumerator CountTextMision()
{
yield return new WaitForSecondsRealtime(6);
panelMision.SetActive(false);
}
IEnumerator PlayInitAnimation()
{
yield return new WaitForSeconds(19.0f);
yield return new WaitForEndOfFrame();
SetState(PlayerState.LetsGo);
}
IEnumerator WaitSoundOver()
{
yield return new WaitForSeconds(0.5f);
soundsEkard.PlayOneShot(soundDeadEkard,10.0f);
yield return new WaitForSeconds(3.0f);
soundsEkard.PlayOneShot(soundGameOver, 0.5f);
panelLost.SetActive(true);
}
public void AttackEnd()
{
SetState(EnemyState.Idle);
UnityEngine.Debug.Log(“Acabé de atacar”);
}
public void AttackDamage()
{
var player = EkardController.Instance;
var posEkard = player.transform.position;
var distance = (posEkard - transform.position).sqrMagnitude;
I think you missed where I mentioned, use code tags. Using code tags properly
Please edit your post so people can read it a lot easier.
Edit: Also, this.
As I said, you’re simply destroying something that still has a reference. It’s pretty straight forward. Once again, static is a keyword that I mentioned for you to look for. A static list that is made up of instances that get destroyed will start throwing errors when it can’t find those items anymore.
public static List<SkeletonBasic> Instances = new List<SkeletonBasic>();
Thank you very much for sharing the link for the code labels, I send both codes again, the one for the player, which is the EkardController script, and the one for the enemy, which is SkeletonBasic.
Thank you and again an apology.
MissingReferenceException: The object of type ‘SkeletonBasic’ 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.
EkardController.AttackDamage () (at Assets/Scripts/EkardController.cs:300)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EkardController : MonoBehaviour
{
public static EkardController Instance;
public enum PlayerState
{
Idle,
Run,
Attack,
Die,
Roller,
Impact,
Attack_Two,
LetsGo
}
public PlayerState state;
[SerializeField] float speed = 3.5f;
[SerializeField] Animator animator = null;
[SerializeField] float attackRange = 1.5f;
//[SerializeField] float attackAngle = 90f;
[SerializeField] List<GameObject> trailRenderers = new List<GameObject>();
[SerializeField] List<GameObject> trailKicks = new List<GameObject>();
//[SerializeField] int maxHealth = 5;
[SerializeField] PlayerHealth Health;
[SerializeField] Slider sliderPlayer;
[SerializeField] Transform Avelyn = null;
[SerializeField] GameObject panelLost;
[SerializeField] AudioSource soundsEkard;
[SerializeField] GameObject soundWinner;
[SerializeField] GameObject soundAvelyn;
[SerializeField] GameObject soundCementary;
[SerializeField] GameObject panelMision;
[SerializeField] Transform target;
[SerializeField] AudioClip swordPlay;
[SerializeField] AudioClip soundRoller;
[SerializeField] AudioClip soundDamage;
[SerializeField] AudioClip soundDeadEkard;
[SerializeField] AudioClip soundKick;
[SerializeField] AudioClip soundGameOver;
[SerializeField] ParticleSystem bloodEkard;
[SerializeField] public static bool isAlive = true;
[SerializeField] Rigidbody ekardRb;
[SerializeField] float forceJump = 4;
[SerializeField] bool To_Jump;
[SerializeField] bool attack_2;
private float horizontalInput;
private float verticalInput;
[SerializeField] GameObject buttonMenu;
[SerializeField] GameObject buttonExit;
public void Awake()
{
To_Jump = false;
Instance = this;
Health.currentHealth = Health.maxHealth;
sliderPlayer.maxValue = Health.maxHealth;
sliderPlayer.value = sliderPlayer.maxValue;
soundsEkard = GetComponent<AudioSource>();
StartCoroutine(PlayInitAnimation());
}
// Start is called before the first frame update
private void Start()
{
if (animator == null)
{
animator = GetComponent<Animator>() ?? GetComponentInChildren<Animator>();
}
SetState(PlayerState.Idle);
}
// Update is called once per frame
private void FixedUpdate()
{
sliderPlayer.value = Health.currentHealth;
if (state == PlayerState.Die)
{
return;
}
if (Input.GetKeyDown(KeyCode.DownArrow))
{
SetState(PlayerState.Roller);
soundsEkard.PlayOneShot(soundRoller, 5.0f);
}
if (To_Jump == true)
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
animator.SetBool("Jump", true);
ekardRb.AddForce(new Vector3(0, forceJump, 0), ForceMode.Impulse);
}
animator.SetBool("Is Ground", true);
}
else
{
IsFalling();
}
if (Input.GetButton("To_Speed"))
{
speed = 6.0f;
}
else
{
speed = 3.5f;
}
if (Vector3.Distance(transform.position, Avelyn.position) < 2f)
{
SetState(PlayerState.Run);
transform.position = Vector3.MoveTowards(transform.position, target.position, 1.0f * Time.deltaTime);
Health.currentHealth = 0;
soundAvelyn.SetActive(false);
soundCementary.SetActive(false);
soundWinner.SetActive(true);
StartCoroutine(ButtonsActive());
return;
}
horizontalInput = Input.GetAxis("Horizontal");
verticalInput = Input.GetAxis("Vertical");
var direction = new Vector3(horizontalInput, 0f, verticalInput).normalized;
if (state != PlayerState.Attack && state != PlayerState.Attack_Two)
{
if (direction.sqrMagnitude > 0f)
{
transform.position = transform.position + direction * speed * Time.deltaTime;
SetState(PlayerState.Run);
transform.LookAt(transform.position + direction);
}
else if (direction.sqrMagnitude < 0f)
{
transform.position = transform.position + direction * speed * Time.deltaTime;
SetState(PlayerState.Run);
transform.LookAt(transform.position + direction);
}
else
{
SetState(PlayerState.Idle);
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
attack_2 = true;
Debug.Log("Patada Activada");
SetState(PlayerState.Attack_Two);
soundsEkard.PlayOneShot(soundKick);
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
Debug.Log("GolpeActivado");
SetState(PlayerState.Attack);
soundsEkard.PlayOneShot(swordPlay);
}
}
if(isAlive == false)
{
DontDestroyOnLoad(this);
}
}
void IsFalling()
{
animator.SetBool("Is Ground", false);
animator.SetBool("Jump", false);
}
void SetState(PlayerState newState)
{
if (state == newState)
{
return;
}
switch (newState)
{
case PlayerState.Idle:
PlayIdle();
break;
case PlayerState.Run:
PlayRun();
break;
case PlayerState.Attack:
PlayAttack();
break;
case PlayerState.Die:
PlayDie();
break;
case PlayerState.Roller:
PlayRoller();
break;
case PlayerState.Impact:
PlayImpact();
break;
case PlayerState.Attack_Two:
PlayAttackTwo();
break;
case PlayerState.LetsGo:
PlayLestGo();
break;
}
state = newState;
}
public void Hit(int damage)
{
Debug.Log("Golpe a Ekard");
sliderPlayer.value -= damage;
soundsEkard.PlayOneShot(soundDamage, 5.0f);
SetState(PlayerState.Impact);
bloodEkard.Play();
Health.currentHealth -= damage;
if (Health.currentHealth <= 0)
{
isAlive = false;
SetState(PlayerState.Die);
StartCoroutine(WaitSoundOver());
StopCoroutine(WaitSoundOver());
}
}
public void AttackEnd()
{
SetState(PlayerState.Idle);
foreach (var trail in trailRenderers)
{
trail.SetActive(false);
}
UnityEngine.Debug.Log("Acabé de atacar");
}
public void Attack_Two_End()
{
attack_2 = false;
SetState(PlayerState.Idle);
foreach (var trail in trailKicks)
{
trail.SetActive(false);
}
UnityEngine.Debug.Log("Acabé de atacar");
}
public void AttackDamage()
{
foreach (var enemy in SkeletonBasic.Instances)
{
var enemyPos = enemy.transform.position;
if ((enemyPos - transform.position).sqrMagnitude < attackRange * attackRange)
{
Vector3 toTarget = (enemyPos - transform.position).normalized;
if (Mathf.Abs(Vector3.Dot(transform.forward, toTarget) - Mathf.Cos(attackRange * 0.5f)) < 0.3f && attack_2 == true)
{
enemy.Hit(1.5f);
}
else
{
enemy.Hit(0.5f);
}
}
}
foreach (var enemy in YakuBasic.Instances)
{
var enemyPos = enemy.transform.position;
if ((enemyPos - transform.position).sqrMagnitude < attackRange * attackRange)
{
Vector3 toTarget = (enemyPos - transform.position).normalized;
if (Mathf.Abs(Vector3.Dot(transform.forward, toTarget) - Mathf.Cos(attackRange * 0.5f)) < 0.3f && attack_2 == true)
{
enemy.Hit(1.5f);
}
else
{
enemy.Hit(0.5f);
}
}
}
}
public void PlayIdle()
{
animator.CrossFade("idle",0.1f);
}
public void PlayRun()
{
animator.CrossFade("run", 0.1f);
}
public void PlayAttack()
{
foreach(var trail in trailRenderers)
{
trail.SetActive(true);
}
animator.CrossFade("attack", 0.1f);
}
public void PlayRoller()
{
animator.Play("place roll");
}
public void PlayDie()
{
animator.CrossFade("die 2", 0.1f);
}
public void PlayImpact()
{
animator.Play("impact");
}
public void PlayLestGo()
{
animator.Play("lets");
}
public void PlayAttackTwo()
{
foreach (var trail in trailKicks)
{
trail.SetActive(true);
}
animator.CrossFade("attack 2",0.1f);
}
public void OnTriggerStay(Collider other)
{
if (other.CompareTag("Terrain"))
{
To_Jump = true;
}
}
public void OnTriggerExit(Collider other)
{
To_Jump = false;
}
public void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Plasma"))
{
UnityEngine.Debug.Log("Collider with Plasma");
panelMision.SetActive(true);
StartCoroutine(CountTextMision());
}
}
IEnumerator CountTextMision()
{
yield return new WaitForSecondsRealtime(6);
panelMision.SetActive(false);
}
IEnumerator PlayInitAnimation()
{
yield return new WaitForSeconds(19.0f);
yield return new WaitForEndOfFrame();
SetState(PlayerState.LetsGo);
}
IEnumerator WaitSoundOver()
{
yield return new WaitForSeconds(0.5f);
soundsEkard.PlayOneShot(soundDeadEkard,10.0f);
yield return new WaitForSeconds(3.0f);
soundsEkard.PlayOneShot(soundGameOver, 0.5f);
panelLost.SetActive(true);
}
IEnumerator ButtonsActive()
{
yield return new WaitForSeconds(40);
buttonExit.SetActive(true);
buttonMenu.SetActive(true);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UI;
public class SkeletonBasic : MonoBehaviour
{
[SerializeField] public static List<SkeletonBasic> Instances = new List<SkeletonBasic>();
public enum EnemyState
{
Idle,
Run,
Chase,
Attack,
Die
}
EnemyState state;
public bool isAlive { get { return maxHealth > 0; } }
[SerializeField] Animator animator = null;
[SerializeField] NavMeshAgent agent = null;
[SerializeField] AnimationTarget _animTarget = null;
[SerializeField] float maxHealth = 4;
[SerializeField] float currentHealth;
[SerializeField] Slider slider;
[SerializeField] float vision = 10.0f;
[SerializeField] List<Transform> path = new List<Transform>();
[SerializeField] PlayerHealth playerHealth = null;
int currentPath = 0;
[SerializeField] AudioSource soundsSkeleton;
[SerializeField] AudioClip swordPlay;
[SerializeField] AudioClip soundDamageSkeleton;
public static int countSkeletons;
//public static Transform enemy = null;
private void Awake()
{
Instances.Add(this);
currentHealth = maxHealth;
slider.maxValue = maxHealth;
slider.value = slider.maxValue;
soundsSkeleton = GetComponent<AudioSource>();
}
// Start is called before the first frame update
void Start()
{
Debug.Log("Max Value is " + maxHealth);
if (animator == null)
{
animator = GetComponent<Animator>() ?? GetComponentInChildren<Animator>();
}
if (agent == null)
{
agent = GetComponent<NavMeshAgent>() ?? GetComponentInChildren<NavMeshAgent>();
}
_animTarget.OnAnimationEvent += OnAnimationEvent;
//SetState(EnemyState.Idle);
agent.SetDestination(path[currentPath].position);
SetState(EnemyState.Run);
}
private void OnAnimationEvent(string obj)
{
switch(obj)
{
case "AttackDamage":
AttackDamage();
break;
case "AttackEnd":
AttackEnd();
break;
}
}
// Update is called once per frame
void Update()
{
if (state == EnemyState.Die)
{
return;
}
var player = EkardController.Instance;
var posEkard = player.transform.position;
var distance = (posEkard - transform.position).sqrMagnitude;
if (playerHealth.currentHealth > 0 && distance < 1.5f * 1.5f)
{
SetState(EnemyState.Attack);
transform.LookAt(posEkard);
}
else if (playerHealth.currentHealth > 0 && distance < vision * vision)
{
agent.SetDestination(posEkard);
transform.LookAt(posEkard);
SetState(EnemyState.Chase);
}
else if (Vector3.Distance(transform.position,path[currentPath].position) < 1f)
{
currentPath++;
if (currentPath >= path.Count)
{
currentPath = 0;
}
agent.SetDestination(path[currentPath].position);
}
if ((state == EnemyState.Attack || state == EnemyState.Chase) && playerHealth.currentHealth < 1)
{
SetState(EnemyState.Run);
agent.SetDestination(path[currentPath].position);
}
}
void SetState(EnemyState newState)
{
if (state == newState)
{
return;
}
switch (newState)
{
case EnemyState.Idle:
agent.isStopped = true;
PlayIdle();
break;
case EnemyState.Run:
agent.isStopped = false;
PlayRun();
break;
case EnemyState.Chase:
agent.isStopped = false;
PlayRun();
break;
case EnemyState.Attack:
agent.isStopped = true;
PlayAttack();
break;
case EnemyState.Die:
agent.isStopped = true;
PlayDie();
break;
}
state = newState;
}
public void Hit(float hit)
{
Debug.Log("auch");
slider.value -= hit;
currentHealth -= hit;
if(currentHealth <= 0)
{
SetState(EnemyState.Die);
slider.gameObject.SetActive(false);
}
}
public void AttackEnd()
{
SetState(EnemyState.Idle);
UnityEngine.Debug.Log("Acabé de atacar");
}
public void AttackDamage()
{
var player = EkardController.Instance;
var posEkard = player.transform.position;
var distance = (posEkard - transform.position).sqrMagnitude;
if (playerHealth.currentHealth > 0 && distance < 1.5f * 1.5f)
{
EkardController.Instance.Hit(1);
}
UnityEngine.Debug.Log("Hatsa");
}
public void PlayIdle()
{
animator.CrossFade("idle", 0.1f);
}
public void PlayRun()
{
animator.CrossFade("run", 0.1f);
}
public void PlayAttack()
{
animator.CrossFade("attack", 0.1f);
}
public void PlayDie()
{
GetComponentInChildren<Collider>().enabled = false;
animator.CrossFade("die", 0.1f);
soundsSkeleton.PlayOneShot(soundDamageSkeleton,2.5f);
StartCoroutine(KilledCoroutine());
countSkeletons += 1;
UnityEngine.Debug.Log("Skeletons Die = " + countSkeletons);
}
IEnumerator KilledCoroutine()
{
yield return new WaitForEndOfFrame();
Instances.Remove(this);
agent.enabled = false;
float duration = 2f;
yield return new WaitForSeconds(1f);
while(duration > 0f)
{
transform.position = transform.position - Vector3.up * 0.5f * Time.deltaTime;
yield return null;
duration -= Time.deltaTime;
}
Destroy(gameObject);
}
private void OnDrawGizmos()
{
//Gizmos.DrawWireSphere(transform.position, vision);
for (int i = 1; i < path.Count; ++i)
{
Gizmos.DrawLine(path[i - 1].position, path[i].position);
}
if (path.Count > 1)
{
Gizmos.DrawLine(path[path.Count - 1].position, path[0].position);
}
}
}
Thanks for adding the code tags, it’s so much easier to read. But, I’m not sure did you read the rest of my response? There is nothing to change. You have a static variable, it’s still maintaining references to things in your scene, so it breaks. You either need to clear your list when you restart the scene or don’t use a static variable.
Thank you very much for your help and for the comments you have made to me, in fact I had to remove the instance when reloading the scene, I did this with the help of the boolean variable that detects if my player is alive, for which the following sentence added in my enemy’s update method solved the problem. Thank you very much.
if (EkardController.isAlive == false)
{
Instances.Remove(this);
}