I wanted to do a jump similar to super mario bros meaning you can move mid air but if you move in the opposite direction that you started your jump in you will slow down. For example if u jump in the right direction but move to the left midair u can move to the left but very slowly. I tried doing it by adding a if clause that checks if the player is moving to the left and then half the player speed but for some reason that didn't work. Thanks in advance! Here's my code:
private Rigidbody rb;
[SerializeField] private float jumpForce;
[SerializeField] private float playerSpeed;
private float distToGround = 0.0051904f;
public bool isGrounded = false;
private bool _jump;
private float _horizontal;
private bool _movingLeft;
private bool _movingRight;
private bool _turnedLeft;
private bool _turnedRight;
private BoxCollider playerFeet;
private void Awake()
{
rb = gameObject.GetComponent<Rigidbody>();
}
private void Start()
{
}
private void Update()
{
GetInputs();
}
private void FixedUpdate()
{
//PlayerJump
if (_jump && _turnedRight == true)
{
transform.rotation = Quaternion.Euler(0, 0, 0);
rb.AddForce(new Vector3(0, jumpForce), ForceMode.Impulse);
_jump = false;
}
else if (_jump && _turnedLeft == true)
{
transform.rotation = Quaternion.Euler(0, -180, 0);
rb.AddForce(new Vector3(0, jumpForce), ForceMode.Impulse);
_jump = false;
}
//RotatePlayerDependingWhereHeMoves
if(_movingLeft == true && isGrounded)
{
gameObject.transform.rotation = Quaternion.Euler(0f, 180f, 0f);
_movingLeft = false;
}
if (_movingRight == true && isGrounded)
{
gameObject.transform.rotation = Quaternion.Euler(0f, 0f, 0f);
_movingRight = false;
}
//MovePlayer
rb.velocity = new Vector3(rb.velocity.x, rb.velocity.y, _horizontal * -playerSpeed);
//ChecksIfGrounded
GroundCheck();
}
void GetInputs()
{
_horizontal = Input.GetAxisRaw(Tags.HORIZONTAL_AXIS);
if(isGrounded && Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("Player pressed Jump");
_jump = true;
}
if(_horizontal == -1)
{
_movingLeft = true;
}
else if(_horizontal == 1)
{
_movingRight = true;
}
if(transform.rotation.y == 0)
{
_turnedRight = true;
}
else if(transform.rotation.y == -180)
{
_turnedLeft = true;
}
}
void GroundCheck()
{
if(Physics.Raycast(transform.position, Vector3.down, distToGround 0.1f))
{
isGrounded = true;
}
else
{
isGrounded = false;
}
}
CodePudding user response:
Compare the input to the current direction the rigidbody is moving when mid-air. Then, chip away at the speed at a desired rate. You can do this inside a different method.
private void FixedUpdate()
{
//PlayerJump
if (_jump && _turnedRight == true)
{
transform.rotation = Quaternion.Euler(0, 0, 0);
rb.AddForce(new Vector3(0, jumpForce), ForceMode.Impulse);
_jump = false;
}
else if (_jump && _turnedLeft == true)
{
transform.rotation = Quaternion.Euler(0, -180, 0);
rb.AddForce(new Vector3(0, jumpForce), ForceMode.Impulse);
_jump = false;
}
//RotatePlayerDependingWhereHeMoves
if(_movingLeft == true && isGrounded)
{
gameObject.transform.rotation = Quaternion.Euler(0f, 180f, 0f);
_movingLeft = false;
}
if (_movingRight == true && isGrounded)
{
gameObject.transform.rotation = Quaternion.Euler(0f, 0f, 0f);
_movingRight = false;
}
//MovePlayer
if (!isGrounded)
{
//since the player is not touching the ground, modify speed in here
ModifyMidAirSpeed();
}
else
{
//move player normally...
rb.velocity = new Vector3(rb.velocity.x, rb.velocity.y, _horizontal * -playerSpeed);
}
//ChecksIfGrounded
GroundCheck();
}
float air_speed_acceleration = 1.0f; //use this to change the rate at which speed is modified mid-air
void ModifyMidAirSpeed()
{
Vector3 new_velocity = rb.velocity;
//check if the rb's is moving on the horizontal axis
if (rb.velocity.x != 0)
{
//is the moving direction the same as the input?
bool isRBMovingRight = rb.velocity.x > 0;
if (isRBMovingRight && _movingRight)
{
//yes it is
//accelerate mid-air?
new_velocity.x = Mathf.Lerp(new_velocity.x, _horizontal * -playerSpeed, air_speed_acceleration * Time.fixedDeltaTime);
rb.velocity = new_velocity;
return;
}
//no it is not!
//slow down mid-air
new_velocity.x = Mathf.Lerp(0, new_velocity.x, air_speed_acceleration * Time.fixedDeltaTime);
rb.velocity = new_velocity;
return;
}
//the player jumped while standing still
//move towards desired direction mid-air?
new_velocity.x = Mathf.Lerp(0, _horizontal * -playerSpeed, air_speed_acceleration * Time.fixedDeltaTime);
rb.velocity = new_velocity;
}
Above, I wrote an example which should allow you to reduce the player's velocity mid-air. You can use the method ModifyMidAirSpeed
when the player is not touching the ground to handle mid-air movement and keep your code separated and tidy.
I would also recommend storing input as a Vector2. This will allow you to use fewer variables (I'm talking about _movingLeft
and _movingRight
) and should prove helpful in the future.
CodePudding user response:
public class PlayMovement : MonoBehaviour
{
//Character's blood volume
public int Hp = 1;
// is it on the ground
private bool isGround = false;
//rigid body
private Rigidbody2D rBody;
//animation
private Animator ani;
//Get the sprite image (in order to flip the image later)
private SpriteRenderer sr;
void Start () {
//Get these two components here
rBody = GetComponent<Rigidbody2D>();
ani = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
void Update() {
if (Hp <= 0)
{
return;
}
//Because the character just runs left and right, take the horizontal axis
float horizontal = Input.GetAxis("Horizontal");
//if the horizontal axis is not 0
if (horizontal != 0)
{
//go ahead
transform.Translate(transform.right * Time.deltaTime * 1 * horizontal);
//Flip the picture (simulate turning the head)
if (horizontal > 0)
{
//The description is to go to the right, so it does not flip
sr.flipX = false;
}
if (horizontal < 0)
{
sr.flipX = true;
}
//move animation
ani.SetBool("Run", true);
}
else
{
ani.SetBool("Run", false);
}
//jump. The I key is pressed, and the character is standing on the ground.
if (Input.GetKeyDown(KeyCode.I) && isGround == true)
{
//Jump force (up, acting on rigid body)
rBody.AddForce(Vector2.up * 200);
//Play the jump sound
AudioManager.Instance.PlaySound("jump");
}
//Use the ray to detect whether it touches the ground (method 1)
//Draw the ray. Starting from the center point, go down *0.1 meters.
Debug.DrawRay(transform.position, Vector2.down * 0.1f);
/* Create 2d rays. Features: You can return directly. 3d returns a boolean value, hit is on it, and out is used to give the hit value.
And in the brackets, you can directly fill in the starting point, direction, distance, and detection layer of the ray (here is the 8th layer). */
RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.down, 0.1f, 1<<8);
if(hit.collider != null)
{
//Indicate that it hit the ground
isGround = true;
//Turn off the jump animation
ani.SetBool("Jump", false);
}
else
{
// did not touch the ground (in the air)
isGround = false;
ani.SetBool("Jump", true);
}
}
//The player's death method, because it is called in the enemy's code, is public here
public void Die()
{
Hp--;
if (Hp <= 0)
{
//die
ani.SetTrigger("Die");
// delete the collider. (Because when the player dies, it is dropped from the scene, so just delete the collider, not the rigid body).
Destroy(GetComponent<Collider2D>());
//stop playing background music
AudioManager.Instance.StopMusic();
//play death music
AudioManager.Instance.PlaySound("death");
// make the player still
rBody.velocity = Vector2.zero;
// Make the player still, i.e. set its speed to 0. In order to prevent the player from dying in different situations, the height of the upward jump is different)
rBody.velocity = Vector2.zero;
//jump. give an upward force
rBody.AddForce(Vector2.up * 150f);
// Delay. Play after 1 second
Invoke("Die2", 1f);
}
}
void Die2()
{
AudioManager.Instance.PlaySound("Death 2");
}
}
Here's the script code for Mario PlayControl, hope it helps, as you provide the code to test it's hard