#28709 - identitycrisisuk - Thu Nov 04, 2004 9:48 pm
A bit difficult to express as a title and to search for but I think you will know what I mean if I explain. What I want to do is check when a key has gone down but wasn't down the frame before, so that for example when you hold down a button to jump you don't just bounce every time you hit the floor or shoot on every frame, each individual action has to be a separate keypress.
I'm thinking what I'd have to do is take a copy of the control register each frame through some KeyUpdate function and then have another Macro like the keyDown one (keyPress maybe) that would somehow compare the two registers and only return true when the required key is pressed in the current register but not in the last copy of it. I'm thinking that's not too hard but I just wanted to know if that's the best way and whether anyone's done it before (well obviously but who and how ;) because I'm feeling a bit slow today (yeah, just today).
#28712 - Touchstone - Thu Nov 04, 2004 10:32 pm
Yes, you'd want to save a copy of the previous key register and compare the current with the previous to see if the button got pressed this frame or if it was being kept down from previous frame.
As for making your character jump only the first time the button is pressed you can set a flag in your character data that say the character should not jump again until the flag have been cleared and the button pressed again, and then have your input handler report to the character that the button was released the frame it was released.
You might want to allow your character to jump when character is touching ground and jump button is down and the jump button have been released since last time the character jumped. That way the player can press jump, release and press again and the character will jump as soon as it hits the ground. Very enjoyable to play.
_________________
You can't beat our meat
#28717 - identitycrisisuk - Thu Nov 04, 2004 11:59 pm
Hmm, interesting idea on the jumping thing but I can't think of many games that do it that way. Mario doesn't so I probably won't ;)
So if I have some variable:
u16 lastKeys;
that is made to equal the key register at the end of each frame, then my keyPress macro would be:
#define keyPress(k) ((~KEYS & k) && (lastKeys & k))
I think... have to test it out.
#28753 - expos1994 - Fri Nov 05, 2004 3:50 pm
Hey, I have a method of detecting button presses that works like a charm. For my purposes anyways.
Here's an excerpt from the GetInput() function that controls it:
Code: |
if(!(*KEYS & KEY_A))
{
if (current_keys[0] == PRESSED)
changed_keys[0] = NONE;
else
{
changed_keys[0] = PRESSED;
current_keys[0] = PRESSED;
}
}
else //Not pressed
{
if (current_keys[0] == PRESSED)
{
changed_keys[0] = UNPRESSED;
current_keys[0] = UNPRESSED;
}
else
changed_keys[0] = NONE;
}
if(!(*KEYS & KEY_B))
{
if (current_keys[1] == PRESSED)
changed_keys[1] = NONE;
else
{
changed_keys[1] = PRESSED;
current_keys[1] = PRESSED;
}
}
else //Not pressed
{
if (current_keys[1] == PRESSED)
{
changed_keys[1] = UNPRESSED;
current_keys[1] = UNPRESSED;
}
else
changed_keys[1] = NONE;
}
|
This goes through all of the buttons, it's repetitive so I only show button A and button B. Obviously this could all go into a compact For ... Loop, but I have them all typed out.
Now what this does is detect changes to the buttons. So if you press "A", changed_keys[0] will say PRESSED for one frame. On the next frame if will say NONE if the button is still pressed (because there was no change). If you let up on the A button, changed_keys[0] will read UNPRESSED.
So you just check for button PRESSES and UNPRESSES. You can use your imagination to write simple code to pick up repeats. Like say if you don't UNPRESS the A button for 15 frames, you manually set changed_keys[0] to PRESSED again. So it repeats - when you want it to. This prevents mario from jumping like a runaway jackhammer.
The point is, because the GBA will read the Keys register 60 times per second you only want to detect when the button is PRESSED or RELEASED. Everything in between should register as NONE (no change).
In case you do want to know exactly what the buttons look like, you have the current_keys[] array that holds that info, but I don't ever use it.
I hope that helps. It really is a good system. I just include input.h into my games and I'm good to go with detecting button PRESSES and RELEASES. If you need me to clarify something further, just let me know.
#28771 - identitycrisisuk - Fri Nov 05, 2004 8:11 pm
That's.... complicated. I can see what you're doing but the way I described did work. I thought it was quite nice as most of it is done in .h files. I put that new macro alongside my keyDown macro (#define keyDown(k) (~KEYS &k)) and put the lastKeys variable in the .h file too (initialised to 0xFFFF). Then all I need to do is lastKeys = KEYS; at the end of the GetInput function. Then I can say keyPress(KEY_A) for a jump and keyDown(KEY_RIGHT) for when I want to walk right continuously.
#28775 - expos1994 - Fri Nov 05, 2004 8:54 pm
Hmm. Well I can't really tell what you mean by keyDown(KEY_RIGHT) and keyPress(KEY_A). I don't understand how you would implement that.
I don't find my way to be complicated at all. It detects if the button has either been pressed or released. That's all it does.
Here's some examples:
Code: |
if (changed_keys[BUTTON_A] == PRESSED)
mario.action = JUMP;
|
This way mario would not JUMP again until you physically press the A button again (In a lot of cases this is what you want).
Code: |
if (changed_keys[BUTTON_A] == PRESSED)
car.action = SPEED_UP;
if (changed_keys[BUTTON_A] == UNPRESSED)
car.action = SLOW_DOWN;
|
If you were to press and release 'A' several times in this case, the game would behave like this: SPEED_UP,SLOW_DOWN,SPEED_UP,SLOW_DOWN,SPEED_UP,etc.
This is what you would want a gas pedal to do. In this case, "A" is the car's gas pedal.
Code: |
if (changed_keys[BUTTON_START] == PRESSED)
game.mode = START_GAME;
|
For my money, it doesn't get any less complicated than that.
But I guess I just don't quite get what you are doing. It sounds interesting, but what is the benefit of having keyDown() and keyPress().
How can you really judge a key being down or just being pressed, aren't those the same things? In both cases, the state of the key register will change 60 times per second.
Quote: |
... and keyDown(KEY_RIGHT) for when I want to walk right continuously.
|
how long is continuosly? Does the man just walk forever. With my system I would probably code a continous walk like this:
Code: |
if (changed_keys[BUTTON_RIGHT] == PRESSED)
mario.action = WALKING;
if ((mario.action == WALKING) && (changed_keys[BUTTON_RIGHT] == UNPRESSED))
mario.action = IDLE;
|
the state of your game and its objects can change 60 times a second. That is why I believe it is only necessary to capture button presses and button releases.
I am not trying to trash your method of doing things. Actually I am interested in it. Maybe you could explain it a little more. I'm pretty fuzzy on how you would implement the keyPress() and keyDown() macros.
#28777 - identitycrisisuk - Fri Nov 05, 2004 9:40 pm
Maybe keyDown and keyPress aren't the best names to be easily distinguishable, they do kinda sound like the same thing. keyDown is fairly simple, it comes in most tutorials as part of the gba.h or gba_keys.h depending on how you organise things.
So when you have keyDown(KEY_RIGHT) it will tell you whether the right key is currently pressed (on this frame). So if you have keyDown(KEY_RIGHT) on every frame, followed by pos.x++ or something, the position will be increased on every frame that the key is held down, whether it has just gone down or was down the previous frame.
To make keyPress work you need to store the state of the key register on one frame after you have done all the input checking you want. Then on the next frame KEYS will hold what keys are down this frame and lastKeys hold what keys were down last time. So expanding keyPress(KEY_A) you get (~KEYS & KEY_A) && (lastKeys & KEY_A) which will return true when KEY_A's bit is 0 this frame but was 1 in the last frame. So you can call keyPress(KEY_A) every frame, followed by vel.y-=10 knowing that the velocity won't increase by 10 every frame that the button is down, just the first time it goes down (and also check for the thing being on the ground, unless you have an air double jump or something). That maybe still doesn't make sense, I'd make a rubbish teacher ;)
Thinking about it, maybe I didn't mean to say your way was complicated, it just takes more code to update the situation each frame, even if you did put it in a loop. Also in your walking example you have to explicitly tell mario to stop walking, in mine he would just stop moving because there is currently no input and the code would not reach the statement that increases his position.
#28782 - expos1994 - Fri Nov 05, 2004 11:11 pm
I don't know if you have implemented your solution yet, but here's some things to think about:
If you have:
Code: |
if (keyDown(KEY_RIGHT))
mario.x++;
|
Mario's x position will be 60 after 1 sec., 120 after 2 sec., 180 after three sec. , and off the screen after 4 seconds.
The way I animate characters is by changing their states. So when the button is pressed, Mario enters the WALK state. There is code that handles the x position and also the animation based on his state.
When the button is released, his state becomes IDLE. Which handles any idle animations I may have.
It seems like really the only difference is that your definition of holding the key down is if the button is pressed, and my way defines it as if the button is pressed it is down until it is released.
The benefit I get from my method, (and I have used your method), is that I don't do things based on the state of the buttons. I do things based on the state of my characters (and objects). I detect key presses and releases and use those to set the states of the various objects.
I don't think you will have a problem with your method, it should work fine. I think the real difference between your way and mine is that I do things based on presses AND releases. And you do things solely based on presses. When I made my input handler, I wanted it to detect releases. And now I don't even think about it, I just link in my input handler and off I go.
#28791 - identitycrisisuk - Sat Nov 06, 2004 2:13 am
The mario.x++ thing was just a rough example, not exactly what I've done but I'm not quite sure what you're getting at with your position examples. Surely travelling a screens width in a scrolling game in about 4 seconds isn't ridiculously fast? I'm having a little trouble getting a good idea of the relative speeds on the gameboy at the moment though, I'm waiting for a flash cart and then I should get a more clear idea about how fast things move as the performance of emulators on my computer is atrocious.
I do have some kind of state setting kind of bits to my character, flags for stuff like moving, crouching, being on ground, direction facing etc. but I do still do some stuff where I get the keypresses, not a particularly good habit I suppose. It may get pulled back if I do more stuff that will affect the state from outside of the controls (stuff like being hit, which would take control away for a time).
It also may just be my way of thinking about things that makes me not really consider using the release of buttons for much. For example, when you say that you would detect when the accelerator was released to slow down a car, I'd think of it more like friction is always acting on a car - so when there is no longer a positive force acting on it, it will slow down of it's own accord. Benefit/Drawback of a mind that works in Physics :)
#28795 - expos1994 - Sat Nov 06, 2004 5:42 am
Quote: |
Benefit/Drawback of a mind that works in Physics :) |
Well I deal with physics enough in my daily life. When I'm making a game, I pay no mind to the rules of physics. In my games, I make the rules. And my rules say when you let up on the A button, the car slows down!
But I do get what you're saying though. :)[/quote]
#28796 - identitycrisisuk - Sat Nov 06, 2004 11:52 am
expos1994 wrote: |
Well I deal with physics enough in my daily life. When I'm making a game, I pay no mind to the rules of physics. In my games, I make the rules. And my rules say when you let up on the A button, the car slows down! |
Good Answer :)
#28885 - Cearn - Mon Nov 08, 2004 2:10 pm
Quote: |
A bit difficult to express as a title and to search for but I think you will know what I mean if I explain. What I want to do is check when a key has gone down but wasn't down the frame before ... |
There's an old thread about this and other button issues over here. Might be worth a look.