- Home /
Keep Player Crouching
Hi, I'm new on Unity and I'm trying to make my player crouch. I got it but when I put some objects to go under them I go stand up and my player gets stucked. The colliders overlaps. Anybody can help me? There's the code (the comments are on my native language, sorry):
This image should explain my problem better: https://imgur.com/a/dFHSLy1
//Variables de acciones
bool jump; //Comprueba si el personaje está saltando.
bool sprint; //Comprueba si el personaje está corriendo.
bool crouch; //Comprueba si el personaje está agachado.
float originalHeight; //Altura original de personaje.
float originalCharCollision;//Altura original de la colisión del personaje.
float crouchHeight = 1.5F; //La altura que queremos que tenga nuestro personaje al agacharse.
float crouchCharCollision = 1.5F; //La altura que queremos que tenga la colisi´ñon de nuestro personaje al agacharse.
// Start is called before the first frame update
void Start()
{
character = GetComponent<CharacterController>(); //Selecciona al personaje
charColision = GetComponent<CapsuleCollider>(); //Selecciona la colisión
originalHeight = character.height; //Coge la altura que le hayamos pasado en Unity al Character Controller
originalCharCollision = charColision.height; // Coge la altura que le hayapmos pasado en Unity al Capsule Collider
}
// Update is called once per frame
void Update()
{
//Variables para el movimiento
moveHorizontal = Input.GetAxis("Horizontal");// GUardamos el movimiento horizontal (Derecha 1 | Izquierda -1)
moveVertical = Input.GetAxis("Vertical"); //Guardamos el movimeinto vertical (Arriba 1 | Abajo -1)
//Metodos
Move();
Crouch(); //Crouch es capaz de detectar por si sola si esta agachado o no gracias a CheckCrouch().
if (!sprint)//Ejecuta el método Sprint() cuando el personaje no está corriendo.
{
Sprint();
}
if (!jump)//Ejecuta el método Jump() cuando el personaje no está saltando. Con esto conseguimos que no hayan saltos infinitos.
{
Jump();
}
}
void Crouch()
{
if (character.isGrounded)
{
if (Input.GetKey(KeyCode.LeftControl))
{
crouch = true;
CheckCrouch();
}
else
{
crouch = false;
CheckCrouch();
}
}
}
void CheckCrouch()
{
if (crouch)
{
character.height = crouchHeight; //Cambia la altura de nuestro personaje por la que le hemos pasado anteriormente
charColision.height = crouchCharCollision; //Cambia la altura de colisión de nuestro personaje por la que le hemos pasado anteriormente
}
else
{
//Vuelve a su estado original
character.height = originalHeight;
charColision.height = originalCharCollision;
}
}
}
Answer by Ermiq · Nov 18, 2019 at 10:38 AM
Assuming you use CapsuleCollider
on your character, you'll need to cast a virtual capsule identical to the character's capsule to check for any potential collisuons up there. Physics.CapsuleCast()
is the function you can you in this case, but since you don't need to check any additional space above the character you could just use a simpler option - Physics.CapsuleCheck()
. There are also Physics.SphereCast()
, Physics.RayCast()
, Physics CheckBox()
etc. Which one to use depends on the situation.
Imagine the character's capsule as two spheres and a cylinder between the spheres.
___
/ \ - upper sphere
\___/
| |
| __ |
/ \
\____/ - lower sphere
You will cast this capsule at the character's position to check if there are any collisions at the space where the character will stand. The capsule height should be set to the full character height as when the character is not crouching.
Also, you need to ignore the character himself while checking the collisions, otherwise, the CheckCapsule()
will return true
because it will detect the collision with the character. To ignore the character you need to set a layer for the character, in the character's inspector find Layer
menu and create the layer Player
and set the character to it.
Now in the code, a couple of bitwise operations:
// create the int variable to store the player layer
int playerLayer = -1;
// and the variable which will represent all layers except the player's layer. It will be used in 'Physics.CheckCapsule()' to detect all collisions in all layer but to ignore the player layer.
int allLayersExceptPlayer;
//in Start() get the layer mask which will include all layers except the 'Player' layer
void Start() {
//Convert Layer Name to Layer Number
playerLayer = LayerMask.NameToLayer("Player");
// or you can just use number of the layer, e.g. your player layer is 1, then 'playerLayer = 1;'
//Calculate layermask of the player
allLayersExceptPlayer = (1 << playerLayer);
//and invert to ignore it.
allLayersExceptPlayer = ~allLayersExceptPlayer;
}
void Crouch()
{
if (character.isGrounded)
{
if (Input.GetKey(KeyCode.LeftControl))
{
crouch = true;
CheckCrouch();
}
// set 'crouch=false' only when there's a space to stand straight
else if (CanStandUp())
{
crouch = false;
CheckCrouch();
}
}
}
// casts a capsule to check the space above the chatacter
private bool CanStadUp() {
if (Physics.CheckCapsule(
//param1 - the center of the lower sphere, it's the character position point but higher.
// the height is character's radius. Also, you probably will need to add some offset to prevent the collisions with the ground, e.g. the physics default collision detection offset
transform.position + Vector3.up * (characterRadius + Physics.defaultcontactoffset),
// param2 - the center of the upper sphere
// the character's full height minus his radius
transform.position + Vector3.up * (characterFullHeight - characterRadius),
// param3 - the radius of the spheres, but a bit less to prevent the sphere collision with the ground
characterRadius - Physics.defaultcontactoffset,
// param4 - layers to check, use our layer mask qhich we've got in the 'Start()'
allLayersExceptPlayer,
QuerryTriggerInteraction.Ignore)
// the result of the 'CheckCapsule' is true when some collisions were detected in the given capsule space within the given layers. Return 'false' i.e. can't stand now.
return false;
else
// if there's nothing was detected (even the character himself wasn't detected because the function has ignored his layer)
return true; // can stand up
}
Answer by lgarczyn · Oct 21, 2019 at 06:16 PM
Simply do a CapsuleCast upwards to check if the player is allowed to stop crouching.
How can I do that? I'm learning Unity and don't know so much about program$$anonymous$$g yet
@politdejan8 https://docs.unity3d.com/ScriptReference/Physics.CapsuleCast.html
The best thing to $$anonymous$$ch you is to find out yourself. Everything you will ever need to know about Unity is in the documentation (other than very niche things)
CapsuleCast is a function that basically tries to move a CapsuleCollider through the world from one place to another, and gives you the distance to the first thing it hits
I've spent hours and hours trying to get this to work as a straight up beginner. I've copied the code exactly. 2019.1.5f1 version. I was able to troubleshoot that somewhere the code is causing Crouch to be always on LiteBlue
Answer by AppDosis · Nov 21, 2019 at 10:39 PM
If you want to learn a lot about crouching and character controllers i recommend you check "Kinematic Character Controller" on the asset store, it helped me a lot!