- Home /
Keeping speed while crouching in midair and remove clipping while returning to standing
I've been working on making a good crouching script now for a while but no matter how I try I can't put the last pieces together.
One thing I want is that if you jump while running (standing) and then start to crouch in midair you should not slow down except for when landing on the ground. I've been trying some IsGrounded-functions but when I do the script just ignore the slowdown altogether and makes the player move around with normal standingspeed while crouching.
The other (and most important - I even dare to say gamebreaking) missing component is the fact that the player should not be able to stand up if standing up will result in the player clipping through objects. At the moment I can stand up straight from crouching anywhere which isn't how it normally works in games. I've tried to create a collider with the same size as the First Person Controller collider and used some collider scripts to make the game realize that while anything is touching this collider the player should not be able to stand.
The code so far looks like this (it's a modified version of a crouching script I found here a while ago):
var forWalkSpeed: float = 7; // regular speed forward var sideWalkSpeed: float = 7; // regular speed sidestep var backWalkSpeed: float = 7; // regular speed backward var forCrchSpeed: float = 3; // crouching speed forward var sideCrchSpeed: float = 3; // crouching speed sidestep var backCrchSpeed: float = 3; // crouching speed backward
internal var forSpeed: float; // the current speed state internal var sideSpeed: float; internal var backSpeed: float;
internal var crouchHeight : float; // variables for character height while crouching internal var crouchingHeight : float;
internal var standingHeight: float; // height of character while standing internal var crouching = false; // boolean is crouching? //internal var running = false; // boolean is running?
internal var characterMotor: CharacterMotor; //direct variable to the characterMotor internal var mainCamera: GameObject; // direct variable to the mainCamera
//var distToGround: float;
function Start() { //initialize characterMotor = GetComponent(CharacterMotor); mainCamera = gameObject.FindWithTag ("MainCamera"); standingHeight = mainCamera.transform.localPosition.y; crouchingHeight = (standingHeight - 0.9); crouchHeight = (standingHeight - crouchingHeight); distToGround = collider.bounds.extents.y; // get the distance to ground }
function Update() { //simple machine for setting the current speed of the character if(crouching) { forSpeed = forCrchSpeed; // slow down when crouching sideSpeed = sideCrchSpeed; backSpeed = backCrchSpeed; } //else if( running ) //{ // speed = runSpeed; //} else { forSpeed = forWalkSpeed; backSpeed = backWalkSpeed; sideSpeed = sideWalkSpeed; } /* //If the sprint button is clicked, and not crouching .. SPRINT!
if (Input.GetKey("left ctrl") || Input.GetKey("right ctrl")){
if(!crouching){
running = true;
//cameraZoom.sprint = true; //sets sprint true so the camera knows to pan out
}
} else {
//cameraZoom.sprint = false;
running = false;
} */
// if crouch button has been pressed, put FPS into crouch
if (Input.GetButtonDown ("Crouch")){
if(crouching){
stopCrouching();
return;
}
if(!crouching)
crouch();
}
// crouch with smoothing
if(crouching)
{
if(mainCamera.transform.localPosition.y > crouchingHeight){
if(mainCamera.transform.localPosition.y - (crouchHeight*Time.deltaTime*4) < crouchingHeight){
mainCamera.transform.localPosition.y = crouchingHeight;
}
else
{
mainCamera.transform.localPosition.y -= crouchHeight*Time.deltaTime*4;
}
}
}
else
{
if(mainCamera.transform.localPosition.y < standingHeight){
if(mainCamera.transform.localPosition.y + (crouchHeight*Time.deltaTime*4) > standingHeight){
mainCamera.transform.localPosition.y = standingHeight;
}
else
{
mainCamera.transform.localPosition.y += crouchHeight*Time.deltaTime*4;
}
}
}
//set the max speed in the char motor;
characterMotor.movement.maxForwardSpeed = forSpeed; // set max forward speed
characterMotor.movement.maxSidewaysSpeed = sideSpeed; // max sideway speed
characterMotor.movement.maxBackwardsSpeed = backSpeed; //max backwards speed
}
// sets the size of the collider to crouch size
function crouch() { this.GetComponent(CharacterController).height -= crouchHeight; this.GetComponent(CharacterController).center -= Vector3(0,crouchHeight/2, 0); crouching = true; }
// resets the size of the collider to standing size
function stopCrouching() { crouching = false; this.GetComponent(CharacterController).height += crouchHeight; this.GetComponent(CharacterController).center += Vector3(0,crouchHeight/2, 0); }
/ function IsGrounded(): boolean { return Physics.Raycast(transform.position, -Vector3.up, distToGround + 0.1); }/
Answer by aldonaletto · Jan 13, 2012 at 11:30 PM
I would do the following changes:
1- cache the CharacterController at Start to save time:
... internal var character: CharacterController;
function Start(){ character = GetComponent(CharacterController); ... You can use it to know when the character is grounded with character.isGrounded
2- Use characterMotor.jumping.jumping to know when the character is jumping, and block the crouch speed:
... if(crouching && !characterMotor.jumping.jumping) { forSpeed = forCrchSpeed; // slow down when crouching sideSpeed = sideCrchSpeed; backSpeed = backCrchSpeed; } ...You may also try to use character.isGrounded instead:
if (crouching && character.isGrounded){
3- Before standing up, do a raycast upwards to check if there's enough room (set the float distUp variable to a suitable value):
... if (Input.GetButtonDown ("Crouch")){ if(crouching && !Physics.RaycastHit(transform.position, Vector3.up, distUp)){ stopCrouching(); return; } if(!crouching) ...I hope this can solve your problems - or at least help you to find the solutions.
Answer by Hordaland · Jan 14, 2012 at 02:09 AM
Thanks alot! The speed is now the same even while I crouch midair. I also disabled the ability to jump while crouched since it's not appropriate behaviour to do so in the kind of slowpaced game I'm making.
The raycast worked after a light tweak I had to make since Unity gave me an error. Now it looks like this:
function Update(){
var hit : RaycastHit; ...
// if crouch button has been pressed, put FPS into crouch
if (Input.GetButtonDown ("Crouch")){
if(crouching && !Physics.Raycast(transform.position, Vector3.up, hit, distUp)){
stopCrouching();
return;
}
if(!crouching)
crouch();
}
The only issue I have is that if I don't stand directly below the object the rays won't hit. Is there any possibility to shoot out more rays and in different directions so that my whole character can enjoy this feeling of not being able to stand straight?
You could use Physics.SphereCast ins$$anonymous$$d:
if(crouching && !Physics.SphereCast(transform.position, character.radius, Vector3.up, hit, distUp)){SphereCast is a kind of "thick" Raycast, with the specified radius.