List scrolling problem

Started by Silent Bob, Sun 22/04/2018 11:35:09

Previous topic - Next topic

Silent Bob

Hi there :),

I've been recently working on my save/load system customization. I'm facing the list scrolling issue. In the RepExec section of Global Script i put this simple code:


if (IsKeyPressed(eKeyUpArrow) && gPanel.Visible == true)
{
   if (lstSaveGamesList.SelectedIndex > 0)
        {
      lstSaveGamesList.SelectedIndex--;
        }
}
else if (IsKeyPressed(eKeyDownArrow) &&  gPanel.Visible == true)
{            
   if (lstSaveGamesList.SelectedIndex < lstSaveGamesList.ItemCount - 1)   
        {
      lstSaveGamesList.SelectedIndex++;
        }
}


The scrolling works fine, but unfortunately sometimes when I press the upArrow or downArrow, the selection skips 2 times, instead of just one :sad:. Sometimes for some reason selection stays in the same position while pressing the button. It seems it's random. Any ideas why does it occur?

Mike
If you wanna do something - you seek for solution, if you don't want to - you seek for a reason.

Snarky

I think there should be a general instruction to all novice AGS coders: Don't use RepExec()/repeatedly_execute()/repeateadly_execute_always()! Just don't.

These functions are necessary for some things, but newbies seem to default to putting all their code in there, when it should be the last resort for when there's no other alternative.

In this case, the correct alternative is to use on_key_press().

Gurok

Oh, and the reason why you're sometimes getting skips is because when you press up/down, you're really holding it down for a very short time. IsKeyPressed detects whether a key is currently held down. Sometimes, you're holding the key for two game cycles, hence the "skip".

Do what Snarky said.
[img]http://7d4iqnx.gif;rWRLUuw.gi

Silent Bob

Thank You both for suggestions :)

Mike
If you wanna do something - you seek for solution, if you don't want to - you seek for a reason.

Silent Bob

#4
If I set this all on 'on_key_press' section, then it also works, but triggering action is strange. When it was on RepExec the multiple skips occured due to game cycles, but scrolling was really smooth. Here You have to push the Arrow keys like on writing machine to make it work. Otherwise it doesn't.
If you wanna do something - you seek for solution, if you don't want to - you seek for a reason.

Snarky

The keyrepeat might vary from computer to computer, I think? But yeah, that's the trade-off.

To get the best of both worlds you'd probably need something more complex, along these lines:

Code: ags
#define KEY_REPEAT_THRESHOLD 10 // Change this to adjust the delay from "move one space" to "scroll continuously"

int keyUpRepeat;
int keyDownRepeat;

function on_key_press(eKeyCode keycode)
{
  switch(keycode)
  {
    case eKeyUpArrow:
      if(gPanel.Visible && keyUpRepeat == 0)
      {
        keyUpRepeat++;
        if(lstSaveGamesList.SelectedIndex > 0)
          lstSaveGamesList.SelectedIndex--;
      }
      break;
    case eKeyDownArrow:
      if(gPanel.Visible && keyDownRepeat == 0)
      {
        keyDownRepeat++;
        if(lstSaveGamesList.SelectedIndex < lstSaveGamesList.ItemCount - 1)
          lstSaveGamesList.SelectedIndex++;
      }
      break;
  }
}

function repeatedly_execute()
{
  if(IsKeyPressed(eKeyUpArrow))
  {
    if(keyUpRepeat > KEY_REPEAT_THRESHOLD && gPanel.Visible && lstSaveGamesList.SelectedIndex < lstSaveGamesList.ItemCount - 1)
      lstSaveGamesList.SelectedIndex--;
    keyUpRepeat++;
  }
  else
    keyUpRepeat = 0;
  if(IsKeyPressed(eKeyDownArrow))
  {
    if(keyDownRepeat > KEY_REPEAT_THRESHOLD && gPanel.Visible && lstSaveGamesList.SelectedIndex < 0)
      lstSaveGamesList.SelectedIndex++;
    keyDownRepeat++;
  }
  else
    keyDownRepeat = 0;
}

Crimson Wizard

#6
As an alternative, I think it may be possible to utilize KeyListener module here, that lets you know how long a key was held down, etc:
http://www.adventuregamestudio.co.uk/forums/index.php?topic=53226.0

It basically does same thing as Snarky's code is doing, but hides a part of implementation, so your script may look like:
Code: ags

#define KEY_REPEAT_THRESHOLD 120 // how long to wait before next scroll, in milliseconds

function repeatedly_execute()
{
  if (gPanel.Visible)
  {
     if (KeyListener.IsKeyDown[eKeyUpArrow] && KeyListener.KeyDownTime[eKeyUpArrow] > KEY_REPEAT_THRESHOLD)
     {
        if (lstSaveGamesList.SelectedIndex < lstSaveGamesList.ItemCount - 1)
           lstSaveGamesList.SelectedIndex--;
     }
     if (KeyListener.IsKeyDown[eKeyDownArrow] && KeyListener.KeyDownTime[eKeyDownArrow] > KEY_REPEAT_THRESHOLD)
     {
        if (lstSaveGamesList.SelectedIndex < 0)
           lstSaveGamesList.SelectedIndex++;
     }
   }
}

Silent Bob

#7
Damn, Snarky, as far this provides the most eligible solution :shocked:. Could You in short explain what does this code? I see now the logic is divided into 2 sections - out RepExec, and in RepExec. First one is fired by keyPress listener, and there are 2 cases described, each one increasing given int var if gPanel is visible and a given var is equal to 0.

Second part of logic is in RepExec section, and there are 2 conditions same depending on which arrow key was pressed and we have vars incrementation. Anyway why does this solution is the closest to ideal one if simple on_key_press from solution suggested earlier should theoretically work too, but it doesn't...


If you wanna do something - you seek for solution, if you don't want to - you seek for a reason.

Snarky

I can't quite figure out what you're asking, or even if it works just the way you want it to, but the logic of the code is thus:

-The on_key_press() code ensures that we never miss a keypress (because it always fires this event, while IsKeyPressed() only checks if the key is down at the particular moment you press it). By checking if(key__Repeat==0) we ensure that it is only called once per keypress (because if you hold down a button, on_key_press() will usually fire repeatedly after a while, and we want to ignore that).

-The repeatedly_execute() code is to take care of the smooth scrolling: when you hold down a key, it will fire every game loop (unlike on_key_press(), which I believe fires at a slower rate, maybe every 10 loops or so). However, to avoid a tap on a key accidentally moving two positions, and because we're already using on_key_press() to do the initial move, it's set up to not do anything the first 10 loops (0.25 seconds) that the key is down.

It's probably possible to cut down on the code repetition, but I couldn't think of an efficient way to do it.

SMF spam blocked by CleanTalk