I’m currently working on a personal project and I need a rocket jump to work. I’m having trouble in that I can’t get the rocket jump to send my player in a diagonal or sideways direction, it only sends them upwards. Here’s the code that controls how the explosions work:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rocket : MonoBehaviour
{
[SerializeField] private float rocketTime;
[SerializeField] private float explosionRadius;
[SerializeField] private float explosionForce;
private void Start()
{
// Destroy the rocket after a set time if it doesn't collide
Destroy(gameObject, rocketTime);
}
private void OnCollisionEnter2D(Collision2D collision)
{
// Apply explosion logic and destroy the rocket
ApplyExplosion();
Destroy(gameObject);
}
private void ApplyExplosion()
{
// Check for collision with the player within the explosion radius
Collider2D playerCollider = Physics2D.OverlapCircle(transform.position, explosionRadius, LayerMask.GetMask("Player"));
if (playerCollider != null && playerCollider.CompareTag("Player"))
{
Rigidbody2D rb = playerCollider.GetComponent<Rigidbody2D>();
PlayerMovement playerMovement = playerCollider.GetComponent<PlayerMovement>();
if (rb != null && playerMovement != null)
{
// Calculate the direction from the explosion to the player
Vector2 direction = playerCollider.transform.position - transform.position;
// Calculate the distance between the explosion and the player
float distance = direction.magnitude;
// Apply force based on the square root of the distance (multiplied by a constant)
float force = Mathf.Sqrt(distance) * explosionForce;
// Normalize the direction and apply the force
direction.Normalize();
rb.AddForce(direction * force, ForceMode2D.Impulse);
// Set isRocketJumping to true if the player is in the air
if (!playerMovement.IsGrounded)
{
playerMovement.SetRocketJumping(true);
}
}
}
}
private void OnDrawGizmosSelected()
{
// Visualize the explosion radius in the editor
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, explosionRadius);
}
}
Here’s some more code that further shows what I’m trying to achieve:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
[Tooltip("Controls movement speed of the player")]
[SerializeField] private float runSpeed;
[Tooltip("Controls force applied when the player jumps")]
[SerializeField] private float jumpForce;
[Tooltip("Adjustable distance used to check if the player is grounded")]
[SerializeField] private float groundCheckDistance;
[Tooltip("Select which layer is treated as the Ground layer")]
[SerializeField] private LayerMask groundLayer;
[Tooltip("Controls how far the player will slide when they come to a stop")]
[SerializeField] private float friction;
[Tooltip("Value to track the current velocity of the smooth damp")]
[SerializeField] private float velocityX;
[Tooltip("Controls how much the player can control movement in the air")]
[SerializeField] private float airControlFactor;
[Tooltip("Controls how much time the player has left to jump after leaving the ground")]
[SerializeField] private float coyoteTime;
[Tooltip("Controls how much time the player has to queue a jump before they land")]
[SerializeField] private float jumpBufferTime;
public bool IsGrounded => isGrounded;
private bool isRocketJumping = false;
private float jumpBufferCounter;
private float coyoteTimeCounter;
private Rigidbody2D rb;
private bool isGrounded;
private void Start()
{ rb = GetComponent<Rigidbody2D>(); }
private void Update()
{
Move();
Jump();
GroundCheck();
}
/// <summary>
/// This method allows for air control while the player isn't grounded and by fluidly reducing the movement to 0 using SmoothDamp, it simulates friction.
/// </summary>
private void Move()
{
float moveInput = Input.GetAxisRaw("Horizontal");
// Adjust air control factor if rocket jumping
float currentAirControlFactor = isRocketJumping ? airControlFactor * 1.5f : airControlFactor;
// Reduces the player's movement by the air control factor when the player isn't grounded
if (!isGrounded)
{ moveInput *= currentAirControlFactor; }
if (moveInput == 0 && isGrounded)
{
float targetVelocityX = Mathf.SmoothDamp(rb.velocity.x, 0, ref velocityX, friction);
if (Mathf.Abs(targetVelocityX) < 0.01f)
{ targetVelocityX = 0f; }
rb.velocity = new Vector2(targetVelocityX, rb.velocity.y);
}
else
{
rb.velocity = new Vector2(moveInput * runSpeed, rb.velocity.y);
velocityX = rb.velocity.x;
}
}
public void SetRocketJumping(bool state)
{ isRocketJumping = state; }
/// <summary>
/// This method allows the player to have some time to jump after leaving the ground and allows for them to queue their jumps.
/// It also allows the player to jump higher based on how long the jump button is held for.
/// </summary>
private void Jump()
{
if (isGrounded)
{ coyoteTimeCounter = coyoteTime;}
else
{ coyoteTimeCounter -= Time.deltaTime; }
// Queues a jump after the button is pressed otherwise the buffer time is reduced when no jump input is given
if (Input.GetButtonDown("Jump"))
{ jumpBufferCounter = jumpBufferTime; }
else
{ jumpBufferCounter -= Time.deltaTime; }
if (coyoteTimeCounter > 0f && jumpBufferCounter > 0f)
{
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
jumpBufferCounter = 0f;
coyoteTimeCounter = 0f;
}
// If the jump button is released while jumping, the vertical jump is halved which gives the player more control over jumps
if (Input.GetButtonUp("Jump") && rb.velocity.y > 0f)
{ rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * 0.5f); }
}
/// <summary>
/// This method uses a raycast to check if the player is grounded by casting a ray downwards from the player's position.
/// If the ray hits what ever is set as the ground layer, then the boolean isGrounded is set to True.
/// </summary>
private void GroundCheck()
{
Vector2 position = transform.position;
Vector2 direction = Vector2.down;
float distance = groundCheckDistance;
RaycastHit2D hit = Physics2D.Raycast(position, direction, distance, groundLayer);
isGrounded = hit.collider != null;
// Reset isRocketJumping when the player lands
if (isGrounded)
{ isRocketJumping = false; }
Debug.DrawRay(transform.position, Vector2.down * groundCheckDistance, Color.blue);
}
/// <summary>
/// Draws blue line which is just used as a visual aid for the GroundCheck method.
/// </summary>
private void OnDrawGizmos()
{
Gizmos.color = Color.blue;
Gizmos.DrawLine(transform.position, transform.position + Vector3.down * groundCheckDistance);
}
}
Any horizontal velocity change from the rocket jump is being overwritten by lines 76 and 80 in the PlayerMovement script. Instead of setting rb.velocity you should try to use AddForce to move the player’s character around. And do it from within FixedUpdate.