3
votes

I need to check when my character is grounded so that i wouldn't continue to play the walk sound when he falls off something (or jumps in the air).

This is the code that takes care of the jumping, falling and gravity. cc in this code block is the CharacterController component. If the character already is grounded and the jump key was not pressed, the vertical speed will remain zero; if he is not grounded, then gravity is applied in the y direction.

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 isGrounded value constantly fluctuates, and the Debug.Log line fluctuates between yes and no, so when I use the isGrounded condition for playing the footsteps sound, the sound randomly stops and starts again, even though I am constantly just walking straight on a simple smooth plane.

Is there a way around this?

I am not concerned about the fact that isGrounded is fluctuating and that it's incorrect, because in gameplay that is not noticable. I am only worried about how to constantly play the footsteps sound while the character is walking, and not jumping, and not falling. As far as my concerns go, this may be solved by actually fixing the fluctuation or another workaround; I would be happy with either.

These are my conditions for playing the footsteps sound:

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 ();
}
3

3 Answers

0
votes

I have meet similar circumstances developing character movement with PhysX engine. To be more precisely, my character was unabled to move downstairs. Instead of it he always trying to jump over steps and go freefall. And his isGrounded was fluctuating on seemingly flat surface as well.

My movement code was also based on velocity integration dX = V · dt.

In the end, I have added simple workaround:

  1. Move dX = V · dt + U where U is a constant vector (0,-u,0).
  2. If character was not isGrounded after step 1 it was moving back (up) by (0,u,0)

Playing with that constant value of u I have found it provides reasonable behaviour when lesser or equal to the height of stairs step.

To explain this workaround it is necessary to make clear that character controller is not a human body. Even using sophisticated methods like velocity integration you still work with solid body while human body is complicated mechanism, you now, it consists of legs, feets et c.

In fact, when my character began to move downstairs, gravity accumulation dV = G · dt was lagged a little, but it was enough to put character in freefall over stairs.

And that's the end of my story :)

PS. I have found corresponding 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 
                );
            }
        }
0
votes

Your approach may be a bit overcomplicated. I'd recommend storing references to all your characters sounds (typically in Start or as public properties), then simply swap them out during the appropriate Input event.

I.e. This should eliminate the need to keep track of whether char. is grounded.

Pseudo-Code:

if ( walking ): audio.clip = audioWalk

if ( jump ): audio.clip = audioJump

EDIT

When completely still on flat terrain every few calls to Update (or FixedUpdate) reveals isGrounded getting set to false. However, while isGrounded is not reliable in detecting true state, I found it reliable for checking false state. In other words, when character is in the "air" isGround reliably remains false. With that in mind you can calculate your air time like this:

// 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




}
0
votes

If y movement is 0, then the character will not be pushed into the floor, and isGrounded will return false. I recommend setting y velocity to any negative number when grounded. That way the player will collide with the floor and isGrounded will return true. What I do is just not change y velocity at all when grounded, all I do is stop applying gravity.

Sorry if I'm a bit late, this is for anybody new who happens to read this article, as it appears at the top of the Google search for help with this situation.