Frustrating idle view problems

Started by Lewis, Tue 04/06/2013 08:25:14

Previous topic - Next topic

Lewis

Hello!

So, I have a player character who needs to be constantly in their idle view animation unless they're walking, in which case they take the normal animation.

Normal view is 23.
Idle view is 24.

On game start, I'm calling cPlayer.SetIdleView(24,0); (i.e. set the view number to 24, with a delay time of 0)

But this is causing the character to freeze on the first frame of the idle view, and only animate when walking. When the character walks, it animates through the idle view, not the normal view.

Refraining from calling cPlayer.SetIdleView on game start solves the problem, but I need the idle view to be constantly looping when you're not moving. I have no idea why setting the idle view is having an effect on the character's normal view.

Any ideas? I've been banging my head against the wall for an hour with this, and I just can't work out what's wrong.
Returning to AGS after a hiatus. Co-director of Richard & Alice and The Charnel House Trilogy.

Lewis

#1
Factor to consider: I'm using the AltKeyboardMovement module, which could I suppose have something to do with it. Anyone smarter than I that could tell me whether there's anything in this code that conflicts?

Code: AGS
// Alt Keyboard Movement module script

str_keys keys;
export keys;

int RunSpeed;
int LoopDomination;
int WalkView;
int RunView, RunSpeedX, RunSpeedY;
bool Moving;
bool Animating;
float DiagonalFactor;
bool AnimateAtEdge;
bool TurnIfBlocked = true;
bool Enabled = true;
int Mode;

static eKeyCode KeyboardMovement::GetKey(eKMKey key) {
  if (key == eKMKeyUp) return keys.Up;
  if (key == eKMKeyLeft) return keys.Left;
  if (key == eKMKeyDown) return keys.Down;
  if (key == eKMKeyRight) return keys.Right;
  if (key == eKMKeyRun) return keys.Run;
}

static void KeyboardMovement::SetKey(eKMKey key, eKeyCode k) {
  if (key == eKMKeyUp)    keys.Up = k;
  if (key == eKMKeyLeft)  keys.Left = k;
  if (key == eKMKeyDown)  keys.Down = k;
  if (key == eKMKeyRight) keys.Right = k;
}

static void KeyboardMovement::SetRunKey(eKMModificatorKeyCode k) {
  if (k >= 403 && k <= 407) keys.Run = k;
}

static void KeyboardMovement::SetMovementKeys(eKMMovementKeys mk) {
  if (mk == eKMMovementWASD) {
 //   KeyboardMovement.SetKey(eKMKeyUp, eKeyW);
    KeyboardMovement.SetKey(eKMKeyLeft, eKeyA);
 //   KeyboardMovement.SetKey(eKMKeyDown, eKeyS);
    KeyboardMovement.SetKey(eKMKeyRight, eKeyD);
  }
  if (mk == eKMMovementArrowKeys) {
    KeyboardMovement.SetKey(eKMKeyUp, eKeyUpArrow);
    KeyboardMovement.SetKey(eKMKeyLeft, eKeyLeftArrow);
    KeyboardMovement.SetKey(eKMKeyDown, eKeyDownArrow);
    KeyboardMovement.SetKey(eKMKeyRight, eKeyRightArrow);
  }
}

static int KeyboardMovement::GetRunSpeed() {
  return RunSpeed;
}  
static void KeyboardMovement::SetRunSpeed(int rs) {
  RunSpeed = rs;
}

static void KeyboardMovement::SetLoopDomination(eKMLoopDomination ld) {
  LoopDomination = ld;
}

static int KeyboardMovement::GetRunView() {
  return RunView;
}
static void KeyboardMovement::SetRunView(int rw, int rsx, int rsy) {
  RunView = rw;
  RunSpeedX = rsx;
  RunSpeedY = rsy;
}

static bool KeyboardMovement::Moving() {
  return Moving;
}
static bool KeyboardMovement::Animating() {
  return Animating;
}

static void KeyboardMovement::SetDiagonalFactor(float df) {
  DiagonalFactor = df;
}

static void KeyboardMovement::SetEdgeAnimation(bool aae) {
  AnimateAtEdge = aae;
}

static void KeyboardMovement::SetBlockedTurn(bool tib) {
  TurnIfBlocked = tib;
}

static bool KeyboardMovement::IsEnabled() {
  return Enabled;
}

static void KeyboardMovement::Disable() {
  Enabled = false;
}
static void KeyboardMovement::Enable() {
  Enabled = true;
}

static eKMMode KeyboardMovement::GetMode() {
  return Mode;
}
// for tapping mode: current xa, ya
int cxa, cya, rxa, rya;
static void KeyboardMovement::SetMode(eKMMode mode) {
  Mode = mode;
  cxa = 0;
  cya = 0;
  rxa = 0;
  rya = 0;
}

static void KeyboardMovement::StopMoving() {
  if (Mode == eKeyboardMovement_Tapping) {
    cxa = 0;
    cya = 0;
    rxa = 0;
    rya = 0;
  }
}

void game_start() {
  
  KeyboardMovement.SetMode();  // default: pressing
  
  // DIRECTIONAL KEYS
  KeyboardMovement.SetMovementKeys();  // default: WASD
  
  // RUN KEY MODIFICATOR
  KeyboardMovement.SetRunKey();  // default: Left Shift

  // RUN ANIMATION DELAY
  KeyboardMovement.SetRunSpeed();  // default: 2
  
  // DIAGONAL MOVEMENT WITHOUT DIAGONAL LOOPS USES
  KeyboardMovement.SetLoopDomination();  // default: last non-diagonal loop
  KeyboardMovement.SetDiagonalFactor(0.707);  
}

int walk_timer;

int Sgn(int i) {
  if (i < 0) return -1;
  if (i == 0) return 0;
  return 1;
}

int Abs(int i) {
  if (i == 0) return 0;
  return i/Sgn(i);
}

int xfree, yfree;

bool PathFree(int x, int y, int xa, int ya) {
  
  int i, j, step;
  bool go_x;
  if (Abs(xa) > Abs(ya)) { // horizontal domination
    step = Sgn(xa);
    go_x = true;
  }
  else step = Sgn(ya); // vertical domination
  
  xfree = x;
  yfree = y;
  
  if (go_x) {
    i = x+step;
    while (i != x+xa+step) {
      j = y + (ya*(i-x))/xa;
      if (GetWalkableAreaAt(i, j)) {
        xfree = i;
        yfree = j;
      }
      else i = x+xa;
      i += step;
    }
  }
  else {
    j = y+step;
    while (j != y+ya+step) {
      i = x + (xa*(j-y))/ya;
      if (GetWalkableAreaAt(i, j)) {
        xfree = i;
        yfree = j;
      }
      else j = y+ya;
      j += step;
    }
  }
  
  xfree -= x;
  yfree -= y;
  if (xfree == 0 && yfree == 0) return false;
  return true;
}

void AdvanceFrame(int xa, int ya, int l) {
    
  int sca = GetScalingAt(player.x, player.y);
  
  int sgn;
  if (player.ScaleMoveSpeed) {
    sgn = Sgn(xa);
    xa = (xa*sca)/100; if (xa == 0) xa = sgn;
    sgn = Sgn(ya);
    ya = (ya*sca)/100; if (ya == 0) ya = sgn;
  }
  bool free = PathFree(player.x - GetViewportX(), player.y - GetViewportY(), xa, ya);
  int x = player.x + xfree;
  int y = player.y + yfree;
    
  int pf = player.Frame;
  int pl = player.Loop;
  // advance frame
  pf++;
  // roll around
  if (pf >= Game.GetFrameCountForLoop(player.View, pl)) pf = 1;
  if (l != pl) { //player changes loop
    // translate frame to new loop
    // frame is 1-x
    // old last frame and new last frame
    int olf = Game.GetFrameCountForLoop(player.View, pl)-1;
    int nlf = Game.GetFrameCountForLoop(player.View, l)-1;
    if (olf != 1) pf = (pf*(nlf-1))/(olf-1);
    if (pf == 0) pf = 1;
  }
  // change loop
  if (free || TurnIfBlocked) {
    player.Loop = l;
  }
  // advance frame
  Animating = false;
  if (free || AnimateAtEdge) {
    Animating = true;
    player.Frame = pf;
  }
  else player.Frame = 0;
  // move player
  Moving = false;
  if (free) {
    Moving = true;
    player.x = x;
    player.y = y;
  }
}

int GetNewLoop(int xa, int ya, int old_loop) {

  int loop;                        // loops:         xa
  int i = (Sgn(ya)+1)*3+Sgn(xa)+1; //            <0   0  >0
  String s = "7351X2604";          //         <0  7 | 3 | 5
  s = String.Format("%c", s.Chars[i]); //  ya  0  1 | X | 2
  loop = s.AsInt;                  //         >0  6 | 0 | 4
  
  if (player.DiagonalLoops && Game.GetLoopCountForView(player.View) < 8) player.DiagonalLoops = false;
  if (player.DiagonalLoops || loop < 4) return loop;
  
  // movement is diagonal but view doesn't have diagonal loops/DM is turned off
  int ld = LoopDomination;
  // old loop determines new loop domination
  if (ld == eKMLoopDLast) {
    if (old_loop == 0 || old_loop == 3) ld = eKMLoopDVertical;
    else                                ld = eKMLoopDHorizontal;
  }
  if (ld == eKMLoopDHorizontal) {
    if (loop < 6) return 2; // right
                  return 1; // left
  }
  if (ld == eKMLoopDVertical) {
    if ((loop/2)*2 == loop) return 0; // down
                            return 3; // up
  }
}

void HandleKeyPresses() {
    
  if (Mode == eKMModePressing) {
    rxa = 0;
    rya = 0;
    if (IsKeyPressed(keys.Left)) {
      if (!IsKeyPressed(keys.Right))   rxa = -player.WalkSpeedX;
    }
    else if (IsKeyPressed(keys.Right)) rxa =  player.WalkSpeedX;
    if (IsKeyPressed(keys.Up)) {
      if (!IsKeyPressed(keys.Down))    rya = -player.WalkSpeedY;
    }
    else if (IsKeyPressed(keys.Down))  rya =  player.WalkSpeedY;  
  }
}
  
void on_key_press(eKeyCode k) {
    
  if (!Enabled) return;
  
  if (Mode != eKeyboardMovement_Tapping) return;
  
  if (player.Moving) player.StopMoving();
  
  if (k == keys.Left) {
    if (cxa != -player.WalkSpeedX) {
      cxa = -player.WalkSpeedX;
      cya = 0;
    }
    else cxa = 0;
  }
  if (k == keys.Right) {
    if (cxa != player.WalkSpeedX) {
      cxa = player.WalkSpeedX;
      cya = 0;
    }
    else cxa = 0;
  }
  if (k == keys.Up) {
    if (cya != -player.WalkSpeedY) {
      cya = -player.WalkSpeedY;
      cxa = 0;
    }
    else cya = 0;
  }
  if (k == keys.Down) {
    if (cya != player.WalkSpeedY) {
      cya = player.WalkSpeedY;
      cxa = 0;
    }
    else cya = 0;
  }
    
  rxa = cxa;
  rya = cya;
}


void HandleMovement() {  
    
  HandleKeyPresses();
  int xa = rxa;
  int ya = rya;
  
  // reset frame timer to:
  int set_wt_to = player.AnimationSpeed;

  // running?
  if (IsKeyPressed(keys.Run) && !player.Moving) {
    // adjust timer reset
    set_wt_to = RunSpeed;
    // run view?
    if (RunView > 0) {
      // change view if necessary, store walk view
      if (player.View != RunView) {
        WalkView = player.View;
        player.ChangeView(RunView);
      }
      // adjust movement vars
      xa = (xa*RunSpeedX)/player.WalkSpeedX;
      ya = (ya*RunSpeedY)/player.WalkSpeedY;
    }
  }
  else if (player.View == RunView && WalkView > 0) player.ChangeView(WalkView);
  
  int loop = GetNewLoop(xa, ya, player.Loop);
  
  int sgn;
  if (walk_timer == 0) {
    if (xa == ya && xa == 0) {
      if (!player.Moving) player.Frame = 0;
      Moving = false;
      Animating = false;
    }
    else if (xa*ya == 0) {  // horizontal or vertical movement
      if (player.Moving) player.StopMoving();
      walk_timer = set_wt_to;
      AdvanceFrame(xa, ya, loop);
    }
    else {                  // diagonal movement
      if (player.Moving) player.StopMoving();
      walk_timer = set_wt_to;
      sgn = Sgn(xa);
      xa = FloatToInt(IntToFloat(xa)*DiagonalFactor, eRoundNearest);
      if (xa == 0) xa = sgn;
      sgn = Sgn(ya);
      ya = FloatToInt(IntToFloat(ya)*DiagonalFactor, eRoundNearest);
      if (ya == 0) ya = sgn;
      AdvanceFrame(xa, ya, loop);
    }
  }
  else walk_timer--;
}

void repeatedly_execute() {
  if (Enabled) HandleMovement();
}  

void on_mouse_click(MouseButton button) {
  if (mouse.Mode == eModeWalkto) {
    rxa = 0;
    rya = 0;
  }
}


EDIT: It is something to do with the module! At least in some respect.

I just turned my mouse movement back on, and tried moving the character with the mouse. The correct 'walk' animation plays. However, the character's idle view still doesn't animate - it just hangs on the first frame. Any help would be massively appreciated.
Returning to AGS after a hiatus. Co-director of Richard & Alice and The Charnel House Trilogy.

Lewis

#2
Okay, third post in a row from me, but very slowly I'm starting to understand how this works, and I figure I may as well record my progress for anyone else facing this problem down the line.

I have fixed the problem where the idle view doesn't animate by commenting out some key lines in the Alt Keyboard Movement module:

  //TEST     if (!player.Moving) player.Frame = 0;
  //TEST    Moving = false;
  //TEST    Animating = false;

However, using the keyboard controls, the player's normal view still isn't right. However, I've had an idea...

EDIT: Hmm, no, I thought I had an idea but it didn't work.

Basically, when I try to move my character with the keyboard, it's not taking him out of the idle view, and is instead using the idle view as the walk view. It's something to do with the keyboard module but I can't figure out exactly what. Any ideas?
Returning to AGS after a hiatus. Co-director of Richard & Alice and The Charnel House Trilogy.

MiteWiseacreLives!

Had this same problem and could find nothing that helped.
AGS version 3.3.0?? Hopefully if anyone is listening they could look into this?

kaput

#4
Blasphemy removed - wait for Khris  :P

Lewis

I'll try that after work, cheers.

Pretty sure it's something to do with the way the keyboard module handles movement - i.e. it overwrites the standard movement functions and ties all the key-presses directly to animations etc. I'm just not an adept enough programmer to be able to spot where in the module this is being handled.
Returning to AGS after a hiatus. Co-director of Richard & Alice and The Charnel House Trilogy.

kaput

Actually, the more I think about it the more I see that the code I gave you is a mess and there's a 95% chance it won't work. Sorry buddy.

Khris

#7
The issue is fixed now.
My module doesn't use Walk(), it directly changes the player's position and frame. Thus, the IdleView isn't stopped. The only way to do so is turn if off temporarily.

The fixed download is at the same location:
https://dl.dropbox.com/s/0ffncwkp218brgy/AltKeyboardMovement.scm?dl=1

As for why your idle view hangs at the first frame: no idea what could be causing that. While fixing my module I created a test idle view with four loops and set the key and pink poster as the first two frames in each. It did animate just fine, although the second frame was displayed considerably shorter than the first.

MiteWiseacreLives!

I find without the module the idle animation won't run continuously, always sits for a second then begins (once you stop walking that is).

Lewis

Khris, you're a legend. Will try out later on.
Returning to AGS after a hiatus. Co-director of Richard & Alice and The Charnel House Trilogy.

SMF spam blocked by CleanTalk