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.
Related
The
rb.velocity = Vector2.up * jumpVelocity;
works but I want to add the Time.DeltaTime to code. Like this:
rb.velocity = Vector2.up * jumpVelocity*Time.deltaTime;
when I add it a character, it does not jump despite the fact I use the Rigidbody2D gravity and the dynamic character.
FULL CODE:
public float MovementSpeed = 1;
private BoxCollider2D boxCollider2D;
[SerializeField] private LayerMask layerMask;
// Start is called before the first frame update
void Start()
{
anim = GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
boxCollider2D = transform.GetComponent<BoxCollider2D>();
}
// Update is called once per frame
void Update()
{
var movement = Input.GetAxis("Horizontal");
transform.position += new Vector3(movement, 0, 0) * Time.deltaTime * MovementSpeed;
var movementUp = Input.GetAxis("Vertical");
if (IsGrounded() && movementUp > 0)
{
float jumpVelocity = 1000f;
rb.velocity = Vector2.up * jumpVelocity;
}
}
private bool IsGrounded()
{
float extraHeightText = 1f;
RaycastHit2D raycastHit2D = Physics2D.BoxCast(boxCollider2D.bounds.center, boxCollider2D.bounds.size, 0f, Vector2.down, extraHeightText , layerMask);
return raycastHit2D.collider != null;
}
I found solution. I shoudnt use * time.deltatime for velocity. because jumpvelocity making it framerate independent. Actually ı wanted to provide framerate independent. jumpvelocity already moves my character at a speed that is framerate independent, using Time.deltaTime actually breaks things. It basically becomes framerate dependent again due to my velocity essentially being speed * Time.deltaTime * Time.deltaTime.
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;
}
}
So I'm trying to make an FPS-type game and is it possible to have a GameObject locked on the Y-axis/not able to move up or down? The GameObject is a model of an AWP from Counter Strike, I am making it move around the plane with the WASD keys, and when I use the mouse to look up/down, the AWP goes diagonally to where I'm looking, and I don't want that. My game looks like this: Screenshot
Here's the code I have for the AWP if it helps:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class AWPscript : MonoBehaviour {
public float speed = 5f;
// public float sensitivityX = 15.0f;
// public float sensitivityY = 15.0f;
public Camera MainCamera;
public Camera scopeCamera;
public float lookSensitivity = 10f;
public float xRotation ;
public float yRotation ;
public float currentXRotation;
public float currentYRotation;
public float xRotationV;
public float yRotationV;
public GameObject Scopepng;
public float lookSmoothDamp = 0.1f;
public Image ScopePNG;
public AudioClip sound;
// Use this for initialization
void Start () {
speed = 7.5f;
}
// Update is called once per frame
void Update () {
if(Input.GetKey(KeyCode.W))
transform.Translate(Vector3.forward * Time.deltaTime*speed);
if (Input.GetKey(KeyCode.S))
transform.Translate(Vector3.back * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.A))
transform.Translate(Vector3.left * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.D))
transform.Translate(Vector3.right * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.LeftControl))
speed = 15f;
lookAround();
scope();
}
void scope()
{
if (Input.GetMouseButton(1))
{
MainCamera.enabled = false;
scopeCamera.enabled = true;
ScopePNG.enabled = true;
}
else
{
MainCamera.enabled = true;
scopeCamera.enabled = false;
ScopePNG.enabled = false;
}
}
void lookAround()
{
xRotation -= Input.GetAxis("Mouse Y") * lookSensitivity;
yRotation += Input.GetAxis("Mouse X") * lookSensitivity;
transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
}
}
Here's probably the simplest solution:
void Update () {
if(Input.GetKey(KeyCode.W))
transform.Translate(Vector3.forward * Time.deltaTime*speed);
if (Input.GetKey(KeyCode.S))
transform.Translate(Vector3.back * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.A))
transform.Translate(Vector3.left * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.D))
transform.Translate(Vector3.right * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.LeftControl))
speed = 15f;
LookAround();
Scope();
JoeFix();
}
public float fixedFloatingHeightMeters; // set to say 1.4 in the editor
private void JoeFix()
{
Vector3 p = transform.position;
p.y = fixedFloatingHeightMeters;
transform.position = p;
}
PS! you really MUST rename lookAround to LookAround and scope to Scope. It can affect things later
Here's kind of an advanced piece of information that may be more what you want. Please try this also!
Currently you have a vector that is the NOSE OF THE OBJECT pointing.
Say the thing is heading NORTH, ok?
So, transform.forward is pointing North BUT, IT IS POINTING "DOWN A BIT".
Although it is pointing north, if you saw it from the side that vector is pointing DOWN A BIT.
What you really want is that vector, but FLAT, NOT POINTING DOWN OR UP. Right?!
In fact here's the magic to do that:
Vector3 correctDirectionButPossiblyDownOrUp = transform.forward;
Vector3 correctDirectionButFlatNoDownOrUp;
correctDirectionButFlatNoDownOrUp
= Vector3.ProjectOnPlane(
correctDirectionButPossiblyDownOrUp,
Vector3.up );
correctDirectionButFlatNoDownOrUp.Normalize();
correctDirectionButFlatNoDownOrUp is now the "magic" vector you want.
But, don't forget Translate works in LOCAL SPACE. (the "object's" idea of the world.) You very much want to move it in world space, which is easy. Notice the last argument: https://docs.unity3d.com/ScriptReference/Transform.Translate.html
transform.Translate(
correctDirectionButFlatNoDownOrUp * Time.deltaTime*speed,
Space.World);
So that's it !
footnote Don't forget "Vector3.up" has absolutely no connection to "Vector3".
If you don't need the gravity then removing the RigidBody component will stop Unity applying gravity and it will hover.
Very new to mono develop and Unity 3d and seem to be having issues with this code. First off, the code IS working. It does what it's supposed to, however, it also does some funky stuff that it's not supposed to. You are able to look up, down, left and right as well as walk those directions, the bad part is though for some reason my character likes to nudge the direction of the mouse when standing still. What am I missing? More efficient/less buggy way of doing this?
public class PlayerControl : MonoBehaviour {
public float WALK_SPEED = 1.3f;
public float RUN_SPEED = 4.0f;
public float STRAFE_SPEED = 5.0f;
public float ROTATION_SPEED = 300.0f;
public float JUMP_FORCE = 250.0f;
void Start()
{
}
// Update is called once per frame
void Update ()
{
float movementSpeed = WALK_SPEED;
float strafeSpeed = STRAFE_SPEED;
float rotationSpeedx = ROTATION_SPEED;
float rotationSpeedy = ROTATION_SPEED;
if (Input.GetKey(KeyCode.LeftShift))
{
movementSpeed = RUN_SPEED;
}
movementSpeed = Input.GetAxis("Vertical") * movementSpeed * Time.deltaTime;
strafeSpeed = Input.GetAxis("Horizontal") * strafeSpeed * Time.deltaTime;
rotationSpeedx = Input.GetAxis("Mouse X") * rotationSpeedx * Time.deltaTime;
rotationSpeedy = Input.GetAxis("Mouse Y") * rotationSpeedy * Time.deltaTime;
Vector3 rotate = new Vector3 (-rotationSpeedy, rotationSpeedx, 0);
transform.Translate(Vector3.forward * movementSpeed);
transform.Translate(Vector3.right * strafeSpeed);
transform.Rotate(rotate);
if (Input.GetKeyDown(KeyCode.Space) &&
transform.position.y < 30)
{
rigidbody.AddForce(Vector3.up * JUMP_FORCE);
}
}
}
Try freezing rotation constraints on rigidbody component. This may stop the nudging.
i have a weird glitch, when i walk down from a corner (i dont press jump), the player will falling down with very fast speed. If i jump, then everything goes normal. (Its Quill18 FPS controller, i learn from there so thats why i dont use the built in controller instead)
using UnityEngine;
using System.Collections;
[RequireComponent (typeof(CharacterController))]
public class FirstPersonController : MonoBehaviour
{
public float movementSpeed = 5.0f;
public float mouseSensitivity = 5.0f;
public float jumpSpeed = 20.0f;
float verticalRotation = 0;
public float upDownRange = 60.0f;
float verticalVelocity = 0;
CharacterController characterController;
// Use this for initialization
void Start()
{
// Screen.lockCursor = true;
characterController = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
// Rotation
float rotLeftRight = Input.GetAxis("Mouse X") * mouseSensitivity;
transform.Rotate(0, rotLeftRight, 0);
verticalRotation -= Input.GetAxis("Mouse Y") * mouseSensitivity;
verticalRotation = Mathf.Clamp(verticalRotation, -upDownRange, upDownRange);
Camera.main.transform.localRotation = Quaternion.Euler(verticalRotation, 0, 0);
// Movement
float forwardSpeed = Input.GetAxis("Vertical") * movementSpeed;
float sideSpeed = Input.GetAxis("Horizontal") * movementSpeed;
verticalVelocity += Physics.gravity.y * Time.deltaTime;
if (characterController.isGrounded && Input.GetButton("Jump"))
{
verticalVelocity = jumpSpeed;
}
Vector3 speed = new Vector3(sideSpeed, verticalVelocity, forwardSpeed ;
speed = transform.rotation * speed;
characterController.Move(speed * Time.deltaTime);
}
}
The problem is that every frame you're running this line:
verticalVelocity += Physics.gravity.y * Time.deltaTime;
Thus, you're gaining "momentum" each second, and it wont stop ever until you jump because you're "resetting" the Y velocity to a normal value. I've ran into this problem before, and it can be fixed simply by only adding the Y velocity when you're not grounded. You can use Raycast to check if you have ground, and if you dont, increase verticalVelocity by that amount.