SDL_console 2.0 l33t users...
Am wondering if you could give me some tips. http://sdlconsole.sourceforge.net/
Am trying to create a function bind() like in Quake/Half-Life.
The syntax is:
bind
eg. bind w +forward
if (argv[2] == "+forward")
player1.controls.forward = SDLK_w;
Currently I have to write all this out. Is there a way where you can join "SDLK_" and and convert to a C constant word (as SDLK_w is a constant right?).
Same goes for taking argv[2] and joining onto player1.controls.? Is this possible?
Regards
Kev
Make two function - one to map legal keys to those SDL constants and one that returns the propper player.control.key...
rember that getAction must return an reference ( & ) for this to work..
oh and btw are you shure that you understand the use of argv[x]? it typicaly contains the commandline arguments.. from "int main ( int argc, char* argv[] )"
/Please excuse my bad spelling - My native language is binary not english
|Visit me
\Take my advice - I don''''t use it...
pesudo code: (player.controll.key-type)& getAction(std::string in) { switch ( in ) { case "+forward" : return player1.controls.forward; ... Default: return NULL; } } (SDLK_ type) getKey (std::string in) { switch ( in ) { case "w" : return SDLK_w; deafult : return SDLK_error; } } a = getAction ( argv[2] ); if ( a != NULL ) { k = getKey( argv[1] ); if ( k != SDLK_error ) a = k; }
rember that getAction must return an reference ( & ) for this to work..
oh and btw are you shure that you understand the use of argv[x]? it typicaly contains the commandline arguments.. from "int main ( int argc, char* argv[] )"
/Please excuse my bad spelling - My native language is binary not english
|Visit me
\Take my advice - I don''''t use it...
/Please excuse my bad spelling - My native language is binary not english|Visit meTake my advice - I don''t use it...
quote:
oh and btw are you sure that you understand the use of argv[x]? it typicaly contains the commandline arguments.. from "int main ( int argc, char* argv[] )"
Are you sure you understand the use of argv? It''s just a variable name. If you named it ''parametersIGetFromTheCommandLine'' it would still contain the commandline arguments (and only inside the scope of main, unless you pass it on).
If you want to call arguments you get from someplace else ''argv'' you''re free to do so.
How do I set my laser printer on stun?
quote:
Original post by Wildfirequote:
oh and btw are you sure that you understand the use of argv[x]? it typicaly contains the commandline arguments.. from "int main ( int argc, char* argv[] )"
Are you sure you understand the use of argv? It''s just a variable name. If you named it ''parametersIGetFromTheCommandLine'' it would still contain the commandline arguments (and only inside the scope of main, unless you pass it on).
If you want to call arguments you get from someplace else ''argv'' you''re free to do so.
oh for the love of god! yes I know its just a name - wich is why I included the ''main'' line. I is how ever widly acceptet that one uses argv for commandline parameteres ( never know any book or programmer who didn''t ) - I was simply warning him of variable name collision / wondering if he wanted to make a program called bind.exe...
ps. take you rude comments somewhere else.. I wasn''t mocking - just asking ... ( the bold tag is really anoying isn''t it.. )
/Please excuse my bad spelling - My native language is binary not english|Visit meTake my advice - I don''t use it...
I was not trying to be rude. I used the bold tag merely to accentuate the words, something you can do in natural speech, but is difficult to do in written language unless you use something like bold.
I know that ''argv'' is usually used for command line parameters. If he doesn''t use those, he can use argv for anything else. And if he did use argv for parameters, and inside the same scope, for another variable, any compiler would surely tell him about it.
I can''t recall trying to mock you either. And no, the bold tag is not anoying.
I know that ''argv'' is usually used for command line parameters. If he doesn''t use those, he can use argv for anything else. And if he did use argv for parameters, and inside the same scope, for another variable, any compiler would surely tell him about it.
I can''t recall trying to mock you either. And no, the bold tag is not anoying.
How do I set my laser printer on stun?
Ok. Here''s what I got from James Abbatiello:
Hello. Your question was forwarded to me by Garrett Banuk.
I don''t think you can directly do what you''ve outlined above.
The problem is that ''SDLK_w'' only exists at compile time, and
the "w" you get from the user doesn''t happen until run time.
I think the solution you need here is some lookup tables.
This will be a more general solution (since you''ll be able to
support keys other than single letters). I assume you have a
struct that looks something like this:
typedef struct player_controls_s
{
SDLKey forward;
SDLKey back;
/* ... */
} player_controls_t;
Then you might be able to use some code that looks somewhat like
this (warning: untested code follows):
#include <stddef.h> /* for offsetof() */
#include <string.h> /* for strcmp() */
#include "SDL.h" /* for SDLKey */
#define PLAYER_CONTROLS_OFFSET(x) offsetof(player_controls_t, x)
static const struct {
const char *str;
SDLKey val;
} bind_key_lookup[] = {
{ "a", SDLK_a },
{ "b", SDLK_b },
/* ... */
{ " ", SDLK_SPACE },
/* ... */
};
static const struct {
const char *str;
size_t offset;
} bind_action_lookup[] = {
{ "+forward", PLAYER_CONTROLS_OFFSET(forward) },
{ "+back", PLAYER_CONTROLS_OFFSET(back) },
/* ... */
};
void do_bind(char *argv[])
{
int i, key = -1, action = -1;
for (i = 0;
i < sizeof(bind_key_lookup) / sizeof(bind_key_lookup[0]);
i++)
{
if (strcmp(argv[1], bind_key_lookup.str) == 0)
{
key = i;
break;
}
}
if (key == -1) {
/* error: don''t know what key the user was talking about */
}
for (i = 0;
i < sizeof(bind_action_lookup) / sizeof(bind_action_lookup[0]);
i++)
{
if (strcmp(argv[2], bind_action_lookup.str) == 0)<br> {<br> action = i;<br> break;<br> }<br> }<br> if (action == -1) {<br> /* error: don''t know what action the user was talking about */<br> }<br> <br> *(SDLKey *)((char *)&player1.controls +<br>bind_action_lookup[action].offset) =<br> bind_key_lookup[key].val;<br>}<br><br><br>Things of note:<br>- The syntax I used might be confusing. If you have trouble reading<br>it,<br> ask me questions.<br> <br>- The lookup tables can be constructed by hand, but<br> you could also write a small program to generate them<br> (or, at least, the quite repetative parts). This is left as<br> and exercise for the reader. <img src="wink.gif" width=15 height=15 align=middle><br><br>- If your compiler doesn''t have the offsetof() macro, you''ll need<br> to include your own implementation. Hopefully this won''t be an<br> issue though because:<br> <br>- You might have noticed the whole uglyness resulting from the use<br> of offsetof (especially the mess of casts in the last line). I<br> did this to try to keep your data structures the same. But if<br> you are willing to change things a bit, there''s a better<br> solution. Change your struct definition:<br><br>typedef enum player_action_e<br>{<br> PC_NONE, /* optional */<br> PC_FORWARD,<br> PC_BACK,<br> /* … */<br> PC_NB /* total number of actions */<br>} player_action_t;<br><br>typedef struct player_controls_s<br>{<br> SDLKey actions[PC_NB];<br> /* any other members you like */<br>} player_controls_t;<br><br><br>Now instead of<br> player1.controls.forward = SDLK_w;<br>you can use<br> player1.controls.actions[PC_FORWARD] = SDLK_w;<br><br>IOW, you can access the members by index instead of by<br>a compile-time-only name.<br><br>And the code above gets a bit simpler. Remove the<br>#include <stddef.h> and #define PLAYER_CONTROLS_OFFSET lines<br>as we don''t need them anymore. Change the second struct so<br>that it looks like:<br><br>static const struct {<br> const char *str;<br> player_action_t val;<br>} bind_action_lookup[] = {<br> { "+forward", PC_FORWARD },<br> { "+back", PC_BACK },<br> /* … */<br>};<br><br>And then change the last line so that it reads<br> player1.controls.actions[bind_action_lookup[action].val] = <br> bind_key_lookup[key].val;<br><br>- Finally, if you don''t have any other members to add to<br> player_controls_t, you can just ditch that struct entirely<br> and put the actions array directly in the player struct. You<br> could even rename it "controls" if you wanted so that where<br> before you would have written<br>player1.controls.forward = SDLK_w;<br> you can now write<br>player1.controls[PC_FORWARD] = SDLK_w;<br><br> Its all up to you.<br><br>HTH. Let me know how it goes<br><br>– <br>James Abbatiello<br> </i>
Hello. Your question was forwarded to me by Garrett Banuk.
I don''t think you can directly do what you''ve outlined above.
The problem is that ''SDLK_w'' only exists at compile time, and
the "w" you get from the user doesn''t happen until run time.
I think the solution you need here is some lookup tables.
This will be a more general solution (since you''ll be able to
support keys other than single letters). I assume you have a
struct that looks something like this:
typedef struct player_controls_s
{
SDLKey forward;
SDLKey back;
/* ... */
} player_controls_t;
Then you might be able to use some code that looks somewhat like
this (warning: untested code follows):
#include <stddef.h> /* for offsetof() */
#include <string.h> /* for strcmp() */
#include "SDL.h" /* for SDLKey */
#define PLAYER_CONTROLS_OFFSET(x) offsetof(player_controls_t, x)
static const struct {
const char *str;
SDLKey val;
} bind_key_lookup[] = {
{ "a", SDLK_a },
{ "b", SDLK_b },
/* ... */
{ " ", SDLK_SPACE },
/* ... */
};
static const struct {
const char *str;
size_t offset;
} bind_action_lookup[] = {
{ "+forward", PLAYER_CONTROLS_OFFSET(forward) },
{ "+back", PLAYER_CONTROLS_OFFSET(back) },
/* ... */
};
void do_bind(char *argv[])
{
int i, key = -1, action = -1;
for (i = 0;
i < sizeof(bind_key_lookup) / sizeof(bind_key_lookup[0]);
i++)
{
if (strcmp(argv[1], bind_key_lookup.str) == 0)
{
key = i;
break;
}
}
if (key == -1) {
/* error: don''t know what key the user was talking about */
}
for (i = 0;
i < sizeof(bind_action_lookup) / sizeof(bind_action_lookup[0]);
i++)
{
if (strcmp(argv[2], bind_action_lookup.str) == 0)<br> {<br> action = i;<br> break;<br> }<br> }<br> if (action == -1) {<br> /* error: don''t know what action the user was talking about */<br> }<br> <br> *(SDLKey *)((char *)&player1.controls +<br>bind_action_lookup[action].offset) =<br> bind_key_lookup[key].val;<br>}<br><br><br>Things of note:<br>- The syntax I used might be confusing. If you have trouble reading<br>it,<br> ask me questions.<br> <br>- The lookup tables can be constructed by hand, but<br> you could also write a small program to generate them<br> (or, at least, the quite repetative parts). This is left as<br> and exercise for the reader. <img src="wink.gif" width=15 height=15 align=middle><br><br>- If your compiler doesn''t have the offsetof() macro, you''ll need<br> to include your own implementation. Hopefully this won''t be an<br> issue though because:<br> <br>- You might have noticed the whole uglyness resulting from the use<br> of offsetof (especially the mess of casts in the last line). I<br> did this to try to keep your data structures the same. But if<br> you are willing to change things a bit, there''s a better<br> solution. Change your struct definition:<br><br>typedef enum player_action_e<br>{<br> PC_NONE, /* optional */<br> PC_FORWARD,<br> PC_BACK,<br> /* … */<br> PC_NB /* total number of actions */<br>} player_action_t;<br><br>typedef struct player_controls_s<br>{<br> SDLKey actions[PC_NB];<br> /* any other members you like */<br>} player_controls_t;<br><br><br>Now instead of<br> player1.controls.forward = SDLK_w;<br>you can use<br> player1.controls.actions[PC_FORWARD] = SDLK_w;<br><br>IOW, you can access the members by index instead of by<br>a compile-time-only name.<br><br>And the code above gets a bit simpler. Remove the<br>#include <stddef.h> and #define PLAYER_CONTROLS_OFFSET lines<br>as we don''t need them anymore. Change the second struct so<br>that it looks like:<br><br>static const struct {<br> const char *str;<br> player_action_t val;<br>} bind_action_lookup[] = {<br> { "+forward", PC_FORWARD },<br> { "+back", PC_BACK },<br> /* … */<br>};<br><br>And then change the last line so that it reads<br> player1.controls.actions[bind_action_lookup[action].val] = <br> bind_key_lookup[key].val;<br><br>- Finally, if you don''t have any other members to add to<br> player_controls_t, you can just ditch that struct entirely<br> and put the actions array directly in the player struct. You<br> could even rename it "controls" if you wanted so that where<br> before you would have written<br>player1.controls.forward = SDLK_w;<br> you can now write<br>player1.controls[PC_FORWARD] = SDLK_w;<br><br> Its all up to you.<br><br>HTH. Let me know how it goes<br><br>– <br>James Abbatiello<br> </i>
Using function pointers would eliminate the need for offsets, but you would still need a lookup table of some kind that stores the function addresses. The lookup table would probably hold two variables per entry - the function name the commandline would look for, and then the address of the function. You would need to 'register' every function you would plan on being bindable to a key.
Here is what I use in my program (Sorry if there are any bugs, I just finished writing it today):
DInputI is my interface to DirectInput. I'm sure there are similar functions in SDL ( Refresh() updates the keystate information and Keydown() returns true/false depending on if the key is down or not)
Oh, and the RegisterFunction() method only works with global no-argument functions that return nothing. Here is an example of how to use the class:
// Two example global functions to bind
void ZoomOut() { zPos+=float(50.0f*frameTime); }
void ZoomIn() { zPos-=float(50.0f*frameTime); }
// Any Time
Input->RegisterFunction("ZoomIn", ZoomIn);
Input->RegisterFunction("ZoomOut", ZoomOut);
Input->BindKey(DIK_UP, "ZoomIn");
Input->BindKey(DIK_DOWN, "ZoomOut");
Oh, and DIK_UP / DOWN are DirectInput constants for keys, there should be similar constants available.
//Inside of your game loop - before everything is drawn
Input->Refresh()
[edited by - Hawkeye3 on July 11, 2003 4:30:31 PM]
Here is what I use in my program (Sorry if there are any bugs, I just finished writing it today):
// Input.h#define MAX_FUNCTIONS 100typedef void (*PFN)();struct fnEntry{ char name[32]; PFN fn;};class CInput {public: CInput(); ~CInput(); bool RegisterFunction(LPCSTR name, PFN fn); bool BindKey(int key, LPCSTR fnName); bool OnKey(int key); void Process();private: int nFunctions; int FindFunctionIndex(LPCSTR name); fnEntry fnTable[MAX_FUNCTIONS]; int keyTable[256];};// Input.cppCInput::CInput(){ memset(fnTable, 0, sizeof(fnTable)); memset(keyTable, 0, sizeof(keyTable)); nFunctions = 0;}CInput::~CInput() { }bool CInput::RegisterFunction(LPCSTR name, PFN fn){ // Keep from registering duplicates if(FindFunctionIndex(name)>-1) return false; strncpy(fnTable[nFunctions].name, name, 31); fnTable[nFunctions].fn = fn; nFunctions++; return true;}//////////////////////////////////////////////////////////////////////////// Attempts to find the specified function name in the function table// Returns the index on success, -1 on failureint CInput::FindFunctionIndex(LPCSTR name){ if(nFunctions == 0) return -1; for( int i=0; i<nFunctions; i++) if(stricmp(fnTable[i].name, name)==0) return i; return -1;}bool CInput::BindKey(int key, LPCSTR fnName){ // Make sure the function exists int fnIndex = FindFunctionIndex(fnName); if(fnIndex == -1) return false; keyTable[key] = fnIndex; return true;}void CInput::OnKey(int key){ if(fnTable[keyTable[key]].fn) (fnTable[keyTable[key]].fn)();}void CInput::Process(){ DInputI.Refresh(); for(int i=0; i < 256; i++) { if(DInputI.Keydown(i)) OnKey(i); }}
DInputI is my interface to DirectInput. I'm sure there are similar functions in SDL ( Refresh() updates the keystate information and Keydown() returns true/false depending on if the key is down or not)
Oh, and the RegisterFunction() method only works with global no-argument functions that return nothing. Here is an example of how to use the class:
// Two example global functions to bind
void ZoomOut() { zPos+=float(50.0f*frameTime); }
void ZoomIn() { zPos-=float(50.0f*frameTime); }
// Any Time
Input->RegisterFunction("ZoomIn", ZoomIn);
Input->RegisterFunction("ZoomOut", ZoomOut);
Input->BindKey(DIK_UP, "ZoomIn");
Input->BindKey(DIK_DOWN, "ZoomOut");
Oh, and DIK_UP / DOWN are DirectInput constants for keys, there should be similar constants available.
//Inside of your game loop - before everything is drawn
Input->Refresh()
[edited by - Hawkeye3 on July 11, 2003 4:30:31 PM]
Also, I thought about server/client/multiplayer variables like the ones in Half-Life/Quake. There could be hundreds of variables.
eg.
Player''s Actions:
forward
backward
Server Variables:
sv_timeout
sv_hostname
sv_gravity
Client Variables:
cl_download
cl_model
cl_name
Multiplayer Variables:
mp_timelimit
mp_roundtime
mp_fraglimit
Have you gone this far implementing these for your game? How would you go about it?
Also, Quake/Half-Life use of + and - proceeding actions eg. bind w +forward means the action is activated on press of the key w binded to it. And on depress of key it goes -forward meaning deactivated. However if typed attack in console it would attack once. If typed +attack it would attack forever until -attack was typed. How would you go about implementing this?
Regards
Kev
eg.
Player''s Actions:
forward
backward
Server Variables:
sv_timeout
sv_hostname
sv_gravity
Client Variables:
cl_download
cl_model
cl_name
Multiplayer Variables:
mp_timelimit
mp_roundtime
mp_fraglimit
Have you gone this far implementing these for your game? How would you go about it?
Also, Quake/Half-Life use of + and - proceeding actions eg. bind w +forward means the action is activated on press of the key w binded to it. And on depress of key it goes -forward meaning deactivated. However if typed attack in console it would attack once. If typed +attack it would attack forever until -attack was typed. How would you go about implementing this?
Regards
Kev
Why not have a linked list of binded keys. It would have the actual command they do and then the key that command is binded to. You have it so when a user enters a key it goes threw all the norm keys then threw the linked list.
--------------------------Nukemmsn: nukem996@hotmail.comaim: nukem996open source open mind
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement