Forum begins after the advertisement:
Animator/Game freezes when trying to dash towards an enemy
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › Animator/Game freezes when trying to dash towards an enemy
- This topic has 0 replies, 2 voices, and was last updated 2 days, 20 hours ago by
Ser Apustaja.
-
AuthorPosts
-
March 7, 2026 at 4:00 am #19269::
When trying to dash towards an enemy, the game freezes. The unity console didn’t show any error message.
The animator is pretty much the same at the one in the video. Part 4 of the series
Animator transitions:
View post on imgur.com
Here’s my code for the player script:
using System.Collections; using System.Collections.Generic; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.Events;
public class PlayerController : MonoBehaviour { [Header(“Ground/Animations Configs”)] public float fallMultiplier = 4f; public float lowJumpMultiplier = 3f;
[Header("Horizontal Movement Settings")] [SerializeField] private float walkSpeed = 1; [Space(5)] [SerializeField] private float jumpForce = 6; //Default 6 private float jumpBufferCounter = 0; [SerializeField] private float jumpBufferFrames; private float graceTimeCounter = 0; [SerializeField] private float graceTime; private int airJumpCounter = 0; [SerializeField] private int maxAirJumps; [Space(5)] [Header("Ground Check Settings")] [SerializeField] private Transform groundCheckPoint; [SerializeField] private float groundCheckY = 0.2f; [SerializeField] private float groundCheckX = 0.5f; [SerializeField] private LayerMask whatIsGround; [Space(5)] [Header("Dash option")] [SerializeField] private float dashSpeed; [SerializeField] private float dashTime; [SerializeField] private float dashCooldown; [SerializeField] GameObject dashEffect; [Space(5)] [Header("Attack settings")] private bool attack = false; private float timeSinceAttack; [SerializeField] Transform SideAttackTransform; [SerializeField] Vector2 SideAttackArea; [SerializeField] Transform UpAttackTransform; [SerializeField] Vector2 UpAttackArea; [SerializeField] Transform DownAttackTransform; [SerializeField] Vector2 DownAttackArea; [SerializeField] LayerMask attackableLayer; [SerializeField] float damage; [SerializeField] private float timeBetweenAttack; [SerializeField] GameObject slashEffect; [SerializeField] GameObject slashEffectUp; [SerializeField] GameObject slashEffectDown; bool restoreTime; float restoreTimeSpeed; [Space(5)] [Header("Recoil")] [SerializeField] int recoilXSteps = 5; [SerializeField] int recoilYSteps = 5; [SerializeField] float recoilXSpeed = 100; [SerializeField] float recoilYSpeed = 100; int stepsXRecoiled, stepsYRecoiled; [Space(5)] [Header("Health settings")] public int health; public int maxHealth; [SerializeField] GameObject bloodSpurt; [SerializeField] float hitFlashSpeed; [Space(5)] [HideInInspector ] public PlayerStateList pState; private Rigidbody2D rb; private SpriteRenderer sr; private float xAxis, yAxis; private float gravity; Animator anim; private bool canDash = true; private bool dashed; public static PlayerController Instance; private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } Health = maxHealth; } void Start() { pState = GetComponent<PlayerStateList>(); rb = GetComponent<Rigidbody2D>(); sr = GetComponent<SpriteRenderer>(); anim = GetComponent<Animator>(); gravity = rb.gravityScale; } private void OnDrawGizmos() { Gizmos.color = Color.red; Gizmos.DrawWireCube(SideAttackTransform.position, SideAttackArea); Gizmos.DrawWireCube(UpAttackTransform.position, UpAttackArea); Gizmos.DrawWireCube(DownAttackTransform.position, DownAttackArea); } // Update is called once per frame void Update() { GetInputs(); UpdateJumpVariables(); if (pState.dashing) return; Flip(); Move(); Jump(); ApplyBetterJumpPhysics(); StartDash(); Attack(); RestoreTimeScale(); FlashWhileInvincible(); //Testing //Respawn(); } private void FixedUpdate() { if (pState.dashing) return; Recoil(); } void GetInputs() { xAxis = Input.GetAxisRaw("Horizontal"); yAxis = Input.GetAxisRaw("Vertical"); attack = Input.GetButtonDown("Attack"); } void Flip() { if (xAxis < 0) { transform.localScale = new Vector2(-Mathf.Abs(transform.localScale.x), transform.localScale.y); //transform.eulerAngles = new Vector2(0, 180); pState.lookingRight = false; } else if (xAxis > 0) { transform.localScale = new Vector2(Mathf.Abs(transform.localScale.x), transform.localScale.y); //transform.eulerAngles = new Vector2(0, 0); pState.lookingRight = true; } } private void Move() { rb.linearVelocity = new Vector2(walkSpeed * xAxis, rb.linearVelocity.y); anim.SetBool("Walking", rb.linearVelocity.x !=0 && Grounded()); } 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); if (Grounded()) Instantiate(dashEffect, transform); yield return new WaitForSeconds(dashTime); rb.gravityScale = gravity; pState.dashing = false; yield return new WaitForSeconds(dashCooldown); canDash = true; } void Attack() { timeSinceAttack += Time.deltaTime; if (attack && timeSinceAttack >= timeBetweenAttack) { timeSinceAttack = 0; anim.SetTrigger("Attacking"); if (yAxis == 0 || yAxis < 0 && Grounded()) { Hit(SideAttackTransform, SideAttackArea, ref pState.recoilingX, recoilXSpeed); Instantiate(slashEffect, SideAttackTransform); } else if (yAxis > 0) { Hit(UpAttackTransform, UpAttackArea, ref pState.recoilingY, recoilYSpeed); //SlashEffectAtAngle(slashEffect, 90, UpAttackTransform); Instantiate(slashEffectUp, UpAttackTransform); } else if (yAxis < 0 && !Grounded()) { Hit(DownAttackTransform, DownAttackArea, ref pState.recoilingY, recoilYSpeed); //SlashEffectAtAngle(slashEffectUp, -90, DownAttackTransform); Instantiate(slashEffectDown, DownAttackTransform); } } } private void Hit(Transform _attackTransform, Vector2 _attackArea, ref bool _recoilDir, float _recoilStrength) { Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer); List<Enemy> hitEnemies = new List<Enemy>(); if (objectsToHit.Length > 0) { //Debug.Log("Hit"); _recoilDir = true; } for (int i=0; i < objectsToHit.Length; i++) { Enemy e = objectsToHit[i].GetComponent<Enemy>(); if (e && !hitEnemies.Contains(e)) { e.EnemyHit(damage, (_attackTransform.position - objectsToHit[i].transform.position).normalized, _recoilStrength); hitEnemies.Add(e); } } } 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); } void Recoil() { if (pState.recoilingX) { if (pState.lookingRight) { rb.linearVelocity = new Vector2 (-recoilXSpeed, 0); } else { rb.linearVelocity = new Vector2 (recoilXSpeed, 0); } } if (pState.recoilingY) { if (yAxis < 0) { rb.gravityScale = 0; rb.linearVelocity = new Vector2(rb.linearVelocity.x, recoilYSpeed); } else { rb.linearVelocity = new Vector2(rb.linearVelocity.x, -recoilYSpeed); } airJumpCounter = 0; } else { rb.gravityScale = gravity; } //stop recoil if (pState.recoilingX && stepsXRecoiled < recoilXSteps) { stepsXRecoiled++; } else { StopRecoilX(); } if (pState.recoilingY && stepsYRecoiled < recoilYSteps) { stepsYRecoiled++; } else { StopRecoilY(); } if (Grounded()) { StopRecoilY(); } } void StopRecoilX() { stepsXRecoiled = 0; pState.recoilingX = false; } void StopRecoilY() { stepsYRecoiled = 0; pState.recoilingY = false; } public void TakeDamage(float _damage) { Health -= Mathf.RoundToInt(_damage); StartCoroutine(StopTakingDamage()); } IEnumerator StopTakingDamage() { pState.invincible = true; GameObject _bloodSpurtParticles = Instantiate(bloodSpurt, UpAttackTransform.position, Quaternion.identity); Destroy(_bloodSpurtParticles, 1.5f); anim.SetTrigger("TakeDamage"); yield return new WaitForSeconds(1f); pState.invincible = false; } void FlashWhileInvincible() { sr.material.color =pState.invincible ? Color.Lerp(Color.white, Color.black, Mathf.PingPong(Time.time * hitFlashSpeed, 1.0f)) : Color.white; } void RestoreTimeScale() { if(restoreTime) { if(Time.timeScale < 1) { Time.timeScale += Time.deltaTime * restoreTimeSpeed; } else { Time.timeScale = 1; restoreTime = false; } } } public void HitStopTime(float _newTimeScale, int _restoreSpeed, float _delay) { restoreTimeSpeed = _restoreSpeed; Time.timeScale = _newTimeScale; if (_delay > 0) { StopCoroutine(StartTimeAgain(_delay)); StartCoroutine(StartTimeAgain(_delay)); } else { restoreTime = true; } } IEnumerator StartTimeAgain(float _delay) { restoreTime = true; yield return new WaitForSeconds(_delay); } public int Health { get { return health; } set { if(health != value) { health = Mathf.Clamp(value, 0, maxHealth); } } } //Placeholder //void Respawn() //{ // if (Health <= 0) // { // UnityEngine.SceneManagement.SceneManager.LoadScene(UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex); // } //} 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; } } void Jump() { if (Input.GetButtonUp("Jump")&& rb.linearVelocity.y > 0) { rb.linearVelocity = new Vector2(rb.linearVelocity.x, 0); pState.jumping = false; //pState.falling = false; } if(!pState.jumping) { if (jumpBufferCounter > 0 && graceTimeCounter > 0) { rb.linearVelocity = new Vector3(rb.linearVelocity.x, jumpForce); pState.jumping = true; } else if(!Grounded() && airJumpCounter < maxAirJumps && Input.GetButtonDown("Jump")) { pState.jumping = true; airJumpCounter++; rb.linearVelocity = new Vector3(rb.linearVelocity.x, jumpForce); } } anim.SetBool("Jumping", !Grounded()); // Diferenciar entre subida y caÃda con un umbral //*if (!Grounded()) //{ // if (rb.linearVelocity.y < -4f) // <- umbral para evitar caÃdas muy pequeñas // { // anim.SetBool("Falling", true); // animación de caÃda // } // else // { /// anim.SetBool("Falling", false); // aún en subida o caÃda leve // } //} //else //{ // anim.SetBool("Jumping", false); //}// }
void UpdateJumpVariables() { if (Grounded()) { pState.jumping = false; graceTimeCounter = graceTime; airJumpCounter = 0; } else { graceTimeCounter -= Time.deltaTime; } if (Input.GetButtonDown("Jump")) { jumpBufferCounter = jumpBufferFrames; } else { jumpBufferCounter = jumpBufferCounter - Time.deltaTime * 10; } } void ApplyBetterJumpPhysics() { // Si está cayendo, aplicar multiplicador de caÃda if (rb.linearVelocity.y < 0) { rb.linearVelocity += Vector2.up * Physics2D.gravity.y * (fallMultiplier - 1) * Time.deltaTime; } // Si está subiendo pero se soltó el botón de salto, aplicar lowJumpMultiplier else if (rb.linearVelocity.y > 0 && !Input.GetButton("Jump")) { rb.linearVelocity += Vector2.up * Physics2D.gravity.y * (lowJumpMultiplier - 1) * Time.deltaTime; } }}
March 7, 2026 at 5:00 am #19270::It sounds like you’re experiencing a freeze in your game when you attempt to dash towards an enemy, but there are no error messages in the Unity console. Here are some potential issues and solutions you can look into:
1. Animator State Issues
Verify that your animator transitions are correctly set up. If the
Dashingtrigger is set, but the animator does not have a corresponding transition or the transition conditions are incorrect, it may cause the game to freeze. Ensure that:- The Dashing state has an exit transition back to the idle or walking state.
- The transitions are not set to
Has Exit Timeunless you want them to wait until the animation finishes.
2. Coroutine Issues
Make sure that the
Dashcoroutine is being correctly executed. If you attempt to start the dash while it is already running, it could cause issues. You can add debug logs to see if the coroutine is being called multiple times unintentionally.For example, modify your
StartDashmethod:void StartDash() { if (Input.GetButtonDown("Dash") && canDash && !dashed) { Debug.Log("Starting Dash"); StartCoroutine(Dash()); dashed = true; } if (Grounded()) { dashed = false; } }3. Rigidbody2D Properties
Check the Rigidbody2D component on your player object:
- Ensure that
Is Kinematicis not checked. A kinematic Rigidbody will not react to forces and could cause unexpected behavior. - Check the
Gravity Scale. It should be a positive value to ensure your character falls.
4. Layer Masks and Collision
Make sure that the
whatIsGroundlayer mask is set up correctly. If the ground check is not functioning properly, it could lead to unexpected behavior when dashing. Check if dashing interacts with any colliders that could potentially cause issues.5. Dash Speed and Dash Time
Make sure that your
dashSpeedanddashTimevalues are reasonable. IfdashSpeedis too high, it could cause the player to move through colliders, potentially leading to a freeze if the player continuously collides with the enemy or other objects.6. Debugging Collisions
Add some debug logs to the
Dashmethod to see if the player is colliding with anything during the dash:IEnumerator Dash() { canDash = false; pState.dashing = true; anim.SetTrigger("Dashing"); rb.gravityScale = 0; rb.velocity = new Vector2(transform.localScale.x * dashSpeed, 0); if (Grounded()) Instantiate(dashEffect, transform); yield return new WaitForSeconds(dashTime); rb.gravityScale = gravity; pState.dashing = false; yield return new WaitForSeconds(dashCooldown); canDash = true; Debug.Log("Dash completed"); }7. Check for Infinite Loops
Make sure that you do not have any infinite loops in your code, especially in the
Hitmethod or during collision checks. If you are spawning enemies or effects during the dash, ensure that their spawning logic does not interact with the player’s dash state in a way that could cause a loop.Conclusion
If you’ve checked all of the above and the issue persists, try to isolate the problem by simplifying your dash logic or temporarily disabling other features to see if the problem goes away. Additionally, using debug logs throughout your code can help you find where the freeze occurs.
Let me know if you need further assistance!
-
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: