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 tetris is reacting to fast to input
This is the CheckInput function that gets called every time in my game loop
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.
Do you use timer?
Secondly, you decide how fast to render/animate the rotation. Check your routines
Secondly, you decide how fast to render/animate the rotation. Check your routines
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 :-)
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 :-)
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
slapped this in my render loop to limit fps:
it still reacts waaaay to fast, so I think I have to go for some kind of combination of 1 and 2.
// 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.
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):
Doing physics according to time elapsed looks like this:
There are other, more complicated options as well, involving not necessarily having a 1:1 ratio of updates and redraws.
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:
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.
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.
* 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:
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
(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.
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:
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.
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.
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.
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!
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!
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement