Glitches - Mouse.Mode issue and Unwanted Character Animations

Started by KodiakBehr, Mon 27/08/2012 23:26:11

Previous topic - Next topic

KodiakBehr

Hey, I've uncovered two bugs that I cannot reproduce at will which makes it extremely difficult to ascertain what is going wrong.

1.  Sometimes, without any obvious explanation, the character will play a loop unrelated to his walk-cycle when walking.  Any guesses on what can cause that?
2.  The inventory system doesn't deviate too much from the default Sierra system.  Despite the fact that the code says:

Code: ags

function show_inventory_window () 
{
  gInventory.Visible = true;
  // switch to the Use cursor (to select items with)
  mouse.Mode = eModeInteract;
  // But, override the appearance to look like the arrow
  mouse.UseModeGraphic(eModePointer);
}


Occasionally (but inconsistently) the inventory will appear but the cursor will still be the walk cursor.  Any ideas on what could cause that?

Thanks.

KB

Khris


KodiakBehr

Default game template, minus the keyboard movement, and a custom module I don't fully understand that generates text as an overlay...though I don't see how it would impact either bug.

The first bug I mentioned appears to play the last character animation loop, regardless of what it did, in place of walking forward.

Khris

So the character's NormalView contains additional loops unrelated to walking?
I'd use a different view for that.
Also make sure you've turned off Diagonal Loops in the character's properties.

As for the second issue, something in the code must cause that. There's not much we can do without looking at at least all the repeatedly_execute functions of your game.

KodiakBehr

Yup, I didn't realize that was a bad practice.  Though for what it's worth, diagonal loops was left on, and turning it off appears to have resolved the issue.  Many thanks for that.

Regarding the second issue, in the global script, we have this repeatedly executing --

Code: ags


  int old_mode;
  bool was_over_inventory_button;
  bool was_over_cellphone_button;
  bool was_over_menu_button;

function repeatedly_execute_always() {

  
GUIControl*gc = GUIControl.GetAtScreenXY(mouse.x, mouse.y);
  if (gc == btnIconInv && !was_over_inventory_button) { // mouse just went over the button
    was_over_inventory_button = true;
    old_mode = mouse.Mode;
    mouse.Mode = eModePointer;
  }
  

  if (gc != btnIconInv && was_over_inventory_button) { // mouse just went away from button
    was_over_inventory_button = false;
    if (mouse.Mode != eModeUseinv) mouse.Mode = old_mode;
  }

  if (gc == btnCellphone && !was_over_cellphone_button) { // mouse just went over the button
    was_over_cellphone_button = true;
    old_mode = mouse.Mode;
    mouse.Mode = eModePointer;
  }
  

  if (gc != btnCellphone && was_over_cellphone_button) { // mouse just went away from button
    was_over_cellphone_button = false;
    if (mouse.Mode != eModeUseinv) mouse.Mode = old_mode;
  }

  if (gc == btnIconMenu && !was_over_menu_button) { // mouse just went over the button
    was_over_menu_button = true;
    old_mode = mouse.Mode;
    mouse.Mode = eModePointer;
  }
  

  if (gc != btnIconMenu && was_over_menu_button) { // mouse just went away from button
    was_over_menu_button = false;
    if (mouse.Mode != eModeUseinv) mouse.Mode = old_mode;
  }


if (gCellphone.Visible==true){mouse.UseModeGraphic(eModePointer);
}
}


And in the module script, we have this repeatedly executing --

Code: ags

function repeatedly_execute_always()
{
    isNew = true;
    if (oLabel != null && oLabel.Valid) {
      oLabel.Remove();
      isNew = false;
      
    }
    
    if (isNew) {
      moveTimer = 0.0;
    }
    String s = Game.GetLocationName(mouse.x,  mouse.y);
    if (s == null || s == "") return;
    
    int width = _clamp(GetTextWidth(s, Font), 0, MaxWidth);
    int height = GetTextHeight(s, Font, width + 2);
    
    float smooth = _smoothstep(0.0, 1.0, moveTimer);
    
    int drawY = FloatToInt(_lerp(IntToFloat(height), 0.0, smooth));
     //int drawY = FloatToInt(Maths.Sqrt((1.0 - moveTimer) * 100.0), eRoundNearest);
    moveTimer = saturate(moveTimer + 0.1);
    
     
    if (!SlideIn) drawY = 0;
    
    sprite = DynamicSprite.Create(width, height, true);
    DrawingSurface *surf = sprite.GetDrawingSurface();
    surf.DrawingColor = Color;
    surf.DrawStringWrapped(0, drawY, width + 1, Font, eAlignLeft, s);
    surf.Release();
    
    float targetx = IntToFloat(_clamp(mouse.x - width / 2, 0, System.ViewportWidth - width));
    float targety = IntToFloat(_clamp(mouse.y - height, 0, System.ViewportWidth - height));
    
    float x, y;
    
    
    if (isNew || !SpringOn){
      x = targetx;
      y = targety;
  
    }
    else 
    {


        x = lastMX - (lastMX - targetx) / 4.0;
        y = lastMY - (lastMY - targety) / 4.0;
    }
      
      lastMX = x;
      lastMY = y;
    
    //Display("Showing %s at: %d %d", s,  x,  y);
    
      if (!gInventory.Visible && IsInterfaceEnabled()) {
        oLabel = Overlay.CreateGraphical(FloatToInt(x, eRoundNearest), FloatToInt(y, eRoundNearest) + Offset, sprite.Graphic,  true);
      }
}



Grateful for any thoughts you might have.  I appreciate that showing labels as overlays is seen as being a bit dodgy.

KB

Khris

Well, in theory it's fine to put additional animation loops in the NormalView, but I'd skip loops 4-7 in that case. Unless you're positive that you won't add diagonal walk cycles at some point in the future.

Right, I remember the thread about changing the cursor over the buttons.
I guess it's pretty safe to say that the second issue is caused by that.
What's in btnIconInv_OnClick?

KodiakBehr

Code: ags

function btnIconInv_Click(GUIControl *control, MouseButton button) {

btnCellphone.Visible=false;
if (player.NormalView==1){player.Animate(9, 0, eOnce, eBlock, eForwards);} // if our protagonist is normal sized, show him pulling out his tablet before loading the inventory
else if (player.NormalView==6){player.Animate(10, 2, eOnce, eBlock, eForwards);}  //if our protagonist is tiny in the city view, do the same

  show_inventory_window();
}


Which leads us to...

Code: ags


function show_inventory_window () 
{
  btnIconMenu.Visible=false;
  btnIconInv.Visible=false;
  gInventory.Visible = true;
  // switch to the Use cursor (to select items with)
  mouse.Mode = eModeInteract;
  // But, override the appearance to look like the arrow
  mouse.UseModeGraphic(eModePointer);
}



And then it's turtles all the way down.  I can't see any scenario where upon loading the game inventory the cursor is anything BUT an interact cursor disguised as a pointer, yet occasionally it shows up as my WalkTo icon for reasons beyond my understanding and beyond my ability to replicate.

If there's nothing obvious in any of this, and you're still interested/willing to look at it, I'm happy to share the entire source code with you.  Maybe I'd learn a thing or two on what I could be doing better.

Khris

The explanation is actually pretty simple:

The way the rep_exe code works is:
-store the current mouse mode when player hovers over btnIconInv, switch to pointer
-upon leaving the button, restore previous mode

Any time you want to open the inventory:
-mouse is moved over button, current mouse.Mode is stored in old_mode, mouse.Mode is changed to Pointer
-show_inventory changes mode to eModeInteract but switches graphic to Pointer, i.e. user doesn't notice the change
-user starts operating the inventory GUI, the mouse leaves btnIconInv in order to do so, and old_mode is restored

Now, if old mode was eModeInteract, nothing changes. But if old_mode was eModeWalkto, that's restored, per the instructions in rep_exe.

The solution is to disable the rep_ex instruction. Make sure that show_inventory is below the rep_exe and its variables, then add this line to it:
Code: ags
  was_over_inventory_button = false;

KodiakBehr

That did the trick.  I cannot express my gratitude for picking up on that.

SMF spam blocked by CleanTalk