My tetris is reacting to fast to input

Started by
8 comments, last by JensB 18 years, 4 months ago
This is the CheckInput function that gets called every time in my game loop

        public void CheckInput()
        {
            if (++lastInput < 50)
                return;

            KeyboardState state = inputDevice.GetCurrentKeyboardState();

            if (state[Key.Left])
            {
                if (--currentX < 0)
                    currentX = 0;
            }

            if (state[Key.Right])
            {
                if (++currentX > 10)
                    currentX = 9;
            }

            if (state[Key.Up])
            {
                if (++currentRotation > 3)
                    currentRotation = 0;
            }
        }

My problem is that the game reacts so damn fast to my input, rotating the pieces so I can barely see them. My attempt to correct it is the little if statement / counter you see in the begining - which i can probably tune to work fine....but then it wont work the same ways on other systems, that run faster or slower.... Any advice on how to handle input to make it...less....responsive? :P btw, the inputDevice is a DInput device.
// Jens
Advertisement
Do you use timer?
Secondly, you decide how fast to render/animate the rotation. Check your routines
-----"Master! Apprentice! Heartborne, 7th Seeker Warrior! Disciple! In me the Wishmaster..." Wishmaster - Nightwish
You have 2 options:

A DeltaTime implementation where All physics are done and integrated according to the ammount of time that passed

B A FPS Restrictor where it ensures that the program always runs at 60FPS on any machine

---------
I Suggest B Because if the frame rate was to drop very low then A would mean blocks could double rotate or not rotate at all.

Its quite as simple as this

/// 85Fps Limiter
--Init--
double time;
time = timeGetTime();

// Run after frame
void LimitFrame()
{
double newTime = timeGetTime();
while (newTime - time < 12) sleep(5);
time = newTime();
}

Now Sleep(1) does not guarantee a delay of 1ms so you might want to look at doing something else to slow it down but i would recommend slow though because it means if the USER is running any other programs that need resources the CPU is available.

Now this is important for sum1 running winamp in the background or stuff like that :-)
----------------------------

http://djoubert.co.uk
Quote:Original post by Red_falcon
Do you use timer?
Secondly, you decide how fast to render/animate the rotation. Check your routines


Consider the GAME MECHANICS of rotation and the RENDERING seperate, where once the button is pressed in GAME MECHANICS the object is rotated immediately(obviously the correct checks have been done) and then when rendering simple integrate it like this.

// Where RotateT is a float between 0 -- 1.0 where 1.0 is 100% to target


CurrentTime = timeGetTime();
if (Rotating == true) RotateT = (CurrentTime - startRotateTime) / RotateAnimationTime;

if (RotateT > 1)
{
RotateT = 1.0f;
Angle = TargetAngle;
Rotating = false;
}
//
So if you want the rotation to rotate in 250ms (1/4s) then simple make RotateAnimationTime == 250
----------------------------

http://djoubert.co.uk
slapped this in my render loop to limit fps:

            // limit to 70 fps -- QQQ is this really a good idea?            int now = System.Environment.TickCount;            while (now - lastFrame < 15)                // aproxes to 70 fps....QQQ            {                now = System.Environment.TickCount;                Application.DoEvents();                 // QQQ do i need to acctually sleep?            }


it still reacts waaaay to fast, so I think I have to go for some kind of combination of 1 and 2.
// Jens
That doesn't limit the response rate at all! It's counting up 15 milliseconds per frame, OK, but it still tries to doApplicationEvents() as often as it can in any given "frame" (in the while loop).

Plain FPS limiting looks like this (pseudocode):

gameloop:  repeat forever:    t1 = current_time()    do_physics()    draw_everything()    t2 = current_time()    sleep(frame_time - (t2 - t1))


Doing physics according to time elapsed looks like this:

gameloop:  t1 = current_time()  repeat forever:    t2 = current_time()    do_physics(t2 - t1)    draw_everything()    t1 = t2


There are other, more complicated options as well, involving not necessarily having a 1:1 ratio of updates and redraws.
There's no need to limit fps, you should just have a Input class which handle the keyboard state buffer, then define a KeyDown () function, which checks to see if user just pressed the button down. The code is similar to this:

* Assume you're using GetKeyboardState (), if you're using Windows messages, the following is still applicable:

The Update () method is called each frame:
class Input{public:    inline bool KeyDown (unsigned char const ucVKCode) const    {        return (!!(((m_ppucKBuffs[m_uiCurBuff][ucVKCode]) & (m_ppucKBuffs[m_uiCurBuff ^ 1][ucVKCode] ^ 128)) & 128)) ;    }    inline void Update ()    {        GetKeyboardState (m_ppucKBuffs[m_uiCurBuff ^= 1]) ;    }private:    unsigned char m_ppucKBuffs[2][256] ; //2 buffers, one current, one previous    unsigned int m_uiCurBuff ; //current key (and mouse) state buffer} ;


I've cut out unnecessary parts significantly:
  • Bit 8 (10000000 = 128) implies the key is pressed (1) or not (0).

  • m_uiCurBuff will only be 0 and 1.
    if m_uiCurBuff = 0 then m_uiCurBuff ^ 1 = 1 and vice versa.

     return (!!(((m_ppucKBuffs[m_uiCurBuff][ucVKCode]) & (m_ppucKBuffs[m_uiCurBuff ^ 1][ucVKCode] ^ 128)) & 128)) ;

    This line combines the following checks: the function return true when currently the key is being pressed and the last frame the key wasn't pressed
  • m_ppucKBuffs[uiCurBuff][ucVKCode] is the current state of key ucVKCode
  • m_ppucKBuffs[m_uiCurBuff ^ 1][ucVKCode] is the previous state of key ucVKCode

  • (m_ppucKBuffs[m_uiCurBuff ^ 1][ucVKCode] ^ 128) inverts key state, yields true if the last frame the key wasn't pressed.
  • So, (m_ppucKBuffs[uiCurBuff][ucVKCode]) & (m_ppucKBuffs[uiCurBuff ^ 1][ucVKCode] ^ 128) yields true if the key's just been pressed.

  • Finally, the whole expression (in short: exp) is and-ed and double inverted to convert it to bool value:
    (exp & 128) is a char, !!(exp & 128) is a bool

    Sorry if my code is a bit messy, but I feel this is the fastest way to check for a key press.
  • --> The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones <--
    You do not realy have to limit the FPS for slower input. It won't even really work as handling input 70 times a second is still a lot of rotations :). You can do something like:

    static unsigned int time = time();if ((time() - time) >= repeat_interval) {   // handle the key down event}


    Where time() is the function that gives you the current time and repeat_interval a constant integer which defines the time between resends of the keydown event.

    Crafter 2D: the open source 2D game framework

    ?Github: https://github.com/crafter2d/crafter2d
    Twitter: [twitter]crafter_2d[/twitter]

    Are you doing what Skeleton_V@T is suggesting, and checking to see if the key has just been pressed?

    If you hold down the rotate button, does the block keep rotating? Or do you have to let go of the button and press it again to rotate the block a 2nd time?

    You probably want it to work like that. So when the rotate button key is pressed down, set a flag to mark it as being pressed. Every frame, check if its still down. If it's not, then remove the flag. If it IS down and the flag is not marked, don't do anything....otherwise, set the flag and rotate again.
    thanks for the replies all,

    the code i have will keep rotating if the key is held down

    the question wasnt really about how to handle checking the key, which my code does ok, but more about making it "less responsive" :P

    i implemented something along the lines what is sugested (basically, saying any move takes 1/5th of a second, so i wont accept more input than that)

    give me a few days (not got much time on my hands) to get some collision detection in, and I'll post the complete source, looking for advice and input.

    cheers!
    // Jens

    This topic is closed to new replies.

    Advertisement