Game Development Community

dev|Pro Game Development Curriculum

Footsteps variations

by Richard Marrevee · 10/28/2014 (10:22 am) · 8 comments

When playtesting the demo of my game The Master's Eye I got a little bit tired of the monotone sound of the footsteps when I was walking around the different missions (this was also ment by some community members when they watched videos of my game). Browsing through the code I found out it was fairly easy to add a little variation to it without the need to add different sounds for the same material (and without the need to add a lot of code changes).

When you look at the code in the playFootstepSound method in player.cpp, you'll notice that a footstep is played using the SFX->playOnce method using a SFXProfile defined in script. The disadvantage of this is that it plays the same sound for every single footstep which results in a very dull soundeffect, which is very unnatural imho. I have changed this playFootstepSound method a little bit by adding a random variation in pitch every time the footstepsound is played and now you have footsteps that sounds a little bit different. I have choosen to vary the pitch between 0.70 and 1.15 but this is personal.

I will not give you the changes I've made to Player::playFootstepSound but instead give you the whole new method. Just replace it with this new one, rebuild the engine and you're done. I've also made another change at the end of the method, so I am able to use more than just the 4 hardcoded sounds.

Here it is:
void Player::playFootstepSound( bool triggeredLeft, Material* contactMaterial, SceneObject* contactObject )
{
   MatrixF footMat = getTransform();
   SFXSource* soundSrc;
   F32 randPitch = mRandF(0.70f, 1.15f);

   if( mWaterCoverage > 0.0 )
   {
      // Treading water.

	   if (mWaterCoverage < mDataBlock->footSplashHeight)
	   {
		   soundSrc = SFX->createSource(mDataBlock->sound[PlayerData::FootShallowSplash], &footMat);
		   soundSrc->setPitch(randPitch);
		   soundSrc->play();
		   SFX->deleteWhenStopped(soundSrc);
	   }
      else
      {
         if ( mWaterCoverage < 1.0 )
		 {
			 soundSrc = SFX->createSource(mDataBlock->sound[PlayerData::FootWading], &footMat);
			 soundSrc->setPitch(randPitch);
			 soundSrc->play();
			 SFX->deleteWhenStopped(soundSrc);
		 }
         else
         {
            if ( triggeredLeft )
            {
               SFX->playOnce( mDataBlock->sound[ PlayerData::FootUnderWater ], &footMat );
			   soundSrc = SFX->createSource(mDataBlock->sound[PlayerData::FootBubbles], &footMat);
			   soundSrc->setPitch(randPitch);
			   soundSrc->play();
			   SFX->deleteWhenStopped(soundSrc);
            }
         }
      }
   }
   else if( contactMaterial && contactMaterial->mFootstepSoundCustom )
   {
      // Footstep sound defined on material.

	   soundSrc = SFX->createSource(contactMaterial->mFootstepSoundCustom, &footMat);
	   soundSrc->setPitch(randPitch);
	   soundSrc->play();
	   SFX->deleteWhenStopped(soundSrc);
   }
   else
   {
      // Play default sound.

      S32 sound = -1;
      if( contactMaterial && contactMaterial->mFootstepSoundId != -1 )
         sound = contactMaterial->mFootstepSoundId;
      else if( contactObject && contactObject->getTypeMask() & VehicleObjectType )
         sound = 2;

	  if (sound > -1)
	  {
		  soundSrc = SFX->createSource(mDataBlock->sound[sound], &footMat);
		  soundSrc->setPitch(mRandF(0.5f, 2.0f));
		  soundSrc->play();
		  SFX->deleteWhenStopped(soundSrc);
	  }
	  else
	  {
		  soundSrc = SFX->createSource(mDataBlock->sound[PlayerData::FootHard], &footMat);
		  soundSrc->setPitch(randPitch);
		  soundSrc->play();
		  SFX->deleteWhenStopped(soundSrc);
	  }

/*      switch ( sound )
      {
      case 0: // Soft
         SFX->playOnce( mDataBlock->sound[PlayerData::FootSoft], &footMat );
         break;
      case 1: // Hard
         SFX->playOnce( mDataBlock->sound[PlayerData::FootHard], &footMat );
         break;
      case 2: // Metal
         SFX->playOnce( mDataBlock->sound[PlayerData::FootMetal], &footMat );
         break;
      case 3: // Snow
         SFX->playOnce( mDataBlock->sound[PlayerData::FootSnow], &footMat );
         break;
      default: //Hard
         SFX->playOnce( mDataBlock->sound[PlayerData::FootHard], &footMat );
         break;
     
      }*/
   }
}

I hope you like it and find it useful.

Thanks.

Richard.

About the author

Started programming in 1984 on an Oric, when time progressed switched to MSX, Amiga and finally the Windows PC with T3D. Now developing an epic fantasy game: The Master's Eye. Creator of the DoorClass pack and VolumetricFog pack @ richardsgamestudio.com


#1
10/28/2014 (1:10 pm)
Nice work, Richard! :)
#2
10/28/2014 (7:28 pm)
This is beautiful. I was worried about this myself because I now have the levels finally laid out for my game along with the story line. I will need to soon concentrate on these types of details. Thank you!
#3
10/28/2014 (9:29 pm)
Oh great, it was on our long list of things to do; now you helped us on our way with this. Thanks @Richard!
#4
10/29/2014 (3:22 am)
this is a great resource, thanks.
#5
10/29/2014 (12:16 pm)
Thinking about it again, you can do the same trick with the volume of the footsteps for more variation by using:
F32 randVolume = mRandF(0.6f, 1.0f);
after the line
F32 randPitch = mRandF(0.70f, 1.15f);

and add
soundSrc->setVolume(randVolume);
after each
soundSrc->setPitch(randPitch);
line.
#6
11/01/2014 (4:52 am)
Hey awesome work Richard, thanks for sharing mate :)

Here is a slight alternative if anyone is interested, it keeps the default hard coded sounds (if you actually prefer that), just add the volume stuff from above if you want it. I have also dumped the FootBubbles sound. Don't see the point in that.

void Player::playFootstepSound( bool triggeredLeft, Material* contactMaterial, SceneObject* contactObject )
{
   SFXTrack *track = NULL;  
   if( mWaterCoverage > 0.0 )
   {
      // Treading water.

      if ( mWaterCoverage < mDataBlock->footSplashHeight )
         track = mDataBlock->sound[ PlayerData::FootShallowSplash ];
      else
      {
         if ( mWaterCoverage < 1.0 )
            track =  mDataBlock->sound[ PlayerData::FootWading ];
         else
         {
            if ( triggeredLeft )
            {
               track = mDataBlock->sound[ PlayerData::FootUnderWater ];
               //Pointless having two sounds, just combine them when creating ;-)
               //SFX->playOnce( mDataBlock->sound[ PlayerData::FootBubbles ], &footMat );
            }
         }
      }
   }
   else if( contactMaterial && contactMaterial->mFootstepSoundCustom )
   {
      // Footstep sound defined on material.

      track = contactMaterial->mFootstepSoundCustom;
   }
   else
   {
      // Play default sound.

      // +++ Play something, not nothing!!!

	  S32 sound = 0;
	  
	  /*
	  S32 sound = -1;
	  */

	  // -->
      if( contactMaterial && contactMaterial->mFootstepSoundId != -1 )
         sound = contactMaterial->mFootstepSoundId;
      else if( contactObject && contactObject->getTypeMask() & VehicleObjectType )
         sound = 2;

      switch ( sound )
      {
      case 0: // Soft
         track = mDataBlock->sound[PlayerData::FootSoft];
         break;
      case 1: // Hard
         track = mDataBlock->sound[PlayerData::FootHard];
         break;
      case 2: // Metal
         track = mDataBlock->sound[PlayerData::FootMetal];
         break;
      case 3: // Snow
         track = mDataBlock->sound[PlayerData::FootSnow];
         break;
      }
   }

   //Play track if we have one
   if(track)
   {
      MatrixF footMat = getTransform();
      F32 randPitch = mRandF(0.70f, 1.15f);
      SFXSource* soundSrc = SFX->createSource(track, &footMat);  
      soundSrc->setPitch(randPitch);  
      soundSrc->play();  
      SFX->deleteWhenStopped(soundSrc);  
   }
}
#7
11/02/2014 (3:12 am)
Thanks guys, glad you liked it.