Forum begins after the advertisement:
[Part 10] Boss hit very fast and Null ref
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [Part 10] Boss hit very fast and Null ref
- This topic has 26 replies, 3 voices, and was last updated 1 week, 4 days ago by Terence.
-
AuthorPosts
-
November 18, 2024 at 3:33 am #16384::
So i was making the boss for the game. And when I making the boss event and test the 3 hit function. My boss hit very fast. As we could said it doesn’t reset the animator. It just 2 punch in a frame. And when the boss hit, the console send a message of NullReference. As you can see in what i show below. First is the test video
then is the code. First is the CorruptedMonk.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CorruptedMonk : Enemy { public static CorruptedMonk Instance; [Header("Attacking setting")] [SerializeField] public Transform sideAttackTransform, upAttackTransform, downAttackTransform; [SerializeField] public Vector2 sideAttackArea, upAttackArea, downAttackArea; [Space(5)] public float attackRange; public float attackTimer; [Header("Groundcheck setting")] [SerializeField] private Transform groundcheck; [SerializeField] private float groundchecky = 0.2f; [SerializeField] private float groundcheckx = 0.5f; [SerializeField] private LayerMask isground; int hitCounter; bool stunned, canStunned; bool alive; [HideInInspector] public float runSpeed; [HideInInspector] public bool facingRight; private void Awake() { if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } } // Start is called before the first frame update protected override void Start() { base.Start(); Sr = GetComponentInChildren<SpriteRenderer>(); anim = GetComponentInChildren<Animator>(); ChangeState(EnemyStates.Monk_State1); alive = true; } public bool isonGround() { if (Physics2D.Raycast(groundcheck.position, Vector2.down, groundchecky, isground) || Physics2D.Raycast(groundcheck.position + new Vector3(groundcheckx, 0, 0), Vector2.down, groundchecky, isground) || Physics2D.Raycast(groundcheck.position + new Vector3(-groundcheckx, 0, 0), Vector2.down, groundchecky, isground) ) { return true; } else { return false; } } private void OnDrawGizmos() { Gizmos.color = Color.yellow; Gizmos.DrawWireCube(sideAttackTransform.position, sideAttackArea); Gizmos.DrawWireCube(upAttackTransform.position, upAttackArea); Gizmos.DrawWireCube(downAttackTransform.position, downAttackArea); } // Update is called once per frame protected override void Update() { base.Update(); if (!attacking) { attackCountdown -= Time.deltaTime; } } public void Flip() { if (Move.Instance.transform.position.x < transform.position.x && transform.localScale.x > 0) { transform.eulerAngles = new Vector2(transform.eulerAngles.x, 180); facingRight = false; } else { transform.eulerAngles = new Vector2(transform.eulerAngles.x, 0); facingRight = true; } } protected override void UpdateEnemyStates() { if(Move.Instance != null) { switch (GetCurrentEnemyStates) { case EnemyStates.Monk_State1: break; case EnemyStates.Monk_State2: break; case EnemyStates.Monk_State3: break; case EnemyStates.Monk_State4: break; } } } protected override void OnCollisionStay2D(Collision2D _other) { } public void ResetAllAttack() { attacking = false; StopCoroutine(TriplePunch()); } #region attacking #region variables [HideInInspector] public bool attacking; [HideInInspector] public float attackCountdown; #endregion #region Control public void AttackHandler() { if(currentState == EnemyStates.Monk_State1) { if(Vector2.Distance(Move.Instance.transform.position,rb.position) <= attackRange) { StartCoroutine(TriplePunch()); } else { return; } } } #endregion #region Stage1 IEnumerator TriplePunch() { attacking = true; rb.velocity = Vector2.zero; anim.SetTrigger("Punch"); yield return new WaitForSeconds(0.3f); anim.ResetTrigger("Punch"); anim.SetTrigger("Punch"); yield return new WaitForSeconds(0.5f); anim.ResetTrigger("Punch"); anim.SetTrigger("Punch"); yield return new WaitForSeconds(0.1f); anim.ResetTrigger("Punch"); ResetAllAttack(); } #endregion #endregion }
Then is the Corrupted_Monk_Event.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Corrupted_Monk_Event : MonoBehaviour { void PunchDamagePlayer() { if (Move.Instance.transform.position.x > transform.position.x || Move.Instance.transform.position.x < transform.position.x) { Hit(CorruptedMonk.Instance.sideAttackTransform, CorruptedMonk.Instance.sideAttackArea); } else if (Move.Instance.transform.position.y > transform.position.y) { Hit(CorruptedMonk.Instance.upAttackTransform, CorruptedMonk.Instance.upAttackArea); } else if (Move.Instance.transform.position.y < transform.position.y) { Hit(CorruptedMonk.Instance.downAttackTransform, CorruptedMonk.Instance.downAttackArea); } } void Hit(Transform _attackTrasnform, Vector2 _attackArea) { Collider2D[] _objectToHit = Physics2D.OverlapBoxAll(_attackTrasnform.position, _attackArea, 0); for(int i = 0 ; i < _objectToHit.Length; i++) { if (_objectToHit[i].GetComponent<Collider2D>() != null) { _objectToHit[i].GetComponent<Move>().takeDmg(CorruptedMonk.Instance.dmgMake); } } } }
I even try to change from WaitForSecond to WaitForSecondRealTime but still doesn’t making the punch slow down. Tks you for the series. And another thank for helping me
November 18, 2024 at 3:53 am #16385::Update: I add a debug to check how many punch the boss does and it only make 3 punch. So the Boss still hitting 3 hit. But i got 6 damage and the boss doesn’t need to reset animation at all
and the null ref i already fix it. The getcomponent at the event first getcomponent i just took it wrong. From PlayerController to collider2d. It my fault. It kinda late in the time I made it so maybe my eyes has lied me.November 18, 2024 at 7:15 pm #16399::I really need help here. I making the diving pillar skill and the boss. It jump to the sky and dive down. But when he create the pilar. I only see that he only create one pillar only. And the pillar making multiple time damage to my player and my player get oneshot instead of only two damaga. If you need me to provide anything, just reply and I will give it ASAP.
November 20, 2024 at 11:27 am #16449::Let’s start by fixing the NullReferenceException here:
The issue appears to be with line 29 of the
Corrupted_Monk_Event
script:public class Corrupted_Monk_Event : MonoBehaviour { void PunchDamagePlayer() { if (Move.Instance.transform.position.x > transform.position.x || Move.Instance.transform.position.x < transform.position.x) { Hit(CorruptedMonk.Instance.sideAttackTransform, CorruptedMonk.Instance.sideAttackArea); } else if (Move.Instance.transform.position.y > transform.position.y) { Hit(CorruptedMonk.Instance.upAttackTransform, CorruptedMonk.Instance.upAttackArea); } else if (Move.Instance.transform.position.y < transform.position.y) { Hit(CorruptedMonk.Instance.downAttackTransform, CorruptedMonk.Instance.downAttackArea); } } void Hit(Transform _attackTrasnform, Vector2 _attackArea) { Collider2D[] _objectToHit = Physics2D.OverlapBoxAll(_attackTrasnform.position, _attackArea, 0); for(int i = 0 ; i < _objectToHit.Length; i++) { if (_objectToHit[i].GetComponent<Collider2D>() != null) { _objectToHit[i].GetComponent<Move>().takeDmg(CorruptedMonk.Instance.dmgMake); } } } }
Do you have a Move component attached to your boss?
November 20, 2024 at 5:35 pm #16464::So about the null references, I has already fix it but forgot to write the update on here. it was my mistake that calling this
_objectToHit[i].GetComponent<Collider2D>()
instead of_objectToHit[i].GetComponent<Move>()
I has change and it look good. Now the problem is only the pillar doesn’t spawn right and the dmg it make. I will show you a record of itAs you could see in the record. The pillar is spawn in a random patten and sometime move very far the player. But when it hit, it make about 10 time hits that you could see in the console in just a tic. Here is the script of the water pillar Diving pillar.cs
public class DivingPillar : MonoBehaviour { // Start is called before the first frame update private void OnTriggerEnter2D(Collider2D collision) { if (collision.CompareTag("Player")) { Debug.Log("Player hit by pillar!"); collision.GetComponent<Move>().takeDmg(CorruptedMonk.Instance.dmgMake); Debug.Log($"Player health after hit: {collision.GetComponent<Move>().health}"); } } }
boss_flyingkick.cs in the flyingkick animator
public class Boss_FlyingKick : StateMachineBehaviour { Rigidbody2D rb; bool callOnce; // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { rb = animator.GetComponentInParent<Rigidbody2D>(); } // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { CorruptedMonk.Instance.divingCollider.SetActive(true); if (CorruptedMonk.Instance.isonGround()) { CorruptedMonk.Instance.divingCollider.SetActive(false); if (!callOnce) { CorruptedMonk.Instance.DivingPillar(); animator.SetBool("FlyingKick", false); CorruptedMonk.Instance.ResetAllAttack(); callOnce = true; } } } // OnStateExit is called when a transition ends and the state machine finishes evaluating this state override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { callOnce = false; } }
Boss_jump.cs
public class Boss_Jump : StateMachineBehaviour { Rigidbody2D rb; // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { rb = animator.GetComponentInParent<Rigidbody2D>(); } // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { DiveAttack(); } void DiveAttack() { if (CorruptedMonk.Instance.flyingKichAttack) { CorruptedMonk.Instance.Flip(); Vector2 _newPos = Vector2.MoveTowards(rb.position, CorruptedMonk.Instance.moveToPosition, CorruptedMonk.Instance.speed * 2 * Time.fixedDeltaTime); rb.MovePosition(_newPos); if (CorruptedMonk.Instance.touchWall()) { CorruptedMonk.Instance.moveToPosition.x = rb.position.x; _newPos = Vector2.MoveTowards(rb.position, CorruptedMonk.Instance.moveToPosition, CorruptedMonk.Instance.speed * 3 * Time.fixedDeltaTime); } float _distance = Vector2.Distance(rb.position, _newPos); if(_distance <0.1f) { CorruptedMonk.Instance.Dive(); } } } // OnStateExit is called when a transition ends and the state machine finishes evaluating this state override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { } }
and the flying kick in the boss script
void FlyingKickAttackJump() { attacking = true ; moveToPosition = new Vector2(Move.Instance.transform.position.x, rb.velocity.y +2); flyingKichAttack = true ; anim.SetBool("Jump", true); } public void Dive() { anim.SetBool("FlyingKick",true); anim.SetBool("Jump", false); } private void OnTriggerEnter2D(Collider2D collision) { if (collision.GetComponent<Move>() != null && flyingKichAttack) { collision.GetComponent<Move>().takeDmg(dmgMake * 2); Move.Instance.playerStateList.recoilingX = true; // Disable the attack to prevent further damage flyingKichAttack = false; } } public void DivingPillar() { if (pillar == null) { Debug.LogError("Pillar prefab is missing!"); return; } Vector2 _impactPoint = groundcheck.position; float _spawnDistance = 3; for (int i = 0; i < 10; i++) { Vector2 _pillarSpawnPointRight = _impactPoint + new Vector2(_spawnDistance, 0); Vector2 _pillarSpawnPointLeft = _impactPoint - new Vector2(_spawnDistance, 0); Debug.Log($"Spawning right pillar at: {_pillarSpawnPointRight}"); Instantiate(pillar, _pillarSpawnPointRight, Quaternion.Euler(0, 0, 0)); Debug.Log($"Spawning left pillar at: {_pillarSpawnPointLeft}"); Instantiate(pillar, _pillarSpawnPointLeft, Quaternion.Euler(0, 0, 0)); _spawnDistance += 2; } ResetAllAttack(); }
November 20, 2024 at 10:41 pm #16465::It seems like all your diving pillars are spawning at the same place. Can you check your Hierarchy to confirm this? Then we will find out why it is.
Add the following as well and show me what it prints on the console:
for (int i = 0; i < 10; i++) { Vector2 _pillarSpawnPointRight = _impactPoint + new Vector2(_spawnDistance, 0); Vector2 _pillarSpawnPointLeft = _impactPoint - new Vector2(_spawnDistance, 0); print($"Diving Pillar {i} has a spawn distance of {_spawnDistance}"); Debug.Log($"Spawning right pillar at: {_pillarSpawnPointRight}"); Instantiate(pillar, _pillarSpawnPointRight, Quaternion.Euler(0, 0, 0)); Debug.Log($"Spawning left pillar at: {_pillarSpawnPointLeft}"); Instantiate(pillar, _pillarSpawnPointLeft, Quaternion.Euler(0, 0, 0)); _spawnDistance += 2; }
November 20, 2024 at 11:03 pm #16467::In the hierachy, yes the boss spawn so much water pillar. As you can see at the below picture
And in the console, this is what it show It up to 9 pillar and the spawn distance of 21November 21, 2024 at 2:17 am #16469::I forgot to write this in previous reply but yes, what you thinkk is right, all the pillar is at the same place. There about more than 15 pillar and I check every single one and it appear in the same place. Stack together
November 21, 2024 at 3:14 pm #16474::Can you check all the Pillars in the Hierarchy and see if they are in the same coordinates? Because in our code we created them in different places, but they are still stacking in the same place.
If we find out why, we will fix your issue.
November 21, 2024 at 5:39 pm #16477::yes, in the inspector, it was the same value in the transform. All have the same value like this when the boss create the pillar
November 23, 2024 at 1:56 pm #16500::Does your console have the “Spawning left pillar at…” and “Spawning right pillar at…” messages?
November 23, 2024 at 5:06 pm #16502::Yes, i have. I was thinking that the number it show up in the console is the x and y position of the pillar. But then when we figure out the pillar is spawn in the same place, the number in the console is different so i dont think it is the x and y position anymore. I will give you a picture later
November 23, 2024 at 6:24 pm #16503::Here is the image in the console with the debug log
and here is the inspector of the water pillar at the same time at the console logDebug.Log($"Spawning right pillar at: {_pillarSpawnPointRight}");
and the leftNovember 25, 2024 at 1:34 am #16537::What should I check next? Do you have any idea yet? I could let you access to my project to checking the problem if you want
November 27, 2024 at 8:01 pm #16567 -
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: