Forum begins after the advertisement:
Hey my attacks will not register attacking help me find whats wrong in my code.
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › Hey my attacks will not register attacking help me find whats wrong in my code.
- This topic has 1 reply, 3 voices, and was last updated 1 day, 23 hours ago by
Ser Apustaja.
-
AuthorPosts
-
February 26, 2025 at 8:02 pm #17334::
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 #17336::Your code for the
PlayerController
looks quite comprehensive, but it seems like you might have some issues with the logic or functionality. Here are a few suggestions and common pitfalls you might want to check:-
HTML Entities in Code: It looks like you’ve copied the code with HTML entities instead of regular symbols. Make sure to replace instances of
<
with `, and
&with
&`. This is crucial for your code to compile properly. -
Jump Logic: Ensure that your jump logic works as intended. The jump buffer and coyote time are good practices, but make sure that
jumpBufferCounter
andcoyoteTimeCounter
are properly used. For instance, you should resetjumpBufferCounter
when you jump. -
Dash Logic: The dash logic appears to be functional, but ensure that your
dashCooldown
anddashTime
values are set appropriately in the inspector. The print statements will help you debug if your dash is being triggered correctly. -
Animation States: Make sure that your Animator Controller has the proper transitions for “Walking”, “Jumping”, “Dashing”, and “Attacking”. Missing transitions or incorrect parameter names can lead to animations not playing as expected.
-
Ground Check Logic: Your
Grounded
method uses raycasting to check for the ground. Ensure that yourgroundCheckPoint
,groundCheckY
, andwhatIsGround
are set correctly in the inspector. If the raycast is not hitting anything, the character may not be recognized as grounded. -
Attack Logic: Your attack method might need a check to see if the player is currently attacking before allowing another attack. You might want to add a boolean flag to prevent spamming attacks.
-
Debugging: Use Debug.Log statements liberally to help track down any issues. For instance, log the values of
jumpBufferCounter
,coyoteTimeCounter
, and other key variables at various points in your code. -
Testing: If the player isn’t moving or jumping as expected, double-check your input settings in Unity (Edit > Project Settings > Input) to ensure that “Horizontal”, “Vertical”, “Jump”, and “Dash” are set up correctly.
Here’s a quick fix for the HTML entities in the
Flip
function as an example:void Flip() { if (xAxis 0) { transform.localScale = new Vector2(1, transform.localScale.y); } }
Make sure to go through your entire script and replace all instances of HTML entities with the correct symbols. If you continue to face issues, please provide specific error messages or describe what behavior is not functioning as expected!
February 26, 2025 at 8:46 pm #17338::@ser.apustaja, please try again. He says his attacks will not register attacking. Can you scan through the code again and find out why?
Treat any HTML characters as the characters they represent, and access the code only for C#.
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:50 pm #17341::Based on the provided code for the
PlayerController
class, it looks like you’ve implemented a basic attack system. If the attacks are not registering, there are a few potential areas that could be causing the issue. Here are some things to check and suggestions for debugging:-
Attack Input Handling:
- Ensure that the “Fire1” input is correctly set up in your Input settings in Unity. By default, “Fire1” is usually mapped to the left Ctrl key or mouse button.
- Check if the
attack
variable is being set correctly when the attack button is pressed. You can add a debug log inGetInputs()
to confirm that the input is being detected:void GetInputs() { xAxis = Input.GetAxisRaw("Horizontal"); yAxis = Input.GetAxisRaw("Vertical"); attack = Input.GetButtonDown("Fire1"); Debug.Log($"Attack input: {attack}"); }
-
Time Between Attacks:
- Make sure that
timeBetweenAttack
is set to a reasonable value. If it’s too high, you might not be able to attack often enough. - If it’s not initialized anywhere in your code, it will default to
0
, which could lead to unexpected behavior.
- Make sure that
-
Attack Area and Hit Detection:
- Verify that the
SideAttackTransform
,UpAttackTransform
, andDownAttackTransform
are correctly set in the Unity Inspector. They should be positioned where you expect the attack detection to occur. - Check that
SideAttackArea
,UpAttackArea
, andDownAttackArea
have reasonable dimensions for detecting hits. If they are too small, the attack might not register. - You can log the sizes and positions of your attack areas in the
Hit
method:void Hit(Transform _attackTransform, Vector2 _attackArea) { Debug.Log($"Checking attack at position: {_attackTransform.position} with area: {_attackArea}"); // ... rest of the code ... }
- Verify that the
-
Layer Masks:
- Ensure that the
attackableLayer
mask is correctly set in the Inspector. The objects you want to hit should be on a layer that is included in this mask.
- Ensure that the
-
Physics Overlap Check:
- If the physics overlap check is not returning any colliders, it indicates that there are no objects within the specified area. Confirm that the attack areas are indeed overlapping with the objects you expect to hit.
-
Animator Triggers:
- Check if the animator is correctly set up to respond to the “Attacking” trigger. If the attack animation is not playing, it might be an indication that the Animator setup is incorrect.
By going through these checks and adding debug logs, you should be able to pinpoint where the issue lies. If after these checks the attacks are still not registering, consider isolating the attack logic in a simpler context to test it separately, ensuring that the attack mechanics work independently of other game systems.
- 1 anonymous person
-
-
AuthorPosts
- You must be logged in to reply to this topic.