Forum begins after the advertisement:
[Part 3] Enemy cant take damage
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [Part 3] Enemy cant take damage
- This topic has 0 replies, 2 voices, and was last updated 1 week ago by
Ser Apustaja.
-
AuthorPosts
-
September 28, 2025 at 8:14 am #18859::
The enemy cannot take damage. In the third part of the Metroid game, I copied the author’s code, and the console displayed the text “Null Reference Exception.” The enemy’s health is not being depleted
PlayerMovement Code:
using System.Collections; using System.Runtime.CompilerServices; using UnityEngine; public class PlayerMovement : MonoBehaviour { [Header("Horizontal Input Settings:")] [SerializeField] private float walkSpeed = 1; [Header("Vertical Movment Settings:")] [SerializeField] private float jumpForce = 45f; private float jumpBufferCounter; [SerializeField] private float jumpBufferFrames; private float coyotTimeCounter = 0; [SerializeField] private float coyotTime; private int airJumpCounter = 0; [SerializeField] private int maxAirJumps; [Header("Grounde Check Settings:")] [SerializeField] private Transform groundCheckPoint; [SerializeField] private float groundCheckY = 0.2f; [SerializeField] private float groundCheckX = 0.5f; [SerializeField] private LayerMask whatIsGround; [Header("Dash Settings:")] [SerializeField] private float dashSpeed; [SerializeField] private float dashTime; [SerializeField] private float dashCooldown; [Header("Attack Settings:")] private bool attack = false; float timeBetweenAttack, timeSinceAttack; [SerializeField] Transform SideAttackTransform, UpAttackTransform, DownAttackTransform; [SerializeField] Vector2 SideAttackArea, UpAttackArea, DownAttackArea; [SerializeField] LayerMask attackableLayer; [SerializeField] float damage; [SerializeField] GameObject slashEffect; PlayerStateList pState; private Rigidbody2D rb; private float xAxis, yAxis; private float gravity; Animator anim; private bool canDash = true; private bool dashed; public static PlayerMovement Instance; private void Start() { rb = GetComponent<Rigidbody2D>(); anim = GetComponent<Animator>(); pState = GetComponent<PlayerStateList>(); gravity = rb.gravityScale; if (Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } } private void Awake() { } private void OnDrawGizmos() { Gizmos.color = Color.red; Gizmos.DrawWireCube(SideAttackTransform.position, SideAttackArea); Gizmos.DrawWireCube(UpAttackTransform.position, UpAttackArea); Gizmos.DrawWireCube(DownAttackTransform.position, DownAttackArea); } private void Update() { GetInputs(); UpdateJumpVariables(); if (pState.dashing) return; Flip(); Move(); Jump(); StartDash(); Attack(); } private void GetInputs() { xAxis = Input.GetAxisRaw("Horizontal"); yAxis = Input.GetAxisRaw("Vertical"); attack = Input.GetMouseButtonDown(0); } private void Flip() { if (xAxis > 0) { transform.localScale = new Vector3(1, 1, 1); } if (xAxis < 0) { transform.localScale = new Vector3(-1, 1, 1); } } void StartDash() { if (Input.GetButtonDown("Dash") && canDash && !dashed) { StartCoroutine(Dash()); dashed = true; } if (Grounded()) { dashed = false; } } IEnumerator Dash() { canDash = false; pState.dashing = true; anim.SetTrigger("Dashing"); rb.gravityScale = 0; rb.linearVelocity = new Vector2(transform.localScale.x * dashSpeed, 0); yield return new WaitForSeconds(dashTime); rb.gravityScale = gravity; pState.dashing = false; yield return new WaitForSeconds(dashCooldown); canDash = true; } void Attack() { timeSinceAttack += Time.time; if (attack && timeSinceAttack >= timeBetweenAttack) { timeSinceAttack = 0; anim.SetTrigger("Attacking"); if (yAxis == 0 && yAxis < 0 && Grounded()) { Hit(SideAttackTransform, SideAttackArea); Instantiate(slashEffect, SideAttackTransform); } else if (yAxis > 0) { Hit(UpAttackTransform, UpAttackArea); SlashEffectAtAngle(slashEffect, 90, UpAttackTransform); } else if (yAxis < 0 && !Grounded()) { Hit(DownAttackTransform, DownAttackArea); SlashEffectAtAngle(slashEffect, -90, DownAttackTransform); } } } private void Hit(Transform _attackTransform, Vector2 _attackArea) { Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer); if(objectsToHit.Length > 0) { Debug.Log("Hit"); } for (int i = 0; i < objectsToHit.Length; i++) { print("Found " + objectsToHit[i].name); if (objectsToHit[i].GetComponent<Enemy>() != null) { print("Hitting " + objectsToHit[i].name); objectsToHit[i].GetComponent<Enemy>().EnemyHit(damage); } } } void SlashEffectAtAngle(GameObject _slashEffect, int _effectAngle, Transform _attackTransform) { _slashEffect = Instantiate(_slashEffect, _attackTransform); _slashEffect.transform.eulerAngles = new Vector3(0, 0, _effectAngle); _slashEffect.transform.localScale = new Vector2(transform.localScale.x, transform.localScale.y); } private void Move() { rb.linearVelocity = new Vector2(xAxis * walkSpeed, rb.linearVelocity.y); anim.SetBool("Walking", rb.linearVelocity.x != 0 && Grounded()); } public bool Grounded() { if(Physics2D.Raycast(groundCheckPoint.position, Vector2.down, groundCheckY, whatIsGround) || Physics2D.Raycast(groundCheckPoint.position + new Vector3(groundCheckX, 0, 0), Vector2.down, groundCheckY, whatIsGround) || Physics2D.Raycast(groundCheckPoint.position + new Vector3(-groundCheckX, 0, 0), Vector2.down, groundCheckY, whatIsGround)) { return true; } else { return false; } } private void Jump() { if (Input.GetButtonUp("Jump")) { rb.linearVelocity = new Vector2(rb.linearVelocity.x, 0); pState.jumping = false; } if (!pState.jumping) { if (jumpBufferCounter > 0 && coyotTimeCounter > 0) { rb.linearVelocity = new Vector2(rb.linearVelocity.x, jumpForce); pState.jumping = true; } else if (!Grounded() && airJumpCounter < maxAirJumps && Input.GetButtonDown("Jump")) { pState.jumping = true; airJumpCounter++; rb.linearVelocity = new Vector2(rb.linearVelocity.x, jumpForce); } } anim.SetBool("Jumping", !Grounded()); } private void UpdateJumpVariables() { if (Grounded()) { pState.jumping = false; coyotTimeCounter = coyotTime; airJumpCounter = 0; } else { coyotTimeCounter -= Time.deltaTime; } if (Input.GetButtonDown("Jump")) { jumpBufferCounter = jumpBufferFrames; } else { jumpBufferCounter = jumpBufferCounter - Time.deltaTime * 10; } } }
Enemy Code:
using UnityEngine; public class Enemy : MonoBehaviour { [SerializeField] float health = 10; private void Update() { if (health <= 0) { Destroy(gameObject); } } public void EnemyHit(float _damageDone) { health -= _damageDone; } }
Console text:
NullReferenceException: Object reference not set to an instance of an object UnityEditor.Graphs.Edge.WakeUp () (atf37757a1c985477b9f83ca7c1f4fb00c>:0)
September 28, 2025 at 10:44 pm #18862::It looks like you’re encountering a
Null Reference Exception
which usually indicates that you’re trying to access a member of an object that hasn’t been initialized (i.e., the object isnull
). In your case, since you mentioned that the enemy’s health is not being depleted, let’s focus on theHit
method in yourPlayerMovement
code.Here are a few potential issues to check:
-
Ensure Attackable Layer is Set: Make sure that the enemy GameObject has the correct Layer set, which matches the
attackableLayer
mask in yourPlayerMovement
script. If the enemy is on a layer that is not included inattackableLayer
, it won’t be detected by thePhysics2D.OverlapBoxAll
function. -
Check Collider Setup: Ensure that the enemy GameObject has a Collider2D component and that the attack transform (like
SideAttackTransform
,UpAttackTransform
, etc.) is positioned correctly to overlap with the enemy’s collider when you attack. -
Instantiate Slash Effect: In your
Attack
method, you’re callingInstantiate(slashEffect, SideAttackTransform)
. Ensure thatslashEffect
is assigned in the Inspector, as this could also lead to aNullReferenceException
if it’s not set. -
Debugging the Hit Method: Add some debug logs to help pinpoint where the problem lies. Modify the
Hit
method like this:
private void Hit(Transform _attackTransform, Vector2 _attackArea) { Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer); if (objectsToHit.Length > 0) { Debug.Log("Hit"); for (int i = 0; i < objectsToHit.Length; i++) { Debug.Log("Found " + objectsToHit[i].name); Enemy enemy = objectsToHit[i].GetComponent(); if (enemy != null) { Debug.Log("Hitting " + objectsToHit[i].name); enemy.EnemyHit(damage); } else { Debug.LogWarning("Found object does not have an Enemy component: " + objectsToHit[i].name); } } } }
-
Check Player State List: Make sure that the
PlayerStateList
component is correctly attached to the player GameObject. IfpState
isnull
, it will cause issues when you checkpState.dashing
. -
Handling the Null Reference Exception: The error message regarding
NullReferenceException
fromUnityEditor.Graphs.Edge.WakeUp
seems unrelated to your game logic and might be a part of Unity’s editor scripts or your project setup. If the game runs fine despite this error, it might not be critical. Ensure all your scripts are properly linked and referenced in the Unity Editor.
After checking these points, try running your game again and see if the enemy’s health starts depleting or if the console gives you more information about the source of the error.
-
-
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: