Unity Player falling very slowly - c#

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;
}
}

Related

Unity GroundCheck always returning false

I'm following brackey's fps movement tutorial. I've copied all the code correctly.
but the isGrounded value is always false, even if the player is touching the ground
The Ground is also on the layer "Ground"
and here's my code
// non related varriables
public CharacterController controller;
public float speed = 12f;
//the gravity
public float gravity = -9.81f;
//the transform groundcheck, it's attached to the groundcheck object
public Transform groundCheck;
public float groundDistance = 0.4f;
// layer mask groundmask.
public LayerMask groundMask;
Vector3 velocity;
bool isGrounded;
// Update is called once per frame
void Update()
{
// check if the groundcheck transform is colliding with the ground, which always for //some reason returns false.
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
// make the set y velocity to 0. when groundcheck touches the ground
if (isGrounded && velocity.y < 0)
{
velocity.y = 0;
}
// the movement code (not related)
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
// move the player acording the gravity.
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
Since you're using CharacterController, you can use a build-in function
void Update()
{
if (controller.isGrounded && velocity.y < 0)
{
velocity.y = 0;
}
//the rest of your code
}
CharacterController docs
Two things.
First, you don't need to pass in that layer mask. Layer masks are only for when you are trying to ignore another object not detect it. So get rid of that ground mask in CheckSphere.
Second, make sure your ground has a collider and is set on. Unity physics engine looks for colliders and if it doesn't see one it won't register anything.

Unity 3D Jumping issue

I've been following along with a 3D shooter tutorial (pretty good so far) but I've hit a snag when it comes to my framerate and jumping. The framerate on my PC is just not consistent and consequently the jump height varies constantly and sometimes the character doesn't jump at all. I know handling jumping in Update (rather than FixedUpdate) can cause issues regarding framerates but the tutorial insists that using Time.deltaTime should resolve that. Any ideas on what I should do to try and keep my jumps consistent?
//Jumping
public float jumpHeight = 10f;
public Transform ground;
private bool readyToJump;
public LayerMask groundLayer;
public float groundDistance = 0.5f;
// Update is called once per frame
private void Update()
{
Jump();
PlayerMovement();
CameraMovement();
Shoot();
}
void PlayerMovement()
{
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 movement = x * transform.right + z * transform.forward;
myController.Move(movement * speed * Time.deltaTime);
//9.8 meters/second^2
velocity.y += Physics.gravity.y * Mathf.Pow(Time.deltaTime, 2) * gravityModifier;
if (myController.isGrounded)
{
velocity.y = Physics.gravity.y * Time.deltaTime;
}
myController.Move(velocity);
}
private void CameraMovement()
{
float mouseX = Input.GetAxisRaw("Mouse X") * mouseSensitivity * Time.deltaTime;
float mouseY = Input.GetAxisRaw("Mouse Y") * mouseSensitivity * Time.deltaTime;
cameraVerticalRotation -= mouseY;
cameraVerticalRotation = Mathf.Clamp(cameraVerticalRotation, minVertCameraAngle, maxVertCameraAngle);
transform.Rotate(Vector3.up * mouseX);
myHead.localRotation = Quaternion.Euler(cameraVerticalRotation, 0f, 0f);
}
void Jump()
{
readyToJump = Physics.OverlapSphere(ground.position, groundDistance, groundLayer).Length > 0;
if (Input.GetButtonDown("Jump") && readyToJump)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * Physics.gravity.y) * Time.deltaTime;
}
myController.Move(velocity);
}
Handling the acceleration yourself is a bad idea, especially in Update rather than FixedUpdate. You should know that, in real life, the velocity changes smoothly with the acceleration against time. If you draw a curve, it is a straight slope. However, in computer, if you just calculate the velocity frame by frame, the curve will be looked like stairs.
You may use the physics engine in Unity and add an instant velocity to the character when it jumps. Just let Unity handle the acceleration.
First, you need to add a Rigidbody component to it. Then, you may modify your code to:
private Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Jump()
{
readyToJump = Physics.OverlapSphere(ground.position, groundDistance, groundLayer).Length > 0;
if (Input.GetButtonDown("Jump") && readyToJump)
{
rb.velocity = Vector3.up * jumpHeight * 2f / -Physics.gravity.y * gravityModifier;
}
}
Don't forget to remove the code in PlayerMovement on handling falling after you have Use Gravity in the Rigidbody component.
Edit
If you are using CharacterController, you can only handle the acceleration yourself. You may just move the logic to FixedUpdate to solve the various height problem, or make a more accurate simulation. For example, use this to handle jumping:
velocity.y = jumpHeight * 2f / -Physics.gravity.y * gravityModifier;
and use this to handle falling:
myController.Move(velocity * Time.deltaTime + Physics.gravity * Mathf.Pow(Time.deltaTime, 2) / 2f * gravityModifier);
// Here you should check whether it will fall through the ground.
// If no, use this line to update the velocity.
velocity.y += Physics.gravity.y * gravityModifier * Time.deltaTime;
// Otherwise, update the position to make it on ground and set velocity.y to 0.

Unity Can't Do Ground Check with Objected Generated at Start Time

I have a game that generates a maze at the start of the game. The player is dropped into the maze from a height of about 10 feet or so. The problem is that if I click the player object and change the inspector from normal to debug, I see that the character is still continuously generating falling velocity. I have a sphere at the bottom of the character that is supposed to do a ground check but clearly that isn't working. This is the relevant code for one of the ground tiles and the ground check features of the character.
Ground Tile Code in GameManager.cs in Scripts folder.
var tile = Instantiate(_tilePrefab);
tile.transform.Rotate(90, 0, 0);
tile.transform.localPosition = new Vector3((x * tileWidth) + offsetTile, 0, (y * tileWidth) + offsetTile);
tile.gameObject.layer = LayerMask.NameToLayer("Ground");
tile.transform.parent = _mazePrefab;
PlayerMovement.cs in Scripts folder
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController controller;
public float speed = 15f;
public float gravity = -9.8f;
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
Vector3 velocity;
bool isGrounded;
// Update is called once per frame
void Update()
{
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if (isGrounded && velocity.y > 0)
{
velocity.y = 0f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
I have a ground layer created and everything and I have an empty that projects a sphere at the base of my character.
What am I doing wrong?
The problem must be that your gravity resetting isn’t working. I suppose you are using the tutorial from Brackeys — I have used his tutorial before, so I know it works. The problem must be that your gravity resetting. So, I go through your code. I notice there is an if statement meant to reset the velocity when the player is grounded. So, I check the isGrounded variable. The only thing that could set that incorrectly is that the maze doesn’t have the right layer. Your code does set the layer right, so I rule that one out. I then look back at the if statement. The only thing that could set it off is the second term in it:
if (... && velocity.y > 0)
Notice how later in your code the velocity rapidly decreases.
velocity.y += gravity * Time.deltaTime;
Notice how gravity is a negative variable.
float gravity = -9.8f;
And Time.deltaTime is positive. When multiplying positive and negative values, if the number of negative values in the equation is odd the result is negative, and if it is even the result is positive. Therefore, velocity decreases instead of increases.
In the if statement, you check if velocity.y > 0, in other words: if the velocity is greater than 0, do something. But according to the math, velocity is always decreasing, not increasing. But you are detecting if the velocity is above 0, not under it.
Change the if statement to:
if (isGrounded && velocity.y < 0)
Notice how I change the > to a < to detect if it is less than zero.
That would solve your problem and you could go off here, but there is something else that is less important. Notice how after your if statement, you decrease the velocity.
...
if (isGrounded && velocity.y > 0)// «— if statement.
{
velocity.y = 0f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
velocity.y += gravity * Time.deltaTime;// «—- change velocity.
...
Since after you call the if statement you change it, you won’t need to detect if the velocity is less than 0. This is because the velocity will always be slightly less than 0 at the end of each frame.
There are two things you could do here.
You could remove the second part of the if statement.
You could add the velocity change to the else of the if statement.
For 1:
if (isGrounded)
{
velocity.y = 0f;
}
For 2:
Add:
if (isGrounded)
{
velocity.y = 0f;
}
else
{
velocity.y += gravity * Time.deltaTime;
}
And remove:
controller.Move(move * speed * Time.deltaTime);
//removed this line «—-
controller.Move(velocity * Time.deltaTime);

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 bouncing when colliding with object

I have made a script with movement, that finally works as i want it to, except one thing... I want it to be a first person game, but the way the movement works now, is on the global axis, which means that W is always torwards one specific direction, no matter what direction my camera is turning... How do i fix this? i want the movement to stay how it is, but with the W key to always be forward depending on the way the camera or player is looking.
Please let me know how my script would look edited, or atleast what part i have to change.
I would also like to add that i would love to be able to do a wall jump, but i am not sure how to add that behavior.
Here is my movement script:
public class MovementScript : MonoBehaviour {
public float speed;
public float jumpforce;
public float gravity = 25;
private Vector3 moveVector;
private Vector3 lastMove;
private float verticalVelocity;
private CharacterController controller;
// Use this for initialization
void Start () {
controller = GetComponent<CharacterController> ();
//Låser og gemmer musen
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update () {
//Låser musen op
if (Input.GetKeyDown ("escape"))
Cursor.lockState = CursorLockMode.None;
moveVector = Vector3.zero;
moveVector.x = Input.GetAxis("Horizontal");
moveVector.z = Input.GetAxis("Vertical");
if (controller.isGrounded) {
verticalVelocity = -1;
if (Input.GetButton("Jump")) {
verticalVelocity = jumpforce;
}
} else {
verticalVelocity -= gravity * Time.deltaTime;
moveVector = lastMove;
}
moveVector.y = 0;
moveVector.Normalize ();
moveVector *= speed;
moveVector.y = verticalVelocity;
controller.Move (moveVector * Time.deltaTime);
lastMove = moveVector;
}
}
You need to go from local to world space:
for example when you want to move on the x-axis regarding the player's orientation, the local vector is (1, 0, 0), which you get from your input axis, but the CharacterController need a world based direction (see the doc of the Move function)
A more complex move function taking absolute movement deltas.
To get this, use Transform.TransformDirection like this
worldMove = transform.TransformDirection(moveVector);
controller.Move (worldMove * Time.deltaTime);
EDIT regarding your issue with the controller moving a bit after releasing the input:
That's because GetAxis gives you a smoothed value. Replace GetAxis by GetAxisRaw and it should work
Modify the final moving code to
controller.Move(moveVector.z * transform.forward * Time.deltaTime);
controller.Move(moveVector.x * transform.right * Time.deltaTime);
controller.Move(moveVector.y * transform.up * Time.deltaTime);
Alternatively, suppose your character is only rotated about the Y axis, you can look into rotating your moveVector by your character's Y rotation so moveVector's forward points parallel to your chracter's forward.
I found a good explaination of rotating a vector here: https://answers.unity.com/questions/46770/rotate-a-vector3-direction.html
Rotating a vector:
moveVector = Quaternion.Euler(0, transform.eulerAngles.y, 0) * moveVector;

Categories