Get 25% off your next order from the Unity Asset Store: YW86GYBU8S.
Forum begins after the advertisement:
[Part 3]Dashing and Enemy Collisions
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [Part 3]Dashing and Enemy Collisions
- This topic has 6 replies, 3 voices, and was last updated 4 hours, 55 minutes ago by
Ser Apustaja.
-
AuthorPosts
-
November 3, 2025 at 8:12 am #18982::
Whenever, I dash into an enemy it sort of glitches out and will also stop time for a really long time. Should I also add my code so that it is easier find the issue? If so, which scripts?
November 3, 2025 at 11:35 pm #18983::You can show the
PlayerControllerscript and explain the issue in a bit more detail, and post a video of the issue as well.I’ll see if the AI helper is able to detect any issue with your code with a quick scan. If not, I’ll look at your video and help you further with it.
November 4, 2025 at 8:30 am #18995::Ok, Here’s the Player Controller Script
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player_Controller : MonoBehaviour { [Header("Horizontal Movement Settings")] [SerializeField] private float WalkSpeed = 1; [Space(5)] [Header("Vertical Movement Settings")] [SerializeField] private float JumpForce = 45; private float Jump_Buffer_Counter; [SerializeField] private float Jump_Buffer_Frames = 0; private float Coyote_Time_Counter; [SerializeField] private float Coyote_Time; private int Air_Jump_Counter = 0; [SerializeField] private int Max_Air_Jumps; [Space(5)] [Header("Ground Check Settings")] [SerializeField] Transform GroundCheckPoint; [SerializeField] private float GroundCheckY = 0.2f; [SerializeField] private float GroundCheckX = 0.5f; [SerializeField] private LayerMask WhatIsGround; [Space(5)] [Header("Dash Settings")] [SerializeField] private float Dash_Speed; [SerializeField] private float Dash_Time; [SerializeField] private float Dash_Cooldown; private bool Can_Dash = true; private bool Dashed; [SerializeField] GameObject Dash_Effect; [Space(5)] [Header("Attack Settings")] [SerializeField] float Time_Between_Attack; float Attack_Time_Counter; [SerializeField] private Transform Side_Attack_Transform; [SerializeField] private Transform Up_Attack_Transform; [SerializeField] private Transform Down_Attack_Transform; [SerializeField] private Vector2 Side_Attack_Area; [SerializeField] private Vector2 Up_Attack_Area; [SerializeField] private Vector2 Down_Attack_Area; [SerializeField] private float Up_Attack_Parameter; [SerializeField] private float Down_Attack_Parameter; [SerializeField] private LayerMask Attackable_Layer; [SerializeField] private float Player_Damage; [SerializeField] GameObject Slash_Effect_Object; bool Attack_Bool = false; bool Restore_Time; float Restore_Time_Speed; [Space(5)] [Header("Recoil Settings")] [SerializeField] int Recoil_X_Steps = 5; [SerializeField] int Recoil_Y_Steps = 5; [SerializeField] int Recoil_X_Speed = 100; [SerializeField] int Recoil_Y_Speed = 100; int Steps_X_Recoiled; int Steps_Y_Recoiled; [Header("Health Settings")] public int Player_Health; public int Player_Max_Health; [SerializeField] GameObject Blood_Spurt; [SerializeField] float Hit_Flash_Speed; public delegate void On_Health_Changed_Delegate(); [HideInInspector] public On_Health_Changed_Delegate On_Health_Changed_Callback; [Space(5)] private Vector3 Mouse_Position; [HideInInspector] public Player_State_List Player_State; private Rigidbody2D Rigidbody; private SpriteRenderer Sprite_Renderer; private float Gravity; private float XAxis; Animator Animator; public static Player_Controller Instance; private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } Player_Health = Player_Max_Health; } // Start is called before the first frame update void Start() { Player_State = GetComponent<Player_State_List>(); Rigidbody = GetComponent<Rigidbody2D>(); Sprite_Renderer = GetComponent<SpriteRenderer>(); Animator = GetComponent<Animator>(); Gravity = Rigidbody.gravityScale; } private void OnDrawGizmos() { Gizmos.color = Color.red; Gizmos.DrawWireCube(Side_Attack_Transform.position, Side_Attack_Area); Gizmos.DrawWireCube(Up_Attack_Transform.position, Up_Attack_Area); Gizmos.DrawWireCube(Down_Attack_Transform.position, Down_Attack_Area); } // Update is called once per frame void Update() { GetInputs(); UpdateJumpVariables(); if (Player_State.Dashing) { return; } Flip(); Move(); Jump(); Attack(); Start_Dash(); Restore_Time_Scale(); Flash_While_Invincible(); } private void FixedUpdate() { if (Player_State.Dashing) { return; } Recoil(); } void GetInputs() { XAxis = Input.GetAxisRaw("Horizontal"); Attack_Bool = Input.GetButtonDown("Attack"); Mouse_Position = Camera.main.ScreenToWorldPoint(Input.mousePosition); Mouse_Position.x -= gameObject.transform.position.x; Mouse_Position.y -= gameObject.transform.position.y; Mouse_Position.z = 0f; } void Flip() { if(XAxis < 0) { transform.localScale = new Vector2(Mathf.Abs(transform.localScale.x), transform.localScale.y); Player_State.Looking_Right = false; } else if(XAxis > 0) { transform.localScale = new Vector2(-Mathf.Abs(transform.localScale.x), transform.localScale.y); Player_State.Looking_Right = true; } } private void Move() { Rigidbody.velocity = new Vector2(WalkSpeed * XAxis, Rigidbody.velocity.y); Animator.SetBool("Walking", Rigidbody.velocity.x != 0 && Grounded()); } void Start_Dash() { if(Input.GetButtonDown("Dash") && Can_Dash && !Dashed) { StartCoroutine(Dash()); Dashed = true; } if(Grounded()) { Dashed = false; } } IEnumerator Dash() { Player_State.Dashing = true; Player_State.Invincible = true; Can_Dash = false; Animator.SetTrigger("Dashing"); Rigidbody.gravityScale = 0; Rigidbody.velocity = new Vector2(-transform.localScale.x * Dash_Speed, 0); if(Grounded()) { Instantiate(Dash_Effect, transform); } yield return new WaitForSeconds(Dash_Time); Rigidbody.gravityScale = Gravity; Player_State.Dashing = false; Player_State.Invincible = false; yield return new WaitForSeconds(0.2f); yield return new WaitForSeconds(Dash_Cooldown); Can_Dash = true; } void Attack() { Attack_Time_Counter += Time.deltaTime; if(Attack_Bool && Attack_Time_Counter >= Time_Between_Attack) { Attack_Time_Counter = 0; Animator.SetTrigger("Attacking"); if(Mouse_Position.y < Up_Attack_Parameter && Mouse_Position.y > Down_Attack_Parameter || Mouse_Position.y <= Down_Attack_Parameter && Grounded()) { Hit(Side_Attack_Transform, Side_Attack_Area, ref Player_State.Recoiling_X, Recoil_X_Speed); Slash_Effect_Angle(Slash_Effect_Object, 0, Side_Attack_Transform); } else if(Mouse_Position.y > Up_Attack_Parameter) { Hit(Up_Attack_Transform, Up_Attack_Area, ref Player_State.Recoiling_Y, Recoil_Y_Speed); Slash_Effect_Angle(Slash_Effect_Object, 80, Up_Attack_Transform); } else if(Mouse_Position.y < Down_Attack_Parameter && !Grounded()) { Hit(Down_Attack_Transform, Down_Attack_Area, ref Player_State.Recoiling_Y, Recoil_Y_Speed); Slash_Effect_Angle(Slash_Effect_Object, -90, Down_Attack_Transform); } } } void Hit(Transform Attack_Transform, Vector2 Attack_Area, ref bool Recoil_Directory, float Recoil_Strength) { Collider2D[] Objects_To_Hit = Physics2D.OverlapBoxAll(Attack_Transform.position, Attack_Area, 0, Attackable_Layer); List<Enemy> Hit_Enemies = new List<Enemy>(); if(Objects_To_Hit.Length > 0) { Recoil_Directory = true; } for(int i = 0; i < Objects_To_Hit.Length; i++) { Enemy e = Objects_To_Hit[i].GetComponent<Enemy>(); if(e && !Hit_Enemies.Contains(e)) { e.Enemy_Hit(Player_Damage, (transform.position - Objects_To_Hit[i].transform.position).normalized, Recoil_Strength); Hit_Enemies.Add(e); } } } void Slash_Effect_Angle(GameObject Slash_Effect, int Effect_Angle, Transform Attack_Transform) { Slash_Effect = Instantiate(Slash_Effect, Attack_Transform); Slash_Effect.transform.eulerAngles = new Vector3(0, 0, Effect_Angle); Slash_Effect.transform.localScale = new Vector2(transform.localScale.x, transform.localScale.y); } void Recoil() { if(Player_State.Recoiling_X) { if(Player_State.Looking_Right) { Rigidbody.velocity = new Vector2(-Recoil_X_Speed, 0); } else if(!Player_State.Looking_Right) Rigidbody.velocity = new Vector2(Recoil_X_Speed, 0); } if(Player_State.Recoiling_Y) { if(Mouse_Position.y < Down_Attack_Parameter) { Rigidbody.gravityScale = 0; Rigidbody.velocity = new Vector2(Rigidbody.velocity.x, Recoil_Y_Speed); } else if(Mouse_Position.y > Up_Attack_Parameter) { Rigidbody.gravityScale = 0; Rigidbody.velocity = new Vector2(Rigidbody.velocity.x, -Recoil_Y_Speed); } Air_Jump_Counter = 0; } else { Rigidbody.gravityScale = Gravity; } if(Player_State.Recoiling_X && Steps_X_Recoiled < Recoil_X_Steps) { Steps_X_Recoiled++; } else { Stop_Recoil_X(); } if(Player_State.Recoiling_Y && Steps_Y_Recoiled < Recoil_Y_Steps) { Steps_Y_Recoiled++; } else { Stop_Recoil_Y(); } if(Grounded()) { Stop_Recoil_Y(); } } void Stop_Recoil_X() { Steps_X_Recoiled = 0; Player_State.Recoiling_X = false; } void Stop_Recoil_Y() { Steps_Y_Recoiled = 0; Player_State.Recoiling_Y = false; } public void Take_Damage(float Damage_Taken) { Player_Health_Int -= Mathf.RoundToInt(Damage_Taken); StartCoroutine(Stop_Taking_Damage()); } public IEnumerator Stop_Taking_Damage() { Player_State.Invincible = true; GameObject Blood_Spurt_Particles = Instantiate(Blood_Spurt, transform.position, Quaternion.identity); Destroy(Blood_Spurt_Particles, 1.5f); Animator.SetTrigger("Take Damage"); yield return new WaitForSeconds(1f); Player_State.Invincible = false; } void Flash_While_Invincible() { Sprite_Renderer.material.color = Player_State.Invincible ? Color.Lerp(Color.white, Color.black, Mathf.PingPong(Time.time * Hit_Flash_Speed, 1.0f)) : Color.white; } void Restore_Time_Scale() { if(Restore_Time) { if (Time.timeScale < 1) { Time.timeScale += Time.deltaTime * Restore_Time_Speed; } else { Time.timeScale = 1; Restore_Time = false; } } } public void Hit_Stop_Time(float New_Time_Scale, int Restore_Speed, float Delay) { Restore_Time_Speed = Restore_Speed; Time.timeScale = New_Time_Scale; if (Delay > 0) { StopCoroutine(Start_Time_Again(Delay)); StartCoroutine(Start_Time_Again(Delay)); } } IEnumerator Start_Time_Again(float Delay) { Restore_Time = true; yield return new WaitForSeconds(Delay); } public int Player_Health_Int { get { return Player_Health; } set { if (Player_Health != value) { Player_Health = Mathf.Clamp(value, 0, Player_Max_Health); if(On_Health_Changed_Callback != null) { On_Health_Changed_Callback.Invoke(); } } } } 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") && Rigidbody.velocity.y > 0) { Rigidbody.velocity = new Vector2(Rigidbody.velocity.x, 0); Player_State.Jumping = false; } if(!Player_State.Jumping) { if(Jump_Buffer_Counter > 0 && Coyote_Time_Counter > 0) { Rigidbody.velocity = new Vector3(Rigidbody.velocity.x, JumpForce); Player_State.Jumping = true; } else if(!Grounded() && Air_Jump_Counter < Max_Air_Jumps && Input.GetButtonDown("Jump")) { Player_State.Jumping = true; Air_Jump_Counter ++; Rigidbody.velocity = new Vector3(Rigidbody.velocity.x, JumpForce); } } Animator.SetBool("Jumping", Rigidbody.velocity.y > 0 && !Grounded()); Animator.SetBool("Falling", Rigidbody.velocity.y < 0 && !Grounded()); } void UpdateJumpVariables() { if(Grounded()) { Player_State.Jumping = false; Coyote_Time_Counter = Coyote_Time; Air_Jump_Counter = 0; } else { Coyote_Time_Counter -= Time.deltaTime; } if(Input.GetButtonDown("Jump")) { Jump_Buffer_Counter = Jump_Buffer_Frames; } else { Jump_Buffer_Counter -= Time.deltaTime * 10; } } }``` and here's the video. https://imgur.com/a/c3jaDSj<ol></li>November 4, 2025 at 8:21 pm #18996::It looks like you’ve provided a comprehensive player controller script for a Unity game, along with a link to a video. However, it seems you’re looking for some assistance or feedback on this script.
Here are a few points that might help you improve or debug your script:
-
Syntax Issues:
- In your script, you’re using HTML entities like
<,>, and&instead of the actual symbols `, and&`. Make sure to replace these with the correct symbols to avoid syntax errors.
- In your script, you’re using HTML entities like
-
Jump Logic:
- Ensure that your jump logic is working correctly, especially the coyote time and jump buffering. You might want to add debug logs to see if the conditions for jumping are being met.
-
Dash Functionality:
- Make sure that the dash feature is working as intended. You could test the dash in various scenarios to ensure it doesn’t interfere with other actions like jumping or attacking.
-
Animation Triggers:
- Check if the animation triggers (
Dashing,Attacking, etc.) are set properly in your Animator. Sometimes issues arise from not having the correct transitions in the Animator setup.
- Check if the animation triggers (
-
Health System:
- In your
Take_Damagemethod, ensure that you are limiting the health correctly and that the invincibility works as expected after taking damage.
- In your
-
Input Handling:
- Consider using Unity’s Input System for better input handling, especially if you plan to expand the controls later.
-
Debugging:
- Use
Debug.Logstatements in your code to see if certain blocks of code are being executed as expected. This can help identify any logical errors.
- Use
-
Ground Check:
- Ensure your ground check is robust. You may want to visualize the ground check rays in the scene view to confirm they are hitting the ground as expected.
If you have a specific issue or error message you’re encountering, please share that, and I can help troubleshoot further!
November 4, 2025 at 8:23 pm #18997November 4, 2025 at 8:26 pm #18998::To help you determine if there are any issues with your dash script in the
Player_Controller, let’s take a closer look at the key parts of the dash functionality:-
Dash Trigger: Ensure that the dash is only triggered when the player is able to dash. The check you have in
Start_Dash()looks correct:if(Input.GetButtonDown("Dash") && Can_Dash && !Dashed) -
Coroutine for Dashing: In the
Dash()coroutine, you’re settingPlayer_State.Dashingto true and modifying the velocity:Player_State.Dashing = true; Rigidbody.gravityScale = 0; Rigidbody.velocity = new Vector2(-transform.localScale.x * Dash_Speed, 0);This part should work correctly as long as
Dash_Speedandtransform.localScaleare set up properly. -
Resetting States: After the dash, you reset the gravity and the dashing state. Make sure that this logic is working properly:
yield return new WaitForSeconds(Dash_Time); Rigidbody.gravityScale = Gravity; Player_State.Dashing = false; -
Dash Cooldown: After the dash, you have a cooldown period:
yield return new WaitForSeconds(0.2f); yield return new WaitForSeconds(Dash_Cooldown); Can_Dash = true;Ensure that the cooldown is actually giving you the expected behavior. You might want to log when the dash can be initiated again.
-
Ground Check: You have a check for whether the player is on the ground after the dash, which resets the
Dashedstate:if(Grounded()) { Dashed = false; }This is good, but make sure that the
Grounded()function is accurately detecting whether the player is on the ground.
Debugging Steps
-
Add Debug Logs: Add
Debug.Logstatements in yourStart_Dash()andDash()methods to track when the dash starts and ends. For example:Debug.Log("Dash started"); Debug.Log("Dash ended"); -
Test Input: Check if the input for the dash is being registered properly. You can test this by logging the input state.
-
Visualize Dash: Ensure that the player visibly dashes by checking if the velocity changes as expected during the dash.
If you encounter any specific issues or unexpected behaviors, please provide details on that, and I can help troubleshoot further!
November 4, 2025 at 8:47 pm #18999::@nirvikrajbhandari let me know if this helps. If not, zip up your project and share a link to your project on Google Drive.
You can follow this guide if you’re not sure how to do that: https://blog.terresquall.com/2023/07/how-to-package-and-transfer-your-unity-project-from-one-device-to-another/#zipping-project-files
November 4, 2025 at 8:53 pm #19000::Ok, Here’s the Player Controller Script using System.Collections; using System.Collections.Generic; using UnityEngine;
public class Player_Controller : MonoBehaviour { [Header("Horizontal Movement Settings")] [SerializeField] private float WalkSpeed = 1; [Space(5)] [Header("Vertical Movement Settings")] [SerializeField] private float JumpForce = 45; private float Jump_Buffer_Counter; [SerializeField] private float Jump_Buffer_Frames = 0; private float Coyote_Time_Counter; [SerializeField] private float Coyote_Time; private int Air_Jump_Counter = 0; [SerializeField] private int Max_Air_Jumps; [Space(5)] [Header("Ground Check Settings")] [SerializeField] Transform GroundCheckPoint; [SerializeField] private float GroundCheckY = 0.2f; [SerializeField] private float GroundCheckX = 0.5f; [SerializeField] private LayerMask WhatIsGround; [Space(5)] [Header("Dash Settings")] [SerializeField] private float Dash_Speed; [SerializeField] private float Dash_Time; [SerializeField] private float Dash_Cooldown; private bool Can_Dash = true; private bool Dashed; [SerializeField] GameObject Dash_Effect; [Space(5)] [Header("Attack Settings")] [SerializeField] float Time_Between_Attack; float Attack_Time_Counter; [SerializeField] private Transform Side_Attack_Transform; [SerializeField] private Transform Up_Attack_Transform; [SerializeField] private Transform Down_Attack_Transform; [SerializeField] private Vector2 Side_Attack_Area; [SerializeField] private Vector2 Up_Attack_Area; [SerializeField] private Vector2 Down_Attack_Area; [SerializeField] private float Up_Attack_Parameter; [SerializeField] private float Down_Attack_Parameter; [SerializeField] private LayerMask Attackable_Layer; [SerializeField] private float Player_Damage; [SerializeField] GameObject Slash_Effect_Object; bool Attack_Bool = false; bool Restore_Time; float Restore_Time_Speed; [Space(5)] [Header("Recoil Settings")] [SerializeField] int Recoil_X_Steps = 5; [SerializeField] int Recoil_Y_Steps = 5; [SerializeField] int Recoil_X_Speed = 100; [SerializeField] int Recoil_Y_Speed = 100; int Steps_X_Recoiled; int Steps_Y_Recoiled; [Header("Health Settings")] public int Player_Health; public int Player_Max_Health; [SerializeField] GameObject Blood_Spurt; [SerializeField] float Hit_Flash_Speed; public delegate void On_Health_Changed_Delegate(); [HideInInspector] public On_Health_Changed_Delegate On_Health_Changed_Callback; [Space(5)] private Vector3 Mouse_Position; [HideInInspector] public Player_State_List Player_State; private Rigidbody2D Rigidbody; private SpriteRenderer Sprite_Renderer; private float Gravity; private float XAxis; Animator Animator; public static Player_Controller Instance; private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } Player_Health = Player_Max_Health; } // Start is called before the first frame update void Start() { Player_State = GetComponent<Player_State_List>(); Rigidbody = GetComponent<Rigidbody2D>(); Sprite_Renderer = GetComponent<SpriteRenderer>(); Animator = GetComponent<Animator>(); Gravity = Rigidbody.gravityScale; } private void OnDrawGizmos() { Gizmos.color = Color.red; Gizmos.DrawWireCube(Side_Attack_Transform.position, Side_Attack_Area); Gizmos.DrawWireCube(Up_Attack_Transform.position, Up_Attack_Area); Gizmos.DrawWireCube(Down_Attack_Transform.position, Down_Attack_Area); } // Update is called once per frame void Update() { GetInputs(); UpdateJumpVariables(); if (Player_State.Dashing) { return; } Flip(); Move(); Jump(); Attack(); Start_Dash(); Restore_Time_Scale(); Flash_While_Invincible(); } private void FixedUpdate() { if (Player_State.Dashing) { return; } Recoil(); } void GetInputs() { XAxis = Input.GetAxisRaw("Horizontal"); Attack_Bool = Input.GetButtonDown("Attack"); Mouse_Position = Camera.main.ScreenToWorldPoint(Input.mousePosition); Mouse_Position.x -= gameObject.transform.position.x; Mouse_Position.y -= gameObject.transform.position.y; Mouse_Position.z = 0f; } void Flip() { if(XAxis < 0) { transform.localScale = new Vector2(Mathf.Abs(transform.localScale.x), transform.localScale.y); Player_State.Looking_Right = false; } else if(XAxis > 0) { transform.localScale = new Vector2(-Mathf.Abs(transform.localScale.x), transform.localScale.y); Player_State.Looking_Right = true; } } private void Move() { Rigidbody.velocity = new Vector2(WalkSpeed * XAxis, Rigidbody.velocity.y); Animator.SetBool("Walking", Rigidbody.velocity.x != 0 && Grounded()); } void Start_Dash() { if(Input.GetButtonDown("Dash") && Can_Dash && !Dashed) { StartCoroutine(Dash()); Dashed = true; } if(Grounded()) { Dashed = false; } } IEnumerator Dash() { Player_State.Dashing = true; Player_State.Invincible = true; Can_Dash = false; Animator.SetTrigger("Dashing"); Rigidbody.gravityScale = 0; Rigidbody.velocity = new Vector2(-transform.localScale.x * Dash_Speed, 0); if(Grounded()) { Instantiate(Dash_Effect, transform); } yield return new WaitForSeconds(Dash_Time); Rigidbody.gravityScale = Gravity; Player_State.Dashing = false; Player_State.Invincible = false; yield return new WaitForSeconds(0.2f); yield return new WaitForSeconds(Dash_Cooldown); Can_Dash = true; } void Attack() { Attack_Time_Counter += Time.deltaTime; if(Attack_Bool && Attack_Time_Counter >= Time_Between_Attack) { Attack_Time_Counter = 0; Animator.SetTrigger("Attacking"); if(Mouse_Position.y < Up_Attack_Parameter && Mouse_Position.y > Down_Attack_Parameter || Mouse_Position.y <= Down_Attack_Parameter && Grounded()) { Hit(Side_Attack_Transform, Side_Attack_Area, ref Player_State.Recoiling_X, Recoil_X_Speed); Slash_Effect_Angle(Slash_Effect_Object, 0, Side_Attack_Transform); } else if(Mouse_Position.y > Up_Attack_Parameter) { Hit(Up_Attack_Transform, Up_Attack_Area, ref Player_State.Recoiling_Y, Recoil_Y_Speed); Slash_Effect_Angle(Slash_Effect_Object, 80, Up_Attack_Transform); } else if(Mouse_Position.y < Down_Attack_Parameter && !Grounded()) { Hit(Down_Attack_Transform, Down_Attack_Area, ref Player_State.Recoiling_Y, Recoil_Y_Speed); Slash_Effect_Angle(Slash_Effect_Object, -90, Down_Attack_Transform); } } } void Hit(Transform Attack_Transform, Vector2 Attack_Area, ref bool Recoil_Directory, float Recoil_Strength) { Collider2D[] Objects_To_Hit = Physics2D.OverlapBoxAll(Attack_Transform.position, Attack_Area, 0, Attackable_Layer); List<Enemy> Hit_Enemies = new List<Enemy>(); if(Objects_To_Hit.Length > 0) { Recoil_Directory = true; } for(int i = 0; i < Objects_To_Hit.Length; i++) { Enemy e = Objects_To_Hit[i].GetComponent<Enemy>(); if(e && !Hit_Enemies.Contains(e)) { e.Enemy_Hit(Player_Damage, (transform.position - Objects_To_Hit[i].transform.position).normalized, Recoil_Strength); Hit_Enemies.Add(e); } } } void Slash_Effect_Angle(GameObject Slash_Effect, int Effect_Angle, Transform Attack_Transform) { Slash_Effect = Instantiate(Slash_Effect, Attack_Transform); Slash_Effect.transform.eulerAngles = new Vector3(0, 0, Effect_Angle); Slash_Effect.transform.localScale = new Vector2(transform.localScale.x, transform.localScale.y); } void Recoil() { if(Player_State.Recoiling_X) { if(Player_State.Looking_Right) { Rigidbody.velocity = new Vector2(-Recoil_X_Speed, 0); } else if(!Player_State.Looking_Right) Rigidbody.velocity = new Vector2(Recoil_X_Speed, 0); } if(Player_State.Recoiling_Y) { if(Mouse_Position.y < Down_Attack_Parameter) { Rigidbody.gravityScale = 0; Rigidbody.velocity = new Vector2(Rigidbody.velocity.x, Recoil_Y_Speed); } else if(Mouse_Position.y > Up_Attack_Parameter) { Rigidbody.gravityScale = 0; Rigidbody.velocity = new Vector2(Rigidbody.velocity.x, -Recoil_Y_Speed); } Air_Jump_Counter = 0; } else { Rigidbody.gravityScale = Gravity; } if(Player_State.Recoiling_X && Steps_X_Recoiled < Recoil_X_Steps) { Steps_X_Recoiled++; } else { Stop_Recoil_X(); } if(Player_State.Recoiling_Y && Steps_Y_Recoiled < Recoil_Y_Steps) { Steps_Y_Recoiled++; } else { Stop_Recoil_Y(); } if(Grounded()) { Stop_Recoil_Y(); } } void Stop_Recoil_X() { Steps_X_Recoiled = 0; Player_State.Recoiling_X = false; } void Stop_Recoil_Y() { Steps_Y_Recoiled = 0; Player_State.Recoiling_Y = false; } public void Take_Damage(float Damage_Taken) { Player_Health_Int -= Mathf.RoundToInt(Damage_Taken); StartCoroutine(Stop_Taking_Damage()); } public IEnumerator Stop_Taking_Damage() { Player_State.Invincible = true; GameObject Blood_Spurt_Particles = Instantiate(Blood_Spurt, transform.position, Quaternion.identity); Destroy(Blood_Spurt_Particles, 1.5f); Animator.SetTrigger("Take Damage"); yield return new WaitForSeconds(1f); Player_State.Invincible = false; } void Flash_While_Invincible() { Sprite_Renderer.material.color = Player_State.Invincible ? Color.Lerp(Color.white, Color.black, Mathf.PingPong(Time.time * Hit_Flash_Speed, 1.0f)) : Color.white; } void Restore_Time_Scale() { if(Restore_Time) { if (Time.timeScale < 1) { Time.timeScale += Time.deltaTime * Restore_Time_Speed; } else { Time.timeScale = 1; Restore_Time = false; } } } public void Hit_Stop_Time(float New_Time_Scale, int Restore_Speed, float Delay) { Restore_Time_Speed = Restore_Speed; Time.timeScale = New_Time_Scale; if (Delay > 0) { StopCoroutine(Start_Time_Again(Delay)); StartCoroutine(Start_Time_Again(Delay)); } } IEnumerator Start_Time_Again(float Delay) { Restore_Time = true; yield return new WaitForSeconds(Delay); } public int Player_Health_Int { get { return Player_Health; } set { if (Player_Health != value) { Player_Health = Mathf.Clamp(value, 0, Player_Max_Health); if(On_Health_Changed_Callback != null) { On_Health_Changed_Callback.Invoke(); } } } } 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") && Rigidbody.velocity.y > 0) { Rigidbody.velocity = new Vector2(Rigidbody.velocity.x, 0); Player_State.Jumping = false; } if(!Player_State.Jumping) { if(Jump_Buffer_Counter > 0 && Coyote_Time_Counter > 0) { Rigidbody.velocity = new Vector3(Rigidbody.velocity.x, JumpForce); Player_State.Jumping = true; } else if(!Grounded() && Air_Jump_Counter < Max_Air_Jumps && Input.GetButtonDown("Jump")) { Player_State.Jumping = true; Air_Jump_Counter ++; Rigidbody.velocity = new Vector3(Rigidbody.velocity.x, JumpForce); } } Animator.SetBool("Jumping", Rigidbody.velocity.y > 0 && !Grounded()); Animator.SetBool("Falling", Rigidbody.velocity.y < 0 && !Grounded()); } void UpdateJumpVariables() { if(Grounded()) { Player_State.Jumping = false; Coyote_Time_Counter = Coyote_Time; Air_Jump_Counter = 0; } else { Coyote_Time_Counter -= Time.deltaTime; } if(Input.GetButtonDown("Jump")) { Jump_Buffer_Counter = Jump_Buffer_Frames; } else { Jump_Buffer_Counter -= Time.deltaTime * 10; } } }and here’s the video. https://imgur.com/a/c3jaDSj
November 4, 2025 at 8:56 pm #19001::It seems you’ve shared the player controller script again, and there are still HTML entities present instead of correct symbols, which could lead to syntax errors in Unity. Let’s address that first and then discuss the script further.
Fixing HTML Entities
Please replace all occurrences of HTML entities with their corresponding characters in your script. Here are the replacements you need to make:
<➔ “&➔&
After making these replacements, your script should compile correctly.
Review of the Player Controller Script
Your script looks quite comprehensive, handling various aspects of player movement, jumping, dashing, attacking, and health management. Here are some suggestions and checks you can perform:
-
Dash Functionality:
- Ensure the
Dash()coroutine is performing as expected. Print debug logs in the dash coroutine to confirm it gets triggered and completes successfully.
- Ensure the
-
Ground Check:
- The
Grounded()method should effectively detect if the player is on the ground. You can visualize the raycasts in the Unity editor usingOnDrawGizmos()to ensure they are positioned correctly and detecting the ground.
- The
-
Jump Logic:
- Review the jump conditions to ensure they work as intended, particularly the coyote time and jump buffer. Debug logs can help verify if the player can jump when expected.
-
Animation States:
- Ensure that the animations are set up correctly in the Animator. Check transitions between states (e.g., from idle to walking to jumping) to ensure they reflect the player’s current state accurately.
-
Health Management:
- In your
Take_Damagemethod, ensure that the health system properly triggers events when health changes. You can useDebug.Logto track health values during gameplay.
- In your
-
Testing:
- Playtest various scenarios to ensure movement, jumping, dashing, and attacking all work smoothly together. Look for any bugs or unexpected behaviors, especially when transitioning between states.
-
Code Optimization:
- Consider breaking down larger methods into smaller ones for clarity, especially if you plan to expand the functionality. This can make it easier to manage and debug.
If you have a specific issue you’re facing or a particular aspect of the script you’d like feedback on, please let me know!
November 4, 2025 at 8:56 pm #19002::It looks like you’re sharing a player controller script for Unity, but it appears that the code snippets you’ve provided contain HTML character entities instead of actual symbols. This can cause syntax errors when you try to compile the script.
Here’s a quick checklist to help you identify and fix potential issues in your script, particularly with the dash functionality:
-
Replace HTML Entities:
- Go through your script and replace HTML entities like
<,>,&with `, and&` respectively.
- Go through your script and replace HTML entities like
-
Check Dash Logic:
- Ensure the
Start_Dashmethod is being called correctly. TheDashcoroutine should be initiated only when the conditions are met (Input.GetButtonDown("Dash") && Can_Dash && !Dashed).
- Ensure the
-
Ground Check After Dash:
- After dashing, the
Dashedvariable is reset if the player is grounded. Make sure that this logic correctly allows dashing again once the player is on the ground.
- After dashing, the
-
Gravity Reset:
- After a dash, you set
Rigidbody.gravityScale = Gravity;. Make sure that the variableGravityis properly set during theStart()method.
- After a dash, you set
-
Dash Cooldown:
- Make sure the cooldown period works as intended. You may want to log when the player can dash again to debug.
-
Animation Triggers:
- Check that the Animator is set up correctly with the “Dashing” trigger. Ensure that the transitions are set to avoid unexpected behavior.
-
Test Inputs:
- Log the input you receive for the dash to ensure it’s being registered correctly. This can help you confirm that the input is being handled as you expect.
-
Debugging:
- Add
Debug.Logstatements in your methods to see the flow of execution, especially when dashing. This can help identify if the conditions are met and if the coroutine is being called.
- Add
If you have a specific issue you are encountering when running this script, such as an error message or unexpected behavior during gameplay, please provide those details, and I can assist you further!
November 4, 2025 at 9:11 pm #19003::I tried the solutions given to me, but it didn’t work which leads me to believe the main problem has something to do with the enemies collision or the invincibility. For some reason whenever I uploaded the ZIP folder to google drive it deleted the packages and project settings folders. IF those are not necessary, here’s the link to the folder. https://drive.google.com/file/d/1h9_iWmOzcW02T8LnPJsOZbwFePjRP8Px/view?usp=sharing
November 4, 2025 at 9:16 pm #19004::It seems you’ve narrowed down the problem to either enemy collision or the invincibility logic, and you’re having issues with uploading your project files correctly. Here are some steps to help you troubleshoot the collision and invincibility issues in your game:
1. Check Enemy Collision Logic
- Collider Setup: Ensure that your enemies have the correct colliders set up. They should have a Collider2D component (like BoxCollider2D or CircleCollider2D) that matches their sprites.
- Layer Settings: Ensure that the enemy objects are on the correct layer that your player can interact with. Check the Layer Collision Matrix in the Physics2D settings to ensure that collisions between the player and enemies are enabled.
- Collision Detection: Make sure that you are using the appropriate collision detection method in your scripts. If you are using
OnTriggerEnter2D, ensure that the colliders are set as triggers.
2. Debugging Invincibility
- Log Invincibility State: Place
Debug.Logstatements in yourTake_DamageandStop_Taking_Damagemethods to confirm when invincibility is activated and deactivated. - Check Timing: Ensure that the timing for invincibility is correct. You might want to test with a longer invincibility duration to see if the problem persists.
- Visual Indication: Consider adding a visual feedback (like a shader effect or flashing) when the player is invincible to confirm that the logic is being executed.
3. Testing with Simplified Conditions
- Remove Complex Logic: Temporarily disable complex logic (like dashing or jumping) to isolate the problem. See if the basic collision detection works when the player is just moving.
- Use Debug Colliders: Create a simple debug object with a collider to test collision interactions without the complexity of the player character.
4. Project Settings and Packages
- Missing Packages: If uploading your project is deleting necessary folders, ensure that you are compressing the project correctly. Only the
AssetsandProjectSettingsfolders are typically needed to share a project. - Reimport Packages: If you find that packages are missing, you may need to reimport them. Open the Package Manager in Unity and confirm that all necessary packages are installed.
5. Reproduce the Issue
- Testing in a New Scene: Create a new scene where you can test your player against a single enemy to see if the collision and invincibility issues persist. This can help eliminate scene-specific problems.
Conclusion
If none of these steps resolve your issue, please provide more specifics about the behavior you’re experiencing (e.g., player not taking damage when it should, invincibility not working at all, etc.). If you have specific error messages or behaviors in the Unity console, those would also be helpful for diagnosing the problem.
Let me know how it goes!
-
-
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: