Forum begins after the advertisement:
[Part 4] My down spell is not dealing damage
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [Part 4] My down spell is not dealing damage
- This topic has 0 replies, 1 voice, and was last updated 1 hour, 31 minutes ago by
Nirvik Rajbhandari.
Viewing 1 post (of 1 total)
-
AuthorPosts
-
November 25, 2025 at 1:16 am #19059::
All of my other spells are working as expected, but my down spell won’t deal damage. Here is my player controller script using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;
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; float Heal_Timer; [SerializeField] float Time_To_Heal; [Space(5)] [Header("Mana Settings")] [SerializeField] UnityEngine.UI.Image Mana_Storage; [SerializeField] float Mana; [SerializeField] float Mana_Drain_Speed; [SerializeField] float Mana_Gain; [Space(5)] [Header("Spell Casting")] [SerializeField] float Mana_Spell_Cost = 0.3f; [SerializeField] float Time_Between_Cast = 0.5f; [SerializeField] float Spell_Damage; [SerializeField] float Down_Spell_Force; [SerializeField] GameObject Side_Spell; [SerializeField] GameObject Up_Spell; [SerializeField] GameObject Down_Spell; float Cast_Time_Counter; float Cast_Or_Heal_Timer; [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; Player_Mana = Mana; Mana_Storage.fillAmount = Mana; } 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; } Restore_Time_Scale(); Flash_While_Invincible(); Move(); Heal(); Cast_Spell(); if (Player_State.Healing) { return; } Flip(); Jump(); Attack(); Start_Dash(); } private void OnTriggerEnter2D(Collider2D Other) { if(Other.GetComponent<Enemy>() != null && Player_State.Casting) { Other.GetComponent<Enemy>().Enemy_Hit(Spell_Damage, (Other.transform.position - transform.position).normalized, -Recoil_Y_Speed); } } 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; if (Input.GetButton("Cast/Heal")) { Cast_Or_Heal_Timer += Time.deltaTime; } else { Cast_Or_Heal_Timer = 0; } } void Flip() { if(Attack_Time_Counter < 0.5f) { return; } 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() { if(Player_State.Healing) { Rigidbody.velocity = new Vector2(0,0); } 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(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); if(Objects_To_Hit[i].CompareTag("Enemy")) { Player_Mana += Mana_Gain; } } } } 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.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(); } } } } private void Heal() { if (Input.GetButton("Cast/Heal") && Cast_Or_Heal_Timer > 0.05f && Player_Health_Int < Player_Max_Health && Player_Mana > 0 && Grounded() && !Player_State.Dashing) { Player_State.Healing = true; Heal_Timer += Time.deltaTime; Animator.SetBool("Healing", true); Player_Mana -= Time.deltaTime * Mana_Drain_Speed; if (Heal_Timer >= Time_To_Heal) { Player_Health_Int++; Heal_Timer = 0; } } else { Player_State.Healing = false; Heal_Timer = 0; Animator.SetBool("Healing", false); } } private float Player_Mana { get { return Mana; } set { if (Mana != value) { Mana = Mathf.Clamp(value, 0, 1); Mana_Storage.fillAmount = Mana; } } } void Cast_Spell() { if (Input.GetButtonUp("Cast/Heal") && Cast_Or_Heal_Timer <= 0.05f && Cast_Time_Counter >= Time_Between_Cast && Mana >= Mana_Spell_Cost) { Player_State.Casting = true; Cast_Time_Counter = 0; StartCoroutine(Cast_Coroutine()); } else { Cast_Time_Counter += Time.deltaTime; } if (Grounded()) { Down_Spell.SetActive(false); } if(Down_Spell.activeInHierarchy) { Rigidbody.velocity = Down_Spell_Force * Vector2.down; } } IEnumerator Cast_Coroutine() { Animator.SetBool("Casting", true); Rigidbody.gravityScale = 0; yield return new WaitForSeconds(0.12f); Rigidbody.gravityScale = Gravity; if (Mouse_Position.y < Up_Attack_Parameter && Mouse_Position.y > Down_Attack_Parameter || Mouse_Position.y <= Down_Attack_Parameter && Grounded()) { GameObject Fire_Ball = Instantiate(Side_Spell, Side_Attack_Transform.position, Quaternion.identity); if (Player_State.Looking_Right) { Fire_Ball.transform.eulerAngles = Vector3.zero; } else { Fire_Ball.transform.eulerAngles = new Vector3(Fire_Ball.transform.eulerAngles.x, 180); } Player_State.Recoiling_X = true; } else if (Mouse_Position.y > Up_Attack_Parameter) { Instantiate(Up_Spell, transform); Rigidbody.velocity = Vector2.zero; } else if (Mouse_Position.y < Down_Attack_Parameter && !Grounded()) { Down_Spell.SetActive(true); } Player_Mana -= Mana_Spell_Cost; yield return new WaitForSeconds(0.11f); Animator.SetBool("Casting", false); Player_State.Casting = false; } 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 (Jump_Buffer_Counter > 0 && Coyote_Time_Counter > 0 && !Player_State.Jumping) { 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); } if (Input.GetButtonUp("Jump") && Rigidbody.velocity.y > 3) { Rigidbody.velocity = new Vector2(Rigidbody.velocity.x, 0); Player_State.Jumping = false; } 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; } }}
-
AuthorPosts
Viewing 1 post (of 1 total)
- You must be logged in to reply to this topic.
Advertisement below: