Slow down player gradually using rigidbody? - c#

I'm making a 2D platformer and want the player to slowly slow down after releasing the left/right buttons.
I haven't found any good solutions on the internet. Here is my code:
bool isSprinting = Input.GetButton("Sprint");
float playerInput = Input.GetAxis("Horizontal");
if(!isSprinting)
{
rb.velocity = new Vector2(playerInput * moveSpeed, rb.velocity.y);
}
else
{
rb.velocity = new Vector2(playerInput * runSpeed, rb.velocity.y);
}
if(rb.velocity.x > 0)
{
transform.localScale = Vector3.one;
}
else if(rb.velocity.x < 0)
{
transform.localScale = new Vector3(-1f, 1f, 1f);
}

You can manually reduce the velocity, use Rigidbody2D.Drag, or use Input smoothening.
To manually slow down the Rigidbody2D, you could do something like the following. This should only be done in a FixedUpdate to keep consistent behavior even with varying frame rates.
const float SMALL_INPUT_CONSTANT = 0.01f;//increase to slow down even if a controller's joystick is slightly pressed
const float LERP_CONST_BETWEEN_0_AND_1 = 0.05f;//increase to slow down faster
if(Mathf.Abs(playerInput) < SMALL_INPUT_CONSTANT){
rb.velocity = new Vector2(Mathf.Lerp(rb.velocity.x, 0, LERP_CONST_BETWEEN_0_AND_1), rb.velocity.y);
}
else
{
//insert other movement code here (the if(!isSprinting)...else... code you posted), because you shouldn't set the velocity if the user isn't giving `Horizontal` input
}
You can increase Rigidbody2D.Drag in the Editor, it's labeled as Linear Drag. This will make the Rigidbody2D fall like a feather, so only use it if that's what you want.
I haven't used Input smoothening, but I think it would be the Gravity variable in the Input Manager.

Related

Stuck in walls using a Rigidbody Movement Unity 3D

I am in the process of creating movement for my player that can only move on the x and y axis, I decided to make it a 3D game because I've been trying to learn that dimension of games. My movement functions are set up as so:
public void playerMovement()
{
horizontalInput = (int)Input.GetAxisRaw("Horizontal");
if (horizontalInput != 0)
{
moveX = Mathf.MoveTowards(moveX, horizontalInput * speed, Time.deltaTime * acceleration);
} else
{
moveX = Mathf.MoveTowards(moveX, horizontalInput * speed, Time.deltaTime * acceleration * 4f);
}
rb.velocity = new Vector3(moveX, rb.velocity.y, 0);
grounded = Physics.CheckSphere(groundCheck.transform.position, .2f, LayerMask.GetMask("Ground"));
if (Input.GetKeyDown(KeyCode.UpArrow))
{
Jump();
}
}
public void Jump()
{
if (grounded)
{
rb.velocity = new Vector3(rb.velocity.x, jumpSpeed, 0);
}
}
I am using this code from a tutorial I found on Tiktok and everything works well in the update function, however, when I collide with a wall or the side of any of my objects, I stop in place and can't fall back down. I also can't move out of the area very fast, it takes about 3 seconds to move out of there(I predict from my acceleration slowing down and turning around).
Is there a reason I am stuck on the wall once I collide?

WASD movement in unity2d

I'm new to unity and wanted to know how can i set the A and D keys to move me right and left with Rigidbody2D. I found this script on a forum but it doesn't seem to work:
public float speed = 5f;
private float movement = 0f;
private Rigidbody2D rigidBody;
// Use this for initialization
void Start()
{
rigidBody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
movement = Input.GetAxis("Horizontal");
if (movement > 0f)
{
rigidBody.velocity = new Vector2(movement * speed, rigidBody.velocity.y);
}
else if (movement < 0f)
{
rigidBody.velocity = new Vector2(movement * speed, rigidBody.velocity.y);
}
else
{
rigidBody.velocity = new Vector2(0, rigidBody.velocity.y);
}
}
Is there an error being thrown?
First thing to check is that whatever you have attached this script to actually has a Rigidbody2D.
Physics, ie setting rigidbody speeds, should be done in FixedUpdate rather than Update, if you look that up and it seems too confusing right now don't worry, you can get away with this for now.
Perhaps you should try using rb.AddForce(movement * speed, ForceMode2D.Impluse);.
Since the var movement will actually be positive or negative depending on what key you press, the first two bits of the if statements don't have any use.
Try out looking at this for a single tutorial about moving the player.

How do I move the Rigidbody in FixedUpdate, but still have my character be affected by gravity?

So
Below you see what I initially used to control my characters movement.
_RigidBody.velocity = _ConstantWalkingSpeed * direction.normalized;
This works for walking around in 4 directions. However, if my character falls over an edge, he falls veeeeeery slowly. If I then in mid air disable the walking script, gravity picks up and goes at normal speed.
This leads me to believe that my movement script somehow affects the gravity effect.
As such I tried this solution:
_RigidBody.velocity = _ConstantWalkingSpeed * direction.normalized + new Vector3(0f, _RigidBody.velocity.y, 0f);
That didn't work either, so I tried this:
_RigidBody.velocity = _ConstantWalkingSpeed * direction.normalized + new Vector3(0f, _RigidBody.velocity.y, 0f) + Physics.gravity;
That did make the gravity work, but then the gravity became so strong that I can't move.
I tried only adding Physics.gravity and skipping the new vector part, but then the gravity is still too strong.
TL;DR
The movement script I use affects the players downward gravity, which it shouldn't. I want him to move around but still be affected by gravity. Ideas I have tried didn't work.
Please note that I'd prefer to keep the gravity at -9.81.
Hoping you guys have a suggestion that works :-)
Instead of setting or modifying the velocity, You can use RigidBody.movePositon:
Here is a quick example script I wrote up:
using UnityEngine;
public class simpleMoveRB : MonoBehaviour {
public Rigidbody myBody;
public float _constantWalkSpeed = 3.0f;
Vector3 moveDirection = Vector3.zero;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update() {
if (Input.GetKey(KeyCode.A))
{
moveDirection.x = -1.0f;
}
else if(Input.GetKey(KeyCode.D))
{
moveDirection.x = 1.0f;
}
else
{
moveDirection.x = 0.0f;
}
if(Input.GetKeyDown(KeyCode.Space))
{
myBody.AddForce(Vector3.up * 500.0f);
}
}
private void FixedUpdate()
{
myBody.MovePosition(transform.position + moveDirection * _constantWalkSpeed * Time.deltaTime);
}
}
You can handle movement using this script, and still have gravity work on your object.
Instead of setting the velocity, modify the velocity.
You're overwriting any velocity applied by the physics engine (e.g. gravity) with your input.
_RigidBody.velocity += _ConstantWalkingSpeed * direction.normalized;
You may also want to cap the velocity X and Z values to a maximum:
Vector3 vel = _RigidBody.velocity;
vel.x = Mathf.Min(vel.x, ConstantWalkingSpeed);
vel.z = Mathf.Min(vel.z, ConstantWalkingSpeed);
_RigidBody.velocity = vel;

Unity Player falling very slowly

I created controls for a 3D Platformer game. Somehow the player is falling down very very slowly.
My player object got 2 components, the default capsule collider and the default Rigidbody. I didnt change anything there.
So my code is this one here:
float movementSpeed = 8;
float currentMovementSpeed;
float speedSmoothTime = 0.1f;
float turnSmoothTime = 0.2f;
float jumpPower = 5;
float airControlPercentage = 0.2f;
float turnSmoothVelocity;
float speedSmoothVelocity;
bool isGrounded;
private void FixedUpdate()
{
isGrounded = GroundCheck(); // Is player grounded?
Vector2 inputDirection = (new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"))).normalized;
if (Input.GetButtonDown("Jump") && isGrounded) // Jump handling
Debug.Log("Player Jump");
if (inputDirection != Vector2.zero)
transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(transform.eulerAngles.y, Mathf.Atan2(inputDirection.x, inputDirection.y) * Mathf.Rad2Deg + cameraTransform.eulerAngles.y, ref turnSmoothVelocity, GetModifiedSmoothTime(turnSmoothTime)); // Rotate
currentMovementSpeed = Mathf.SmoothDamp(currentMovementSpeed, movementSpeed * inputDirection.magnitude, ref speedSmoothVelocity, GetModifiedSmoothTime(speedSmoothTime));
playerRigid.velocity = transform.forward * currentMovementSpeed + Vector3.up * playerRigid.velocity.y * Time.deltaTime; // Move
currentMovementSpeed = (new Vector2(playerRigid.velocity.x, playerRigid.velocity.z)).magnitude;
}
private float GetModifiedSmoothTime(float smoothTime) // Limit the control while in air
{
if (isGrounded)
return smoothTime;
if (airControlPercentage == 0)
return float.MaxValue;
return smoothTime / airControlPercentage;
}
private bool GroundCheck() // Player is grounded?
{
if (true)
return true;
return false;
}
Does someone knows what to do here?
It probably has something to do with your current gravity. Check in edit -> project settings -> physics the value of your gravity. In my case is -9,81. Change it to a higher value and see what happens.
I finally got it. How to fix it:
In this line of code
playerRigid.velocity = transform.forward * currentMovementSpeed + Vector3.up * playerRigid.velocity.y * Time.deltaTime;
Take out
* Time.deltaTime
Now the player is falling correctly.
Actually , transform.forward effect the y component of the body thus effects the gravity acting on the body.
Use
rb.velocity = new Vector3(horizontal , -1 , vertical) * speed ; .
It will work, or simply use AddForce to drive the player.
when you want to use gravity calculations, changing the rigidbody in your code can do this.
//rb.velocity = moveInput * moveSpeed;
for example will screw with your movement, even when a button isn't being pressed.
using something like:
if(Input.GetButtonDown("Jump") && Mathf.Abs(rb.velocity.y) < 0.001f)
{
rb.AddForce(new Vector2(0, jumpForce), ForceMode2D.Impulse);
}
will simply add forces on top of the calculations, instead of changing them prior to
In my case, the slow descending of my game character was solved by eliminating unnecessary calls to the physics system in the FixedUpdate() function. For example, when a joystick's X-axis and/or Y-axis are in the zero position.
I call addForce, velocity, rb transforms, etc. only if the absolute joystick value (- and +) exceeds a minimum value, in my case 0.04. Without these tests, these physics calls are done every time FixedUpdate() is called. This seems to overload the physics system, because at the same time, physics is also processing gravity etc.
Note that merely setting the joystick's dead zones in the Unity Input System doesn't solve this problem.
void FixedUpdate()
{
if (Mathf.Abs(stick.x) > 0.04) // prevent unnecessary physics call.
{
rb.transform.eulerAngles = rb.transform.eulerAngles - new Vector3(0, stick.x * Time.deltaTime * RotationSpeed * -1, 0);
}
if (Mathf.Abs(stick.y) > 0.04) // prevent unnecessary physics call.
{
rb.velocity = transform.forward * stick.y * Speed * Time.deltaTime;
}
}

Unity 2D Top Down Shooter movement issue C#

I am trying to make a simple 2D Top-Down Shooter in Unity. I have the basic movement and following of the mouse, but there is an issue in the movement.
Whenever you press say Up and Right at the same time, it moves diagonally as you would expect, but when you let go of the Up key, it keeps going diagonally where I want it to move Right. My code for handling the movement is:
private void Update ()
{
if (Input.GetKey(Up)) {
Debug.Log("UP");
Vector3 velUp = rigidbody2D.velocity;
velUp.y = walkSpeed;
rigidbody2D.velocity = velUp;
}
else if (Input.GetKey(Down)) {
Vector3 velDown = rigidbody2D.velocity;
velDown.y = walkSpeed*-1;
rigidbody2D.velocity = velDown;
}
else if (Input.GetKey(Left)) {
Vector3 velLeft = rigidbody2D.velocity;
velLeft.x = walkSpeed*-1;
rigidbody2D.velocity = velLeft;
}
else if (Input.GetKey(Right)) {
Vector3 velRight = rigidbody2D.velocity;
velRight.x = walkSpeed;
rigidbody2D.velocity = velRight;
}
else {
Vector3 velStop = rigidbody2D.velocity;
velStop.x = 0;
velStop.y = 0;
rigidbody2D.velocity = velStop;
}
//rotation
Vector3 mousePos = Input.mousePosition;
Vector3 objectPos = Camera.main.WorldToScreenPoint (transform.position);
mousePos.x = mousePos.x - objectPos.x;
mousePos.y = mousePos.y - objectPos.y;
float angle = Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}
How can I get the movement to behave as I mentioned? With it moving diagonally like this makes the movement seem off.
Any help is greatly appreciated. Thanks.
You start with a velocity of 0, then you add up all the movements directions you have. Then you normalize the vector and scale it to your movement speed. Otherwise the player moves faster, if walking diagonal.
I haven't checked the code, but something like this will do:
void Update () {
Vector3 vel = new Vector3();
if(Input.GetKey(Up)){
Debug.Log("UP");
Vector3 velUp = new Vector3();
// just use 1 to set the direction.
velUp.y = 1;
vel += velUp;
}
else if(Input.GetKey(Down)){
Vector3 velDown = new Vector3();
velDown.y = -1;
vel += velDown;
}
// no else here. Combinations of up/down and left/right are fine.
if(Input.GetKey(Left)){
Vector3 velLeft = new Vector3();
velLeft.x = -1;
vel += velLeft;
}
else if(Input.GetKey(Right)){
Vector3 velRight = new Vector3();
velRight.x = 1;
vel += velRight;
}
// check if player wants to move at all. Don't check exactly for 0 to avoid rounding errors
// (magnitude will be 0, 1 or sqrt(2) here)
if (vel.magnitude > 0.001) {
Vector3.Normalize(vel);
vel *= walkSpeed;
rigidbody2D.velocity = vel;
}
//rotation
Vector3 mousePos = Input.mousePosition;
Vector3 objectPos = Camera.main.WorldToScreenPoint (transform.position);
mousePos.x = mousePos.x - objectPos.x;
mousePos.y = mousePos.y - objectPos.y;
float angle = Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}
Regarding Normalize have a look at this image.
If you walk only upwards or right you would move with speed 1 (which we later multiply with your desired speed). But if you walk diagonal you walk with about 1.4 times the desired speed (green vector). Normalize keeps the direction of the vector intact, but gives you a length (also called "magnitude") of 1 (red vector).
In older shooters you may find a bug called "bunny hopping". I'm not sure if this is the source of the problem, but I would guess it is.
Regarding vel.magnitude > 0.001:
We actually want to know if vel.magnitude > 0. But vel.magnitude is the result of a calculation and thus may contain rounding errors. If you work with floating-point values always keep that in mind. The check itself is done because the Normalize method needs to divide by the magnitude and division by zero is evil. Not sure if Normalize checks for this itself.
It seems the only time you force your velocity to nothing is when there isn't any key being pressed.
I might suggest adding some checks to see when Input.GetKeyUp is true, and set the rigidbody2D.velocity's x or y values to 0, maybe something like this:
void Update () {
if (Input.GetKeyUp(Up) || Input.GetKeyUp(Down)) {
rigidbody2D.velocity.y = 0;
}
if (Input.GetKeyUp(Left) || Input.GetKeyUp(Right)) {
rigidbody2D.velocity.x = 0;
}
...

Categories