Forum begins after the advertisement:
[Part 3] Recoil will still not work no matter what I try
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [Part 3] Recoil will still not work no matter what I try
- This topic has 12 replies, 3 voices, and was last updated 2 weeks ago by
Terence.
-
AuthorPosts
-
March 6, 2025 at 1:30 pm #17397::
Idk what to do I did most things suggested but it just will not work so help idk if its something to do with the inspector or something else
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("Attacking")] bool attack = false; float timeBetweenAttack, timeSinceAttack; [SerializeField] Transform SideAttackTransform, UpAttackTransform, DownAttackTransform; [SerializeField] Vector2 SideAttackArea, UpAttackArea, DownAttackArea; [SerializeField] LayerMask attackableLayer; [SerializeField] float damage; [SerializeField] GameObject slashEffect; [Space(5)] [Header("Recoiling")] [SerializeField] int recoilXSteps = 5; [SerializeField] int recoilYSteps = 5; [SerializeField] float recoilXSpeed = 100; [SerializeField] float recoilYSpeed = 100; int stepsXRecoiled, stepsYRecoiled; 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 } 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(); Recoil(); if (pState.dashing) return; Flip(); Move(); Jump(); StartDash(); Attack(); } void GetInputs() { xAxis = Input.GetAxisRaw("Horizontal"); yAxis = Input.GetAxisRaw("Vertical"); attack = Input.GetMouseButtonDown(0); } void Flip() { if (xAxis < 0) { transform.localScale = new Vector2(-1, transform.localScale.y); pState.lookingRight = false; } else if (xAxis > 0) { transform.localScale = new Vector2(1, transform.localScale.y); pState.lookingRight = true; } } 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) { } else if (dashed) { } else { StartCoroutine(Dash()); dashed = true; } } if (Grounded()) { dashed = false; } } IEnumerator Dash() { 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 } 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, 80, UpAttackTransform); } else if(yAxis < 0 && !Grounded()) { Hit(DownAttackTransform, DownAttackArea, ref pState.recoilingY, recoilYSpeed); SlashEffectAtAngle(slashEffect, -90, DownAttackTransform); } } } void Hit(Transform _attackTransform, Vector2 _attackArea, ref bool _recoilDir, float _recoilStrength) { Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer); if(objectsToHit.Length > 0) { _recoilDir = true; // Here you should set the corresponding state in PlayerStateList } for(int i = 0; i < objectsToHit.Length; i++) { if(objectsToHit[i].GetComponent<Enemy>() !=null) { objectsToHit[i].GetComponent<Enemy>().EnemyHit(damage, (transform.position - objectsToHit[i].transform.position).normalized, _recoilStrength); } } } 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, _attackTransform.localScale.y); } void Recoil() { Debug.Log("Recoil"); if(pState.recoilingX) { if(pState.lookingRight) { rb.velocity = new Vector2(-recoilXSpeed, 0); } else { rb.velocity = new Vector2(recoilXSpeed, 0); } } if(pState.recoilingY) { rb.gravityScale = 0; if (yAxis < 0) { rb.velocity = new Vector2(rb.velocity.x, recoilYSpeed); } else { rb.velocity = new Vector2(rb.velocity.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 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, rb.velocity.y * 0.5f); // Reduce jump height 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; jumpBufferCounter = 0; // Reset jump buffer when grounded } else { coyoteTimeCounter -= Time.deltaTime; } if (Input.GetButtonDown("Jump")) { jumpBufferCounter = jumpBufferFrames; } else { jumpBufferCounter = jumpBufferCounter - Time.deltaTime *10; } } }
March 6, 2025 at 5:43 pm #17399::I figured out that the enemy moves when i attack it when increasing or decreasing recoilxspeed but not the player and the player gets sent when i attack from above
March 6, 2025 at 5:50 pm #17400::It seems like you’re trying to manage the movement behavior of both the enemy and the player in your game, particularly in response to attacks. If the enemy is moving when you attack it but the player is not behaving as expected, there may be several factors at play. Here’s a general approach to debug and resolve this issue:
-
Check Player Movement Logic: Ensure that the player movement logic is correctly implemented. If you want the player to move or react to attacks, you need to ensure that the movement code is triggered in response to the attack.
-
Verify Attack Logic: When you perform an attack, ensure that the correct events are being fired. For example, check if the attack triggers any movement changes for the player.
-
Recoil Logic: If you are using
recoilxspeed
to adjust movement, ensure that this variable is applied to the player’s movement logic when they are attacked. You might need a separate function that handles the recoil for the player. -
Collision Detection: If the player is being sent flying when attacking from above, check your collision detection logic. It’s possible that the attack from above has a different set of rules compared to other angles.
-
Debugging: You can add debug prints or logs to help you understand what values are being processed when the player attacks. For instance, print the current position, speed, and any other relevant variables whenever an attack is initiated.
-
Handling States: If your game uses states (like idle, attacking, etc.), make sure the player is in the correct state when an attack is performed. If the player is in an “attacking” state, you might want to prevent movement or apply different movement logic.
-
Test Different Scenarios: Try attacking from various angles and distances to see if the behavior changes. This can help isolate the problem.
If you can provide a snippet of your code related to player movement and attack handling, I can offer more specific assistance to help you resolve the issue.
March 6, 2025 at 10:06 pm #17404::I figured out that the enemy moves when i attack it when increasing or decreasing recoilxspeed but not the player and the player gets sent when i attack from above
Is your issue fixed?March 7, 2025 at 4:29 am #17412::No idk how to fix it I just realised that my enemy moves with recoilxspeed instead of my player
March 7, 2025 at 1:03 pm #17415::Can you upload your project onto Google Drive and share the link here? I will help you have a look.
March 8, 2025 at 7:00 pm #17441March 8, 2025 at 7:05 pm #17442::It looks like you’re trying to create a hyperlink in HTML that directs users to a Google Drive folder. The code you’ve provided seems mostly correct. Here’s a breakdown of your code:
<a href="https://drive.google.com/drive/folders/1R8Nfe2o0aC4lQGFnEKB20WTRsQ5kbqJc?usp=drive_link" target="_blank">This should bring you to it</a>
Explanation:
<a>
: This is the anchor tag used to create hyperlinks.href
: This attribute specifies the URL of the page the link goes to.target="_blank"
: This attribute opens the link in a new tab.- The text between the opening and closing
<a>
tags (“This should bring you to it”) is what users will see and click on.
Improvements:
- Accessibility: Consider adding
rel="noopener noreferrer"
to your link for security reasons when usingtarget="_blank"
.
Here’s the improved version of your code:
<a href="https://drive.google.com/drive/folders/1R8Nfe2o0aC4lQGFnEKB20WTRsQ5kbqJc?usp=drive_link" target="_blank" rel="noopener noreferrer">This should bring you to it</a>
Usage:
You can use this code snippet in your HTML file where you want the link to appear. When users click on “This should bring you to it,” they will be redirected to the specified Google Drive folder in a new tab.
If you have any specific issues or additional questions about your code, feel free to ask!
March 9, 2025 at 1:24 pm #17451March 10, 2025 at 8:01 am #17466March 10, 2025 at 8:00 pm #17481::@joshkelly sorry I still don’t have access. Check your Gmail. An access request should have been sent to you.
March 12, 2025 at 3:48 pm #17520March 12, 2025 at 3:51 pm #17521::No problem, Josh! If you need help with your code or anything else, feel free to share the details, and I’ll do my best to assist you!
March 13, 2025 at 6:03 am #17525::@joshkelly found the issue. It was with the
Move()
function inPlayerController
. You need to add the highlighted line:private void Move() { if(pState.recoilingX) return; rb.velocity = new Vector2(Walkspeed * xAxis, rb.velocity.y); anim.SetBool("Walking", rb.velocity.x != 0 && Grounded()); }
The prevents the character from moving around when we are recoiling. Otherwise, the Move() function will overwrite the recoilX force by resetting the velocity. It’s a bug that we missed out when making the video.
Hope this helps!
March 18, 2025 at 2:14 pm #17559 -
-
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: