Checking for keypresses

Blitz3D Forums/Blitz3D Beginners Area/Checking for keypresses

goatless(Posted 2003) [#1]
Hi again,

Some more questions about celestial rift. As a quick and dirty way to get into the language and features I've re-structured and tweaked the Celestial Rift sample. Doing so has left me with some questions I hope somebody out there can answer.

In the game update loops I came across the checks for the various keys the user presses to control the craft and game. :-


If KeyDown(KEY_FIRE) Then

	; FIRE
	playerActionFire()
	FlushKeys

End If


If KeyDown(KEY_HYPER)

	; HYPER JUMP
	playerActionHyper()
	FlushKeys

End If


If KeyDown(KEY_CLOCKWISE)

	; CLOCKWISE TURN
	playerActionTurnClock()
	FlushKeys
	
End If

If KeyDown(KEY_ANTICWISE)

	; ANTI-CLOCKWISE TURN
	playerActionTurnAnti()
	FlushKeys
	
End If
	
If KeyDown(KEY_SPEEDUP) Then

	; ACCELERATE
	FlushKeys
	playerActionAccelerate()
	
End If

If KeyDown(KEY_BOOST) Then

	; BOOST
	FlushKeys
	playerActionBoost()
	
End If


Initially I had a very strong urge to turn the whole lot into a select case statement, or at least an if ... then ... elseif ladder, however I'm not certain whether this coding is intentional or not.

If intentional then it would allow the user to press multiple keys per game loop (e.g. fire and accelerate). However if this is the case why is FlushKeys used immediately after each key-press, wouldn't that negate the intention.

If not intentional, then I'll recode it!

I guess I'm asking how blitz interprets multiple key presses (can each and every key pressed be flagged and checked in one game cycle?). Does the flushkeys command really clear the key buffer until the next loop?


semar(Posted 2003) [#2]
I suggest you to try with and without Flushkeys in the above example, so to see the difference. I *think* it was intentional, to prevent multiple key press. I may be wrong, since I don't have blitz here to test.

can each and every key pressed be flagged and checked in one game cycle?

What do you mean for flagged ? You have to use a flag for each key, if this is what you intend.
The keys are not automatically 'flagged'

for example, assuming that the key codes for the arrow keys go from 200 to 203:

pressed$ = ""
for n = 200 to 203
if keydown(n) then
pressed = pressed + n + ","
endif
next

at the end of the above loop, if you have pressed the 200 and 202 keys, the value of the variable 'pressed' would be like
"200,202"

So you can parse it to know which key have been pressed.

Several other methods are also possible.

Sergio.


goatless(Posted 2003) [#3]
semar,

Thanks for the quick response. Yeah, flagged was the wrong word to use!

What I meant was, when I use the KeyDown command I assumed that the key buffer was implemented as a queue.

However when I thought about the way this was coded the more I thought that maybe it was organised in some other way so that in the space of one cycle, lots of keys could be registered as being down and a check against the relevant key (e.g. keydown(KEY_FIRE)) would then return true/false depending.

I guess I'll need to run some test programs to figure it out.

Cheers.


_PJ_(Posted 2003) [#4]
look at KeyHit() too


Myke-P(Posted 2003) [#5]
Hi there Goatless.

As author of Celestial Rift, I should point out that it was my first ever stab at coding a game in Blitz and version 1.35 at that! So, what I mean is that some of the things I did in that code may well not be the best or even the correct way of doing things. :)

The idea of the FlushKeys() after some of the keypresses was so that the bit of code that was called on the keypress wasn't called more than once, i.e.:

Rift: Is the user pressing fire?
Blitz: YES
Rift: Okay, do this. Then forget that the user is pressing that key until I ask you the question again next loop.

In hindsight, it doesn't really work as well as it should. Now I'd go with a flag and counter system, i.e.:

If KeyDown(KEY_FIRE) = True Then
	If Flag_KeyFire = False Then
		;Do player firing logic
		Flag_KeyFire = True
		Counter_KeyFire = 0
	End If
Else
	Flag_KeyFire = False
End If

If Flag_KeyFire = False Then
	Counter_KeyFire = Counter_KeyFire + 1
	If Counter_KeyFire = 60 Then
		Flag_KeyFire = True
	End If
End If


In this new code, if the player holds down FIRE then it will release a bullet every 60 game frames. Alternatively the player may get a higher firing rate by bashing the key repeatedly.

As for the use of If vs Select, in my opinion If is much more flexible for use in more wacky key combo pressing logic.

Feel free to ask for any more clarifications on my younger self's programming style. ;)


Oldefoxx(Posted 2003) [#6]
The various ways in checking for the key state on a keyboard
(KeyHit(), KeyDown(), GetKey(), WaitKey(), and Input), are designed to facilitate a rapid action game sequence where a player may be signalling several different actions more or less simultaneously, but also allow you to use the keyboard in more or less the traditional way.

Most games only allow for certain range of actions controlled by certain keys, so KeyHit() and KeyDown() can be very useful in ignoring all the other keys that are not implemented in that game. KeyHit() tells you if a key has been hit, and how many times it has been hit, since the last time you checked. KeyDown() tells you if that key is currently pressed or not. Neither KeyHit() or KeyDown() serves to remove a key from the keyboard input queue (which is accessed by GetKey(), Waitkey(), and Input), so there is some risk of reading the same key value over again if paired improperly with a different command. Flushkeys clears the keyboard input queue completely, which is effectively the same as:

   Repeat
     key=GetKey()
   Until key=0


However, the advantage of using the GetKey() approach to purging the keyboard input queue is that you can check the keys entered before discarding them altogether. Remember though, duplications are possible when combined with the
use of KeyHit() and KeyDown(). Fact is, and I'm not real sure about the outcome yet, what happens to the count for each key that is returned after a FlushKeys command is executed? I suspect that the count is uneffected, and that only by using KeyHit() for each scan code will the count be read and reset in the same step.

Also keep in mind that no matter how fast you are at a keyboard, a computer is going to be able to execute thousands of instructions between keystrokes. So for game purposes, then use of WaitKey() and Input, which both wait on user input, may not be desireable, because you can be doing a lot of things in your code between those keystrokes if you do not force the PC to wait on a user's input. That is where KeyHit(), KeyDown(), and GetKey() can be more useful.