- Home /
Limiting Speed on Two Axis
Hello,
I am trying to make a character controller that moves based on adding force to the Rigidbody. I have all the movement working except for one part. I want to limit the speed the object can move but I only want to limit the X and the Z axis. I want to leave the Y axis either unlimited or a higher limit than the others. The character will jump and so the Y axis can't be added in to the speed limit.
Here is the code. Everything here works, I just need to add something to get the speed limit. The movement is in the Fixed Update, so you can ignore everything else.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour {
public float runAcceleration;
public float maxRunSpeed;
public float runStopSpeed;
public float jumpHeight;
public float horizontalSensitivity; //Sensitivity for the mouse movement.
public float verticalSensitivity; //Sensitivity for the mouse movement.
public bool invertLook; //Make true if the player wants to invert their camera X movement.
float rotationX; //Used for clamping the X rotation of the camera.
Rigidbody rb;
Camera cam; //Just gets the camera for mouse movement.
GameObject groundCheck;
CapsuleCollider playerCapsule;
Vector3 forwardVelocity;
Vector3 sidewaysVelocity;
// Use this for initialization
void Start ()
{
rb = GetComponent<Rigidbody>();
groundCheck = GameObject.FindGameObjectWithTag("groundCheck");
cam = GetComponentInChildren<Camera>(); //Gets the camera.
playerCapsule = GetComponent<CapsuleCollider>();
}
// Update is called once per frame
void Update()
{
//***Jump Command***
if (Input.GetButtonDown("Jump") && groundCheck.GetComponent<GroundChecker>().playerGrounded)
{
Jump();
}
//***End of Jump Command***
//***Character/Camera Rotation***
transform.Rotate(new Vector3(0, Input.GetAxis("Mouse X"), 0) * Time.deltaTime * (horizontalSensitivity * 10)); //Rotate the player based on sensitivity with mouse.
transform.Rotate(new Vector3(0, Input.GetAxis("Horizontal2"), 0) * Time.deltaTime * (horizontalSensitivity * 10)); //Rotate the player based on sensitivity with controller.
rotationX += Input.GetAxis("Mouse Y") * Time.deltaTime * (verticalSensitivity * 10); //Rotate the camera up and down based on sensitivity with mouse.
rotationX += Input.GetAxis("Vertical2") * Time.deltaTime * (verticalSensitivity * 10); //Rotate the camera up and down based on sensitivity with controller.
rotationX = Mathf.Clamp(rotationX, -80, 80); //Clamp the camera so it can't rotate too far.
if (invertLook)
{
cam.transform.localEulerAngles = new Vector3(rotationX, transform.rotation.y, transform.rotation.z); //Up and down movement for inverted players.
}
else
{
cam.transform.localEulerAngles = new Vector3(-rotationX, transform.rotation.y, transform.rotation.z); //Up and down movement for non-inverted players.
}
//***End of Character/Camera Rotation***
}
void FixedUpdate ()
{
//***Player Movement***
forwardVelocity = transform.forward * Input.GetAxis("Vertical") * runAcceleration; //Gets the forward velocity based on direction pressed and acceleration.
forwardVelocity.y = rb.velocity.y / 2;
sidewaysVelocity = transform.right * Input.GetAxis("Horizontal") * runAcceleration; //Gets the sideways velocity based on direction pressed and acceleration.
sidewaysVelocity.y = rb.velocity.y / 2;
rb.AddForce(forwardVelocity + sidewaysVelocity);
if (Input.GetAxis("Horizontal") > -0.1f && Input.GetAxis("Horizontal") < 0.1f && Input.GetAxis("Vertical") > -0.1f && Input.GetAxis("Vertical") < 0.1f)
{
rb.velocity = new Vector3 (Mathf.Lerp(rb.velocity.x, 0, runStopSpeed), rb.velocity.y, Mathf.Lerp(rb.velocity.z, 0, runStopSpeed));
}
//***End of Player Movement***
}
void Jump()
{
rb.AddForce(0, jumpHeight, 0, ForceMode.Impulse);
}
}
Answer by HenryStrattonFW · Jan 29, 2017 at 02:30 PM
If I understand your question correctly, then perhaps something like this would do the job.
// Store the current y velocity so we can restore it later.
float tempY = rb.velocity.y;
// Then remove it completely.
rb.velocity.y = 0;
// Now with just the x and z axis in the velocity apply the speed limitation.
if(rb.velocity.magnitude > speedLimit)
{
rb.velocity = rb.velocity.normalized * speedLimit;
}
// Then restore the y component of the velocity, which will be unrestricted.
rb.velocity.y = tempY;
The idea is to remove the y from the velocity before applying the speed restriction, and then restore the y component afterwards so that it is unaffected by the restriction.
Thanks! This worked, but I did have to tweak it a little, so I'll add the code below. You can't directly modify rb.velocity.y, it has to be set up as a vector 3 and just leave the x and z as they are. Also, you don't need to set rb.velocity.y to 0 after you set the tempY. Here is the code that worked for me.
float tempY = rb.velocity.y;
if (rb.velocity.magnitude > maxRunSpeed)
{
rb.velocity = rb.velocity.normalized * maxRunSpeed;
}
rb.velocity = new Vector3(rb.velocity.x, tempY, rb.velocity.z);
Quite right on both counts, sorry didn't have chance to actually run the code through unity just notepad. Good spot.
Thank you so much XD been looking for something like this for days, was about to give up and just leave my character controller as it is (it would slow down when facing a non-cardinal direction, and also when you fell you wouldn't be able to move) but this solved it (with some tweaks)! Thanks again guys.