Footstep Sounds

Started by subspark, Sat 03/05/2008 07:11:07

Previous topic - Next topic

subspark

I am trying to set the character's footstep sounds to a different set based on what room the player is in.
I can't get the code to work and keep getting stuck with nested functions. How do I write this?
This is what I have so far.

Code: ags

function room_Load() {

//===== FOOTSTEP SOUNDS =====//

// WALK DOWN
ViewFrame *walkdown = Game.GetViewFrame(EGOWALK, 1, 1); 
walkdown.Sound = 6; // idle footstep
walkdown = Game.GetViewFrame(EGOWALK, 1, 4);
walkdown.Sound = 5; 
walkdown = Game.GetViewFrame(EGOWALK, 1, 10);
walkdown.Sound = 5;

// WALK LEFT
ViewFrame *walkleft = Game.GetViewFrame(EGOWALK, 2, 1);
walkleft.Sound = 6; // idle footstep
walkleft = Game.GetViewFrame(EGOWALK, 2, 6);
walkleft.Sound = 5;
walkleft = Game.GetViewFrame(EGOWALK, 2, 12);
walkleft.Sound = 5;

// WALK RIGHT
ViewFrame *walkright = Game.GetViewFrame(EGOWALK, 3, 1);
walkright.Sound = 6; // idle footstep
walkright = Game.GetViewFrame(EGOWALK, 3, 6);
walkright.Sound = 5;
walkright = Game.GetViewFrame(EGOWALK, 3, 12);
walkright.Sound = 5;

// WALK UP
ViewFrame *walkup = Game.GetViewFrame(EGOWALK, 4, 1);
walkup.Sound = 6; // idle footstep
walkup = Game.GetViewFrame(EGOWALK, 4, 4);
walkup.Sound = 5;
walkup = Game.GetViewFrame(EGOWALK, 4, 10);
walkup.Sound = 5;

// WALK DOWN-RIGHT
ViewFrame *walkdownright = Game.GetViewFrame(EGOWALK, 5, 1);
walkdownright.Sound = 6; // idle footstep
walkdownright = Game.GetViewFrame(EGOWALK, 5, 5);
walkdownright.Sound = 5;
walkdownright = Game.GetViewFrame(EGOWALK, 5, 11);
walkdownright.Sound = 5;

// WALK UP-RIGHT
ViewFrame *walkupright = Game.GetViewFrame(EGOWALK, 6, 1);
walkupright.Sound = 6; // idle footstep
walkupright = Game.GetViewFrame(EGOWALK, 6, 5);
walkupright.Sound = 5;
walkupright = Game.GetViewFrame(EGOWALK, 6, 11);
walkupright.Sound = 5;

// WALK DOWN-LEFT
ViewFrame *walkdownleft = Game.GetViewFrame(EGOWALK, 7, 1);
walkdownleft.Sound = 6; // idle footstep
walkdownleft = Game.GetViewFrame(EGOWALK, 7, 5);
walkdownleft.Sound = 5;
walkdownleft = Game.GetViewFrame(EGOWALK, 7, 11);
walkdownleft.Sound = 5;

// WALK UP-LEFT
ViewFrame *walkupleft = Game.GetViewFrame(EGOWALK, 8, 1);
walkupleft.Sound = 6; // idle footstep
walkupleft = Game.GetViewFrame(EGOWALK, 8, 5);
walkupleft.Sound = 5;
walkupleft = Game.GetViewFrame(EGOWALK, 8, 11);
walkupleft.Sound = 5;
}


Any help would be hot.

BTW is the AGS server hosted in Iran or something? The server is as slow as a crippled rock.  ???

Cheers,
Paul.

Edit:
ARGHH! This was supposed to go in the beginner's thread. Sorry :-[.

Khris

You can shorten this:

Code: ags
function room_Load() {

  ViewFrame*vf;
  int i;
  while (i<8) {
    vf = Game.GetViewFrame(EGOWALK, i, 1);
    vf.Sound = 6; // idle footstep
    vf = Game.GetViewFrame(EGOWALK, i, 5);
    vf.Sound = 5;
    vf = Game.GetViewFrame(EGOWALK, i, 11);
    vf.Sound = 5;

    i++;
  }
}


Note that the loops are numbered 0-7, not 1-8.
A nested functions error means there's a closing bracket missing somewhere before the mentioned line (AGS thinks you're trying to declare a function inside another function).

subspark

Thanks for this. I figured it out myself, actually. I did in fact make a clumsy script error. Thanks for your shorter example. It's a good learning example of how I can shorten my code in future.

Thanks again mate. Ta.
Paul.

ryanlandry

if you don't have like 10+ different sets, couldn't you just make different versions of your walking view with the sounds pre-assigned in the editor, and then just switch the character's normal view to the correct one at room load?
A fly in the hand is worth?...

subspark

#4
I could but then I'd have roughly 12 times the amount of views in my game. You have to understand that when the character walks over a particular region, such as a metal plate, the footstep sound should reflect that and give important feedback to the player telling them that it is something metal they are standing on. Now I have over 12 different sets of footstep sounds set up that each tell the player that they are standing on different materials including wood and sludge. It would be impractical to have additional views for this when it can be done with a reasonable amount of code. Having said that,
how DO I get a region to change the sound of Ego's footsteps as soon as he walks onto a region and for it to continue doing so until the player has left the region?

I have tried almost everything and it seems like something is stopping the code from doing anything when it is in the room's repeatedly execute function.

I successfully got it to display a "metal on"/"metal off" message when the player was on the region but it's just the sounds that don't swap.

Code: ags
function room_RepExec()
{
  ViewFrame*vf;
  if (Region.GetAtRoomXY(player.x, player.y) == region[2]) {
    while (i<8) {
      vf = Game.GetViewFrame(EGOWALK, i, 0);
      vf.Sound = sFS2Be; // idle footstep
      vf = Game.GetViewFrame(EGOWALK, i, 4);
      vf.Sound = sFS2Ae;
      vf = Game.GetViewFrame(EGOWALK, i, 10);
      vf.Sound = sFS2Ae;
      i++;
    }
  }
  else {    
    while (i<8) {
      vf = Game.GetViewFrame(EGOWALK, i, 0);
      vf.Sound = sFS1Be; // idle footstep
      vf = Game.GetViewFrame(EGOWALK, i, 4);
      vf.Sound = sFS1Ae;
      vf = Game.GetViewFrame(EGOWALK, i, 10);
      vf.Sound = sFS1Ae;
      i++;
    }
  }
}


Any ideas on how to fix this?

Cheers,
Paul.

SSH

Does the change get delayed until the character stops walking or something? Or just has no effect at all?

Also, are you sure that the Room's repeatedly execute interaction points to that function? Try putting a breakpoint at the beginning of the function and single-step through it?
12

subspark

YES!!! I DID IT!! I don't fully understand the whole proccess but I fumbled my way through it nonetheless. Turns out, I wasn't resetting 'i' to zero. This is how I did it for those of you interested and maybe somebody more experienced can explain what is ACTUALLY going on here:

Code: ags
int i; // all walking views
ViewFrame *vf;

function region2_WalksOnto()
{
  hMetalPlate.Enabled = true; // hotspot enabled
  i = 0;
}
function region2_WalksOff()
{
  i = 0;
}

function room_RepExec()
{
  //===== FOOTSTEP SOUNDS =====//
  while (i<8) {
    if (Region.GetAtRoomXY(player.x, player.y) == region[2]) {
      vf = Game.GetViewFrame(EGOWALK, i, 0);
      vf.Sound = sFS2Be; // idle footstep
      vf = Game.GetViewFrame(EGOWALK, i, 4);
      vf.Sound = sFS2Ae;
      vf = Game.GetViewFrame(EGOWALK, i, 10);
      vf.Sound = sFS2Ae;
    }
    else {
      vf = Game.GetViewFrame(EGOWALK, i, 0);
      vf.Sound = sFS1Be; // idle footstep
      vf = Game.GetViewFrame(EGOWALK, i, 4);
      vf.Sound = sFS1Ae;
      vf = Game.GetViewFrame(EGOWALK, i, 10);
      vf.Sound = sFS1Ae;
    }
    i++;
  }
}


Cheers and thanks a million for all your help.
Paul.

Khris

Why did you move i's declaration outside the function?

Put "int i;" at its start and you're done.

You can shorten that code, too, btw:
Code: ags
function room_RepExec() {

  //===== FOOTSTEP SOUNDS =====//
  int i, idle, norm;
  if (Region.GetAtRoomXY(player.x, player.y) == region[2]) {
    idle = sFS2Be; norm = sFS2Ae;
  }
  else {
    idle = sFS1Be; norm = sFS1Ae;
  }

  while (i<8) {
    vf = Game.GetViewFrame(EGOWALK, i, 0);
    vf.Sound = idle; // idle footstep
    vf = Game.GetViewFrame(EGOWALK, i, 4);
    vf.Sound = norm;
    vf = Game.GetViewFrame(EGOWALK, i, 10);
    vf.Sound = norm;
    i++;
  }
}

subspark

Your kidding me! Now that's compact code. I would never have figured that out on my own. Give me a good 4 years at scripting perhaps.

Thanks Khris. I see how it works. Most appreciated.  ;D
Paul.

subspark

#9
There is one problem actually. The footstep sounds don't change from stone to metal soon enough when the game checks to see if the player is on the region. Is there a way, and I mean this in the most nonequivocal manner, to change the the pivot of a character or object via code, or is this something that people believe should be added as a feature?

Unfortunately detection of whether a character steps onto a region is calculated by the center pivot of a character. Obviously, this doesn't allow for accurate detection on frames where the character's limbs are extended beyond the center pivot and planted on the ground.

The manual didn't turn up much when 'pivot' was searched but I'm left to wonder if this has been done before via different means.

Cheers,
Paul.

OneDollar

Its been a several days since anyone replied to this, so apologies for the thread digging. However, on the off-chance that you haven't already solved it and I can be of some help...

You could find out which way the character is facing using character.Loop, then instead of using Region.GetAtRoomXY(player.x, player.y), calculate a new x and y coordinate for the region detection using player.x + characterwidth and player.y + characterheight, where characterwidth and characterheight are either hardcoded values or something calculated from, e.g. Character.BlockingHeight and Character.BlockingWidth. That way if for example the character is moving to the right the region detection takes place a few pixels to the right of their current coordinate.
Code: ags

if (character.Loop==2){
  Region.GetAtRoomXY(player.x + player.BlockingWidth/2, player.y);
}else{
  //etc
}


Obviously its not going to be perfect, especially if you don't use diagonal walking loops, but it shouldn't be any worse than the current method.

subspark

Sounds interesting OneDollar. Thanks for replying. I was hoping someone would answer my question sometime. I didn't want to bump the thread if nobody was able to help me. Ideally, the region adjustment should be based on what frame of a particular loop the character is in rather than just the loop alone because the character takes up more hotizontal space when his foot is extended outward and his heel hits the ground for the first time. This is the frame where the region or something needs to be adjusted to compensate for the character's foot position. There must be an easier way to simulate the collision detection of the character's foot.

Thanks again,
Paul.

GarageGothic

#12
If you don't use viewframe sounds but instead trigger each sound from repeatedly_execute by detecting the character's frame (assuming all loops have the same number of frames), you can do the offset through a simple if/else chain:

Code: ags
function repeatedly_execute_always() {
   if (IsGamePause() == 0) {
       if ((player.Frame == 3) || (player.Frame == 7)) { //the two foot impact frames
          int offsetx; //offsets in coordinates from character.x,character.y
          int offsety; //we're gonna use positive numbers
          if (player.Frame == 3) {
             if (player.Loop == 0) {
                offsetx = 10;
                offsety = 2;
                }
             else if (player.Loop =  1) {
                offsetx = -5;
                offsety = 4;
                }
             //Etc. etc.
             }
          //Repeat for other foot
          if (Region.GetAtRoomXY(player.x+offsetx, player.y-offsety) == region[1])  PlaySound (norm);
          else if (Region.GetAtRoomXY(player.x+offsetx, player.y-offsety) == region[2])  PlaySound (norm2);
          //and so on
          }
      }
   }


You could also set up a large struct based on each character's loop and frame settings and store the information there. Each character would still need loops*2 coordinate sets defined for him though.

subspark

Would a struct simplify the amount of code though? I'm having a play with structs now and will post with a progress report. Hopefully I'll be able to figure something out.

Thanks GarageGothic,
Paul.

GarageGothic

#14
Well, yes it would simplify the code to store the coordinate offsets in a struct. The work is about the same, but it would certainly be cleaner to replace that long sequence of if's with an initialization when starting the game. And especially if you later want to release the code as a module, it would definitely be the way to go.

I guess a simple function such as:

Character.SetupFootStepSound(int loop, int frame, int offsetx, int offsety, int sound);

should do the trick. I would recommend setting up several footstep sounds for each character and material though, which would add another parameter to the function. For my game, I set it up so that every character has three step sounds for each floor material. As the sound is playing it is randomized, but with an exception rule that the same sound can't play twice in a row. So if sound 1 is playing, the next sound must be either sound 2 or 3, and so on. It gives a nice, natural sounding step rhythm.

Edit: I should add that since this method plays the sound directly, not using AGS' internal viewframe sounds, the volume won't drop when the character is scaled with walkable area scaling. This is easily solved by playing the footstep sounds in a specific channel using PlaySoundEx and changing the channel volume proportionally to Character.Scaling property.

subspark

Yes. Controlled randomness using rules is something I am very familiar with. Thanks for the suggestions GarageGothic.

Most appreciated. I will try writing a few structs soon tonight. I hope I don't get stuck but don't hold your breath thinking I'll be successful without some kind of hitch. ;) I'm no code-jamming wiz here. Just an artist who enjoys a bit of casual scripting here and there. Still, I don't doubt that this is something I can do. At least with what's been shown already.

Thanks again,
Paul.

SMF spam blocked by CleanTalk