I’ve started (semi-)serious development with Unity yesterday and started out with a First-Person Controller Script. For the movement I’m using a Character Controller, which works just fine.
Once I started coding the gravity interaction however, things got a bit iffy. I started coding the falling part of gravity, which works fine and then started coding the jumping part.
I used controller.isGrounded to find out if the CharacterController had contact to the ground, therefore enabling it to jump, but for some reason it seems to “oscillate” so to speak. What I mean by that is that sometimes controller.isGrounded returns false, even though it is sitting on the ground. Interestingly enough, Physics.RayCast seems to produce a much more reliable result.
Can someone explain why that is? Is it actually faulty or is it me expecting the wrong things out of controller.isGrounded? I’d like to know so I can improve and maybe correct expectations towards the usage of controller.isGrounded.
If you want a more thorough explanation of the code, feel free to message me and/or post in the thread!
using UnityEngine;
using System.Collections;
public class ControlScript : MonoBehaviour {
public float maxSpeed = 0.15f;
public float acceleration = 1;
public float momentum = 0;
public float horizontalMomentum = 0;
public float jumpHeight = 0.15f;
public float verticalMomentum = 0;
public int rotationSpeed = 36;
public float hitscanLength = 1.6f; //Length of collision hitscan Ray
public bool isGrounded; //To display isGrounded status in Inspector
CharacterController controller;
public Vector3 movementVector;
// Use this for initialization
void Start () {
controller = GetComponent<CharacterController>();
}
// Update is called once per frame
void FixedUpdate ()
{
isGrounded = controller.isGrounded; //Use this to check controller.isGrounded in Inspector
//isGrounded = Physics.Raycast(this.transform.position, Vector3.down, hitscanLength, 1); //Use this to check using RayCast
/*-- Depth Movement --*/
if(Input.GetKey(KeyCode.W))
{
momentum += ((1 * acceleration) * Time.deltaTime);
momentum = Mathf.Clamp(momentum, 0, maxSpeed);
}
else if(Input.GetKey(KeyCode.S))
{
momentum -= ((1 * acceleration) * Time.deltaTime);
momentum = Mathf.Clamp(momentum, -maxSpeed, 0);
}
else
{
if(momentum < 0)
{
momentum += ((1 * acceleration) * Time.deltaTime);
//momentum = Mathf.Clamp(momentum, 0, 0);
if(momentum > -0.002f)
{
momentum = 0;
}
}
if(momentum > 0)
{
momentum -= ((1 * acceleration) * Time.deltaTime);
//momentum = Mathf.Clamp(momentum, 0, 0);
if(momentum < 0.002f)
{
momentum = 0;
}
}
}
/*-- Horizontal Movement -- */
if(Input.GetKey(KeyCode.A))
{
horizontalMomentum -= ((1 * acceleration) * Time.deltaTime);
horizontalMomentum = Mathf.Clamp(horizontalMomentum, -maxSpeed, 0);
}
else if(Input.GetKey(KeyCode.D))
{
horizontalMomentum += ((1 * acceleration) * Time.deltaTime);
horizontalMomentum = Mathf.Clamp(horizontalMomentum, 0, maxSpeed);
}
else
{
if(horizontalMomentum < 0)
{
horizontalMomentum += ((1 * acceleration) * Time.deltaTime);
if(horizontalMomentum > -0.002f)
{
horizontalMomentum = 0;
}
}
if(horizontalMomentum > 0)
{
horizontalMomentum -= ((1 * acceleration) * Time.deltaTime);
if(horizontalMomentum < 0.002f)
{
horizontalMomentum = 0;
}
}
}
/*-- Gravity and Jumping --*/
if(isGrounded) //If the character controller is on the ground...
{
verticalMomentum = 0; //... kill the vertical Momentum.
if(Input.GetKeyDown(KeyCode.Space)) //If the user presses space...
{
verticalMomentum = .45f; //Apply verticalMomentum...
}
}
else //If in freefall...
{
verticalMomentum += ((Physics.gravity.y * Time.deltaTime) / 10); //... Apply gravity acceleration...
verticalMomentum = Mathf.Clamp(verticalMomentum, -.85f, 255); //... but clamp it at a certain speed.
}
//Debug.DrawLine(this.transform.position, new Vector3(this.transform.position.x, this.transform.position.y - hitscanLength, this.transform.position.z), Color.red, 0, false);
movementVector = new Vector3(horizontalMomentum, verticalMomentum, momentum);
controller.Move(movementVector);
}
}