Walk cycle question

Started by FortressCaulfield, Mon 10/02/2025 11:38:05

Previous topic - Next topic

FortressCaulfield

My walk cycle works great. But I want to add more frames to the left and right loops to smooth them out. But I don't want the char's walk speed to change. I see there's an animationspeed setting, but I only want the left and right walk cycles to change. And I know I can adjust walkspeedx but that won't help unless I can also speed up her left and right loops.

I know could call a custom function every time I want to move her where I set animationspeed, call walk and then set animationspeed back again, but I'm way too far in to go back and do that, and the logistics of making it work with all the different ways a char might move is daunting.
"I can hear you! My ears do more than excrete toxic mucus, you know!"

-Hall of Heroes Docent, Accrual Twist of Fate

Snarky

If you double the number of frames in the animation, you have to cut the animation delay in half keep the time of the animation the same, and then cut the movement distance (called "movement speed" in AGS) in half in order to keep the same walking speed.

I don't think it's possible to have different animation delays for the different loops, without the kind of custom function you talk about (and even then it is not trivial).

One possible workaround is to add each frame twice to the up/down animations. If you have movement linked to animation speed, this may introduce some gliding. If this is noticeable, you would have to modify at least the legs in the in-between frames.

Danvzare

#2
Quote from: FortressCaulfield on Mon 10/02/2025 11:38:05My walk cycle works great. But I want to add more frames to the left and right loops to smooth them out. But I don't want the char's walk speed to change. I see there's an animationspeed setting, but I only want the left and right walk cycles to change. And I know I can adjust walkspeedx but that won't help unless I can also speed up her left and right loops.

I know could call a custom function every time I want to move her where I set animationspeed, call walk and then set animationspeed back again, but I'm way too far in to go back and do that, and the logistics of making it work with all the different ways a char might move is daunting.
A quick and dirty solution would be to set movementLinkedToAnimation to false, therefore unlinking your walking animation from the speed the character walks at.
Also, it looks better in my opinion (and to Ron Gilbert apparently, if Thimbleweed Park is anything to go by). Since it removes that jerky look. But that's just my personal preference. You may prefer it on. In which case, I'd suggest following Snarky's advice.

FortressCaulfield

Quote from: Snarky on Mon 10/02/2025 12:58:29I don't think it's possible to have different animation delays for the different loops, without the kind of custom function you talk about (and even then it is not trivial).

Even putting the loops aside doesn't the char.animationspeed setting affect ALL of a char's animation?
"I can hear you! My ears do more than excrete toxic mucus, you know!"

-Hall of Heroes Docent, Accrual Twist of Fate

Snarky

Quote from: Danvzare on Mon 10/02/2025 17:15:48A quick and dirty solution would be to set movementLinkedToAnimation to false, therefore unlinking your walking animation from the speed the character walks at.

This doesn't actually solve the fundamental problem FortressCaulfield is having: to have the animation of one pace (the animation loop) take the same amount of time whichever direction the character is walking, even though the animations don't have the same number of frames.

There are actually a lot of AGS games that suffer from this. It's especially noticeable if they have footstep sounds linked to the animation, where the rhythm changes every time the character changes direction.

Quote from: FortressCaulfield on Mon 10/02/2025 20:03:28Even putting the loops aside doesn't the char.animationspeed setting affect ALL of a char's animation?

Yes, I believe so, but you would only be changing it when the character is walking, so that doesn't really matter. But I don't know exactly what happens if you start changing Character.AnimationSpeed while the character is walking. Some experimentation would be needed.

Kara Jo Kalinowski

#5
Code: ags
function repeatedly_execute_always() 
{
    if (player.Moving) {
    switch (player.Loop) {
      case 0: //Down
      case 3: //Up
      player.AnimationSpeed = 1;
      break;
      case 1: //Left
      case 2: //Right
      player.AnimationSpeed = 4;
      break;
    }
  }
}

Animation speed determines how many frames delay there are between changing animation frames, but it only takes integers. You will need to adjust this based on how many frames are in your view. (I'm assuming some programming knowledge here, but if you need further help, feel free to ask.) Now, this is going to change the walking speed. You have 2 options. You can set the character's MovementLinkedToAnimation to false, in which case it will have more of a gliding effect (you'll need to also adjust MovementSpeed lower to get it to appear right), or you can keep it to true, but change it like so:

Code: ags
function repeatedly_execute_always() 
{
    if (player.Moving) {
    switch (player.Loop) {
      case 0: //Down
      case 3: //Up
      player.AnimationSpeed = 1;
      player.SetWalkSpeed(2, 2);
      break;
      case 1: //Left
      case 2: //Right
      player.AnimationSpeed = 4;
      player.SetWalkSpeed(4, 4);
    }
  }
}

I don't know exactly how the speed is calculated, but this appears somewhat good for me.

I have it set to repeatedly_execute_always so that if walking as a result of a script while blocking other inputs, it will still update the speeds.

Snarky

#6
Quote from: Kara Jo Kalinowski on Tue 11/02/2025 06:39:17
Code: ags
function repeatedly_execute_always() 
{
    if (player.Moving) {
    switch (player.Loop) {
      case 0: //Down
      case 3: //Up
      player.AnimationSpeed = 1;
      player.SetWalkSpeed(2, 2);
      break;
      case 1: //Left
      case 2: //Right
      player.AnimationSpeed = 4;
      player.SetWalkSpeed(4, 4);
    }
  }
}

As the arguments to SetWalkSpeed are x_speed and y_speed (which is actually the x-distance and y-distance; they have been misnamed since forever), you don't need to change them depending on whether you're moving vertically or horizontally. You can simply leave them as player.SetWalkSpeed(4,2) (or just turn off UniformMovementSpeed and set them to those values in the IDE character editor), and it will use 4 when moving horizontally and 2 when moving vertically.

What I don't have any idea of is how the distance is calculated when moving diagonally, especially if you have different x and y speeds.

Also, the manual entry for SetWalkSpeed claims: "This function CANNOT be called while the character is moving, so you must stop him first." Have you tested it to see that that's not correct?

Kara Jo Kalinowski

#7
Quote from: Snarky on Tue 11/02/2025 19:15:21
Quote from: Kara Jo Kalinowski on Tue 11/02/2025 06:39:17
Code: ags
function repeatedly_execute_always() 
{
    if (player.Moving) {
    switch (player.Loop) {
      case 0: //Down
      case 3: //Up
      player.AnimationSpeed = 1;
      player.SetWalkSpeed(2, 2);
      break;
      case 1: //Left
      case 2: //Right
      player.AnimationSpeed = 4;
      player.SetWalkSpeed(4, 4);
    }
  }
}

As the arguments to SetWalkSpeed are x_speed and y_speed (which is actually the x-distance and y-distance; they have been misnamed since forever), you don't need to change them depending on whether you're moving vertically or horizontally. You can simply leave them as player.SetWalkSpeed(4,2) (or just turn off UniformMovementSpeed and set them to those values in the IDE character editor), and it will use 4 when moving horizontally and 2 when moving vertically.

Also, the manual entry for SetWalkSpeed claims: "This function CANNOT be called while the character is moving, so you must stop him first." Have you tested it to see that that's not correct?

Yes, I did, and it worked. Your solution wouldn't work - both horizontal and vertical walk speed need to change to the same amounts depending on which direction you are facing since you don't walk in purely straight lines i.e. you will still be moving left or right sometimes even when facing down. (I was thinking the same as you at first and it doesn't work.)

My animation speeds are extreme examples though, the right settings would depend on how many frames are in the animation. In this case, it plays the up/down animations 4 times as fast which is almost definitely not what OP wants.

Snarky

#8
Quote from: Kara Jo Kalinowski on Tue 11/02/2025 19:18:58Yes, I did, and it worked. Your solution wouldn't work - both horizontal and vertical walk speed need to change to the same amounts depending on which direction you are facing since you don't walk in purely straight lines i.e. you will still be moving left or right sometimes even when facing down. (I was thinking the same as you at first and it doesn't work.)

Ah, I see your point. You're assuming that the x_speed and y_speed are equal in the first place? So if they are different, you would need something like:

Code: ags
function repeatedly_execute_always() 
{
    if (player.Moving) {
    switch (player.Loop) {
      case 0: //Down
      case 3: //Up
      player.AnimationSpeed = 1;
      player.SetWalkSpeed(2, 1);
      break;
      case 1: //Left
      case 2: //Right
      player.AnimationSpeed = 4;
      player.SetWalkSpeed(4, 2);
    }
  }
}

(I find it surprising that changing the AnimationSpeed (i.e. frame delay) from 1 to 4 only requires a doubling of the walk speed to remain consistent, but the logic of the frame delays always makes my head spin. I think it's that the base value is 1 loop per frame, and the delay is added to that, so that AnimationSpeed = 1 actually means it changes frame every 2 loops, and AnimationSpeed = 4 means every 5 loops—40% of the speed—but I'm not 100% sure.)

Kara Jo Kalinowski

Quote from: Snarky on Tue 11/02/2025 19:26:29
Quote from: Kara Jo Kalinowski on Tue 11/02/2025 19:18:58Yes, I did, and it worked. Your solution wouldn't work - both horizontal and vertical walk speed need to change to the same amounts depending on which direction you are facing since you don't walk in purely straight lines i.e. you will still be moving left or right sometimes even when facing down. (I was thinking the same as you at first and it doesn't work.)

Ah, I see your point. You're assuming that the x_speed and y_speed are equal in the first place? So if they are different, you would need something like:

Code: ags
function repeatedly_execute_always() 
{
    if (player.Moving) {
    switch (player.Loop) {
      case 0: //Down
      case 3: //Up
      player.AnimationSpeed = 1;
      player.SetWalkSpeed(2, 1);
      break;
      case 1: //Left
      case 2: //Right
      player.AnimationSpeed = 4;
      player.SetWalkSpeed(4, 2);
    }
  }
}

(I find it surprising that changing the AnimationSpeed (i.e. frame delay) from 1 to 4 only requires a doubling of the walk speed to remain consistent, but the logic of the frame delays always makes my head spin. I think it's that the base value is 1 loop per frame, and the delay is added to that, so that AnimationSpeed = 1 actually means it changes frame every 2 loops, and AnimationSpeed = 4 means every 5 loops—40% of the speed—but I'm not 100% sure.)

Yeah, right, if it's actually meant to be different speeds then you'd need to adjust both of those speeds. I wasn't being super precise with my calculations, just did what seemed to be 'about right' based on my animation speeds. For a typical AGS walk animation, x speed and y speed are usually equal.

If you need more precision than what this solution is offering, it's probably possible to make a generalized script based on the number of frames in the views. But, these functions don't accept floats, so it might be a bit more complicated to be exactly precise. Maybe I can code something...

SMF spam blocked by CleanTalk