Unity3d: CharacterController doesn't stay grounded; the sound effect of steps cannot be played continuously
I need to check when my character is grounded so that I don't keep playing the walking sound when he rolls off something (or jumps in the air).
This is the code that takes care of jumping, falling, and gravity. cc
in this code block, the CharacterController component. If the symbol is already grounded and the jump key has not been pressed, the vertical speed will remain at zero; if it is not grounded, then gravity is applied in the direction y
.
if (cc.isGrounded) {
grounded = true;
if (Input.GetButton ("Jump") == true) {
ySpeed = jumpSpeed;
jumpSound.audio.Play();
} else {
ySpeed = 0;
}
} else {
grounded = false;
ySpeed += Physics.gravity.y * Time.deltaTime;
}
Debug.Log (cc.isGrounded == true ? "yes" : "no");
The problem is that the value isGrounded
fluctuates constantly, and the line Debug.Log
fluctuates between yes
and no
, so when I use the condition isGrounded
to play the sound of footsteps, the sound accidentally stops and starts over again, even though I'm constantly just walking right along a simple flat plan.
Is there a way to get around this?
I don't care about the fact that it is isGrounded
hesitant and that it is wrong, because in the gameplay it is not noticeable. My only concern is how to constantly sound in the footsteps while the character walks, rather than jumping and falling. As far as my problems go, this could be solved by actually fixing the fluctuation or some other workaround; I would be pleased.
These are my conditions for playing the sound of steps:
if((Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0) && grounded == true) {
if(this.audio.isPlaying != true) {
this.audio.Play ();
}
} else if (this.audio.isPlaying) {
this.audio.Stop ();
}
source to share
Your approach can be a little tricky. I would recommend storing references to all of your characters' sounds (usually in Start or as public properties) and then simply replacing them during the appropriate input event .
those. This should remove the need to track if a char is there. grounded.
Pseudo-code:
if ( walking ): audio.clip = audioWalk
if ( jump ): audio.clip = audioJump
EDIT
When you are still on level ground, every few calls to Update (or FixedUpdate) show that isGrounded is set to false. However, while isGrounded is not reliable for detecting true state, I found it reliable for checking for false state. In other words, when the character is in the "air", isGround reliably remains false. With this in mind, you can calculate your air time as follows:
// RequiredFallingTime is a public class field which I set in the inspector to be a little
// bit higher than my jump time (0.7 seconds in my case)
void Update () {
fallingCount = ( cc.isGrounded ) ? 0 : fallingCount + 1;
Debug.Log("Update: fallingCount = " + fallingCount);
fallTime = fallingCount * Time.deltaTime;
Debug.Log("Update: falling Duration = " + fallTime );
falling = ( fallTime >= RequiredFallingTime ) ? true : false;
// Still Falling: None of my Controls should produce sound while falling so return:
if( fallTime / 2 >= RequiredFallingTime )
return;
// If first time falling, play our fall sound:
if( falling ){
audioSource.PlayOneShot(audioClipsOneShot[(int)SoundOneShot.fall]);
}
// If we made it this far, we're not falling--although we could be jumping.
// Do Input checking for approp. sounds
}
source to share
I meet similar circumstances when developing character movement using the PhysX engine. To be more precise, my character could not move down. Instead, he always tries to jump over the steps and go down. And its theGrounded also floated on a seemingly flat surface.
My motion code was also based on speed integration dX = V ยท dt.
I added a simple way at the end:
- Move dX = V dt + U, where U is a constant vector (0, -u, 0).
- If after step 1 the character was not surrounded, it moved back (up) by (0, u, 0)
By playing with this constant u value, I found that it provides reasonable behavior at less or equal stair tread height.
To explain this workaround, it must be clearly stated that the character controller is not a human body. Even using sophisticated methods such as speed integration, you are still working with a rigid body, while the human body is a complex mechanism, now it consists of legs, legs, etc.
In fact, when my character started to move downward, the gravitational accumulation dV = G ยท dt lagged a little, but it was enough to put the character in a free fall down the stairs.
And that's the end of my story :)
PS. I found the relevant code:
// move character
NxU32 activeGroups = getCharacter()->getScene()->getActiveGroups( cg::protagonist );
_character->_nxController->move(
( _character->_vy + _character->_vxz ) * timeStep,
activeGroups, 0.001f,
_character->_collisionFlags, 0.01f
);
// press character to floor
if( pressDown )
{
// press character down on step offset distance
_character->_nxController->move(
NxVec3( 0, -_character->_stepOffset, 0 ),
activeGroups, 0.001f,
_character->_collisionFlags, 0.01f
);
// if press-down actions does not reveal floor under feets
if( !( _character->_collisionFlags & NXCC_COLLISION_DOWN ) )
{
// return character to its presios position
_character->_nxController->move(
NxVec3( 0, _character->_stepOffset, 0 ),
activeGroups, 0.001f,
_character->_collisionFlags, 0.01f
);
}
}
source to share