Forum begins after the advertisement:
[Part 3] Help me with attacks
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [Part 3] Help me with attacks
- This topic has 1 reply, 3 voices, and was last updated 1 day, 22 hours ago by
Terence.
-
AuthorPosts
-
February 26, 2025 at 8:03 pm #17335::
Hey my attacks will not register attacking help me find whats wrong in my code.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour { [Header("Horizontal Movement Settings")] [SerializeField] private float Walkspeed = 1; [Space(5)] [Header("Vertical Movement Settings")] [SerializeField] private float Jumpforce = 45; private float jumpBufferCounter = 0; [SerializeField] private float jumpBufferFrames; private float coyoteTimeCounter = 0; [SerializeField] private float coyoteTime; 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 Settings")] [SerializeField] private float dashSpeed; [SerializeField] private float dashTime; [SerializeField] private float dashCooldown; [SerializeField] GameObject dashEffect; [Space(5)] [Header("Attack Settings")] bool attack = false; float timeBetweenAttack, timeSinceAttack; [SerializeField] Transform SideAttackTransform, UpAttackTransform, DownAttackTransform; [SerializeField] Vector2 SideAttackArea, UpAttackArea, DownAttackArea; [SerializeField] LayerMask attackableLayer; PlayerStateList pState; private Rigidbody2D rb; private float xAxis, yAxis; private float gravity; private bool canDash; private bool dashed; Animator anim; public static PlayerController Instance; private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } } // Start is called before the first frame update void Start() { rb = GetComponent<Rigidbody2D>(); anim = GetComponent<Animator>(); pState = GetComponent<PlayerStateList>(); gravity = rb.gravityScale; canDash = true; // Ensure dashing is enabled at the start print($"Can Dash on start: {canDash}"); } 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(); StartDash(); Attack(); } void GetInputs() { xAxis = Input.GetAxisRaw("Horizontal"); yAxis = Input.GetAxisRaw("Vertical"); attack = Input.GetButtonDown("Fire1"); } void Flip() { if (xAxis < 0) { transform.localScale = new Vector2(-1, transform.localScale.y); } else if (xAxis > 0) { transform.localScale = new Vector2(1, transform.localScale.y); } } private void Move() { rb.velocity = new Vector2(Walkspeed * xAxis, rb.velocity.y); anim.SetBool("Walking", rb.velocity.x != 0 && Grounded()); } void StartDash() { if (Input.GetButtonDown("Dash")) { if (!canDash) { print("Can't dash yet."); } else if (dashed) { print("Already dashed."); } else { print("Starting dash..."); StartCoroutine(Dash()); dashed = true; } } if (Grounded()) { dashed = false; } } IEnumerator Dash() { print("Dash coroutine started"); canDash = false; // Disable dashing until cooldown is finished 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); // Dash duration pState.dashing = false; // Stop the dash animation anim.ResetTrigger("Dashing"); // Reset the dash trigger in case it was still set rb.gravityScale = gravity; pState.dashing = false; yield return new WaitForSeconds(dashCooldown); // Dash cooldown time canDash = true; // Re-enable dashing after cooldown print("Dash coroutine finished"); print("Dashing cooled down"); } void Attack() { timeSinceAttack += Time.deltaTime; if(attack && timeSinceAttack >= timeBetweenAttack) { timeSinceAttack = 0; anim.SetTrigger("Attacking"); if(yAxis == 0 || yAxis < 0 && Grounded()) { Debug.Log("Side attack triggered!"); Hit(SideAttackTransform, SideAttackArea); } else if(yAxis > 0) { Debug.Log("Upward attack triggered!"); Hit(UpAttackTransform, UpAttackArea); } else if(yAxis < 0 && !Grounded()) { Debug.Log("Downward attack triggered!"); Hit(DownAttackTransform, DownAttackArea); } } } void Hit(Transform _attackTransform, Vector2 _attackArea) { // Debugging: Log attack position and area Debug.Log($"Checking attack at position: {_attackTransform.position} with area: {_attackArea}"); Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer); if (objectsToHit.Length > 0) { // Debugging: Log the objects hit Debug.Log("Hit objects:"); foreach (var hit in objectsToHit) { Debug.Log("Hit: " + hit.gameObject.name); // Log the name of the object hit } } else { Debug.Log("No objects hit."); } } 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.velocity.y > 0) { rb.velocity = new Vector2(rb.velocity.x, 0); pState.jumping = false; } if (jumpBufferCounter > 0 && coyoteTimeCounter > 0) { rb.velocity = new Vector3(rb.velocity.x, Jumpforce); pState.jumping = true; } else if (!Grounded() && airJumpCounter < maxAirJumps && Input.GetButtonDown("Jump")) { pState.jumping = true; airJumpCounter++; rb.velocity = new Vector3(rb.velocity.x, Jumpforce); } anim.SetBool("Jumping", !Grounded()); } void UpdateJumpVariables() { if (Grounded()) { pState.jumping = false; coyoteTimeCounter = coyoteTime; airJumpCounter = 0; } else { coyoteTimeCounter -= Time.deltaTime; } if (Input.GetButtonDown("Jump")) { jumpBufferCounter = jumpBufferFrames; } else { jumpBufferCounter = jumpBufferCounter - Time.deltaTime * 10; } } }
February 26, 2025 at 8:11 pm #17337::It looks like you’re having trouble with the attack functionality in your
PlayerController
script. Here are a few things to check and suggestions to help you troubleshoot the problem:-
Check Input Settings: Ensure that the “Fire1” input is correctly set up in Unity’s Input Manager. Go to Edit -> Project Settings -> Input Manager and check that the “Fire1” action is configured correctly.
-
Attack Cooldown: You might want to add a cooldown mechanism for the attacks. Right now, the attack can be triggered every frame if the button is held down. Consider adding a variable to control the time between attacks, like this:
float timeBetweenAttack = 0.5f; // Set this to your desired cooldown time
-
Initialization of
timeBetweenAttack
: You haven’t initializedtimeBetweenAttack
anywhere in your code. Make sure it has a value at the start:void Start() { // ... other initializations timeBetweenAttack = 0.5f; // or whatever value you want }
-
Debugging the Attack Function: You have some debug logs, which is great! Make sure to check the console output to see if “Side attack triggered!”, “Upward attack triggered!”, or “Downward attack triggered!” are being logged when you press the attack button.
-
Check OverlapBox Parameters: Ensure that the
SideAttackTransform
,UpAttackTransform
, andDownAttackTransform
are set correctly in the Unity Editor and that their positions correspond to where you want your character to be able to hit. Also, ensure thatSideAttackArea
,UpAttackArea
, andDownAttackArea
have sensible sizes that match your intended attack hitboxes. -
Layer Mask for Attackable Objects: Make sure that the objects you are trying to hit are on the correct layer that corresponds to
attackableLayer
. If these objects are not on this layer, they won’t be detected by the attack. -
Check for Collider Issues: Ensure that the colliders of the attackable objects are set up correctly, and that they are not disabled or set to a layer that doesn’t interact with the player’s attack layer.
-
Unity Physics Settings: Make sure that the Physics2D settings in Unity do not have any issues that could prevent the overlaps from registering correctly.
-
Testing Hit Detection: If you’re still having issues, consider simplifying the
Hit
method to just log the position and size of the attack area:void Hit(Transform _attackTransform, Vector2 _attackArea) { Debug.Log($"Attacking at {_attackTransform.position} with area {_attackArea}"); Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer); Debug.Log($"Objects hit: {objectsToHit.Length}"); }
By checking these points, you should be able to identify and fix the issue with your attack not registering. If you’ve checked all of these and it still isn’t working, feel free to provide more details about what is happening when you attempt to attack, and I’ll do my best to assist further!
February 26, 2025 at 8:50 pm #17340::@joshkelly if your issue is still not fixed, record a video of the attacks using ScreenToGif and post it here. I will have a look at it for you.
-
-
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: