2014-06-27 18:03:22

Hello all,
So I've been thinking about key modification for a while for Town of Peril, but I haven't found any way to trap all the keys sent to the program without making billions of if  statements which would make the code messy, ridiculously repetitive and probably slow. I know people like CAE Jones have pulled off this kind of thing (take the jeqocon console for example) but I can't find a reliable way. DO you guys have any ideas for this?

A fight we cannot lose.
An enemy we cannot defeat.
A destiny we cannot escape.
Follow me on twitter @guilevi2000

2014-06-28 01:37:25

Here's the class I've been using. It's designed around java, but it only takes an extra function to get it working the same way in bgt.

(The MyKeyC function just generates the default configuration I like using. No one else seems to like it, though, so feel free to ignore that one.)

 // KeyC bridges poll-based and event-based keyboard input,
 // And enables custom keyboard configurations.

 // Constants:
const int START=128, L=1, R=2, U=4, D=8, A=16, B=32, C=64, none=-1;
 // 1:56 PM 4/8/2010: START was originally 0, but since this makes it impossible to determine if start has or hasn't been pressed (and this was causing problems with game controllers), it's been changed to 128.
 const int X=256, Y=512, Z=1024; // Added 10:35 AM 5/24/2010.
const int KeyC_START=128, KeyC_L=1, KeyC_R=2, KeyC_U=4, KeyC_D=8, KeyC_A=16, KeyC_B=32, KeyC_C=64, KeyC_none=-1;
 // 1:56 PM 4/8/2010: START was originally 0, but since this makes it impossible to determine if start has or hasn't been pressed (and this was causing problems with game controllers), it's been changed to 128.
 const int KeyC_X=256, KeyC_Y=512, KeyC_Z=1024; // Added 10:35 AM 5/24/2010.



 KeyC@ MyKeyC() {
 KeyC ret(); //=new KeyC();
 ret.l=KEY_A;
 ret.r = KEY_S;
 ret.u=KEY_W;
 ret.d=KEY_Z;
 ret.a=KEY_F;
 ret.b=KEY_G;
 ret.c=KEY_H;
 ret.start=KEY_SPACE;
 // X, Y and Z added 10:37 AM 5/24/2010:
 ret.x=KEY_R;
 ret.y=KEY_T;
 ret.z=KEY_Y;
 return ret;
}//I use this one a lot...


 class KeyC {
 // Mapping variables to KeyCodes:
 int l;
int r;
int u;
int d;
int a;
int b;
int c;
int start;

 int x; int y; int z; // 10:36 AM 5/24/2010.
 int flags; // Keyup/keydown bits. Note that this prevents start from being caught.
 int lastPressed; //7:13 AM 2/14/2010. To determine if a key being released is the last key that was pressed.

 KeyC() {init();}
 void init() {
 l=KEY_LEFT; r=KEY_RIGHT; d=KEY_DOWN; u=KEY_UP;
 a=KEY_NUMPAD1; b=KEY_NUMPAD2; c=KEY_NUMPAD3; start=KEY_RETURN;
 x=KEY_NUMPAD4; y=KEY_NUMPAD5; z=KEY_NUMPAD6;
 flags=0; // Keyup/keydown bits. Note that this prevents start from being caught.
 lastPressed=-1; //7:13 AM 2/14/2010. To determine if a key being released is the last key that was pressed.


 }// Initialize.

 int getKey(int k) {
 if(k==a) return A;
 else if(k==b) return B;
 else if(k==c) return C;
 else if(k==x) return X;
 else if(k==y) return Y;
 else if(k==z) return Z;
 else if(k==start) return START;
 else if(k==l) return L;
 else if (k==r) return R;
 else if(k==u) return U;
 else if(k==d) return D;
 return none;
}//Key.

bool isKeyPressed(int k) {
 if(k<=0) return false;
 return (flags&k)!=0;
}

 int press(int ke) {
 int k=getKey(ke);

 if(k<=0) return k;
else if( (flags & k)!=0) return none;
 flags|=k;
  lastPressed=k;
 return k;
}//Assuming we don't know what k is from the start.
 int release(int ke) {
 int k=getKey(ke);
 if(k<=0) return k;
 else if( (flags & k)==0) return none;
 // I always get confused on turning off a bit.
 flags = ~ ( (~flags) |k);
 // So that flips flags. We ensure that k is 0, with absolutely no answer for the rest. We flip it back. K turns to 0, everything else is as it was. Is there a quicker way to do that? :P. Maybe &~k?
 return k;
}//Releasing an unknown key.
 // I can't help but think I'm forgetting something. :P.
} //Heh! This used to be a private class...

A save/load function for it might look like this:

bool save_controls(KeyC@ keys, string filename) {
string text="" + keys.l + "\n" + keys.r + "\n" + keys.u + "\n" + keys.d + "\n" + keys.a + "\n" + keys.b + "\n" + keys.c + "\n" + keys.x + "\n" + keys.y + "\n" + keys.z + "\n" + keys.start;
file fout;
 fout.open(filename, "w");
 fout.write(text);
 fout.close();
 return true;
}

KeyC@ load_controls(string filename) {
KeyC ret;
if(!file_exists(filename)) return ret;
file fin;
fin.open(filename, "r");
string text=fin.read(0);
string[] lines=string_split(text, "\n", true);
if(lines.length()<11) return ret; // Otherwise it will crash with a runtime error.
ret.l=string_to_number(lines[0]);
ret.r=string_to_number(lines[1]);
ret.u=string_to_number(lines[2]);
ret.d=string_to_number(lines[3]);
ret.a=string_to_number(lines[4]);
ret.b=string_to_number(lines[5]);
ret.c=string_to_number(lines[6]);
ret.x=string_to_number(lines[7]);
ret.y=string_to_number(lines[8]);
ret.z=string_to_number(lines[9]);
ret.start=string_to_number(lines[10]);
return ret;
}

I haven't tried compiling those two, though. THere might be errors. THe class is fine; I've been using it for like 6 years.

How to use that effectively is a whole other post, though.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2014-06-28 01:47:52

Also, I thinkt he functions you may be seeking are keys_down and keys_pressed. I didn't look at CAE's code fully, so maybe he actually  has those in there. But keys_down and keys_pressed both return arrays of the keys that are currently down or pressed, which allows you to map keys without much trouble.

I like to sleep, Sleep is good,
This is how I do it: Lie on a nice warm cozy bed, and dream dreams about how to rule the world!
Follow @TheGreatAthlon5 on twitter for humorous facts and game updates!
If you like my posts, thumb me up!

2014-06-28 15:17:16

Yes.

This makes more sense in java (key input in swing/awt is handled through a keyAdapter), but:

int[] keys=keys_pressed();
for(uint i=0; i<keys.length(); i++) {
keyPressed(keys[i]);
}
keys=keys_released();
for(uint i=0; i<keys.length(); i++) {
keyReleased(keys[i]);
}


[etc...]


enum screens {intro, main_menu, game, paused, config, game_over, game_complete};

int screen=game; // Intro is better. I'm just ignoring complex side stuff for this example.

KeyC controls;

void keyPressed(int k) {

int c=controls.press(k);
if(c==KeyC_none) return;
switch (c) {
case KeyC_L : move_left(); break;
case KeyC_R : move_right(); break;
// etc
case KeyC_START : screen=config; break;
}
}

int config_step=-1; // A menu is better, but what happens if you change the directional controls?

void keyReleased(int k) {
// I usually do configuration in keyReleased. I forget why but I think it has something to do with feedback.

int c=controls.release(k);

if(screen==config) {

string[] keynames={"left", "right", "up", "down", "A", "B", "C", "X", "Y", "Z", "start"};

switch(config_step) {
case 0 : controls.left=k; break;
case 1 : controls.r=k; break;
case 2 : controls.u=k; break;
case 3 : controls.d=k; break;
case 4 : controls.a=k; break;
case 5 : controls.b=k; break;
case 6 : controls.c=k; break;
case 7 : controls.x=k; break;
case 8 : controls.y=k; break;
case 9 : controls.z=k; break;
case 10 : controls.start=k; break;
case 11 : {config_step=-1; screen=game; return;}
}

config_step++;
if((config_step>=0)&&(config_step<keynames.length())) {
 show_game_window("Press the key to use for " + keynames[config_step] + ". ");
}
}

Again, I just threw that together right now. It might contain errors. If you're to the point where you need this sort of example, and you're not use to loads of error-fixing, you either will be soon or are a super programmer and companies should be competing to try and hire you.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2014-06-28 16:47:10

Hey.
Turns out I had missunderstood the bgt documentation and mixed two functions together. Using keys_pressed makes a lot more sense actually, although I do want to take a look at that class. Thanks CAE.

A fight we cannot lose.
An enemy we cannot defeat.
A destiny we cannot escape.
Follow me on twitter @guilevi2000

2014-06-28 17:09:33

(Speaking of errors, I just noticed that I left off a closing brace at the end of that last example. sad )

The only thing that really matters for customization is separating the input method from the commands. KeyC takes the key that was pressed, and tells you what command it's mapped to. The same idea would be useful for joysticks, etc.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.