我正在用C做一个小游戏。我试着用函数指针以面向对象的方式编程。
这次我真的很想继续前进,不要把东西做得太普通,我经常迷失在这件事上。使用普通的C语言帮助我更快更好地编程。
目前,我使用以下方法描述“游戏状态”:
/* macros */
#define SETUP_ROUTINE(component) component##_##setup_routine
#define DRAW_ROUTINE(component) component##_##draw_routine
#define EVENT_ROUTINE(component) component##_##event_routine
#define UPDATE_ROUTINE(component) component##_##update_routine
#define TEARDOWN_ROUTINE(component) component##_##teardown_routine
#define SETUP_ROUTINE_SIGNATURE void
#define DRAW_ROUTINE_SIGNATURE void
#define EVENT_ROUTINE_SIGNATURE SDL_Event evt, int * quit
#define UPDATE_ROUTINE_SIGNATURE double t, float dt
#define TEARDOWN_ROUTINE_SIGNATURE void
/* data */
typedef enum GameStateType {
GAME_STATE_MENU,
GAME_STATE_LEVELSELECT,
...
} GameStateType;
typedef struct GameState {
GameStateType state;
GameStateType nextState;
GameStateType prevState;
void (*setup_routine)(SETUP_ROUTINE_SIGNATURE);
void (*draw_routine)(DRAW_ROUTINE_SIGNATURE);
void (*event_routine)(EVENT_ROUTINE_SIGNATURE);
void (*update_routine)(UPDATE_ROUTINE_SIGNATURE);
void (*teardown_routine)(TEARDOWN_ROUTINE_SIGNATURE);
} GameState;
虽然你可能喜欢也可能不喜欢这种风格,但我已经开始喜欢它了,到目前为止,它对我这个小型(私人)项目很有帮助。
例如,我有一个“过渡”游戏状态,它只是从一个游戏状态过渡到另一个。
然而,当我将不同的游戏状态链接在一起时,我会得到一些丑陋的东西,比如:
extern GameState GAME; /* The 'singleton' "game" */
extern void menu_setup_routine(SETUP_ROUTINE_SIGNATURE);
extern void menu_draw_routine(DRAW_ROUTINE_SIGNATURE);
extern void menu_event_routine(EVENT_ROUTINE_SIGNATURE);
extern void menu_update_routine(UPDATE_ROUTINE_SIGNATURE);
extern void menu_teardown_routine(TEARDOWN_ROUTINE_SIGNATURE);
extern void debug_setup_routine(SETUP_ROUTINE_SIGNATURE);
extern void debug_draw_routine(DRAW_ROUTINE_SIGNATURE);
extern void debug_event_routine(EVENT_ROUTINE_SIGNATURE);
extern void debug_update_routine(UPDATE_ROUTINE_SIGNATURE);
extern void debug_teardown_routine(TEARDOWN_ROUTINE_SIGNATURE);
另外,对于每个游戏状态,我都有这样的东西:
菜单c
struct MenuModel menu_model; /* The singleton 'menu' model */
游戏c
struct GameModel game_model; /* The singleton 'game' model */
…它们是在整个程序执行过程中留在堆中的全局数据块。当然,这些字段通常由指向动态内存的指针组成,动态内存和动态内存的内容随着游戏状态的变化而变化。
一开始我觉得这很疯狂,我开始喜欢它。但是,当另一个.o链接时,如果它也有这样一个“menu_model”符号,则可能会导致命名空间冲突。
第一个问题:这是不是疯了,有没有更好的方法来做这样的事情?人们通常做些什么来避免这些可能的符号名冲突?
第二个问题是我必须重新发布不同的…\u setup\u routine/。draw\u routine/。。在一个包含以下类型函数的源文件/对象文件中使用“extern..”的函数:
void (*get_setup_routine(GameStateType state))(SETUP_ROUTINE_SIGNATURE) {
switch(state) {
case GAME_STATE_MENU:
return SETUP_ROUTINE(menu);
break;
case GAME_STATE_LEVELSELECT:
return SETUP_ROUTINE(level_select);
break;
default: /* ... */ break;
}
}
因为否则编译时它不知道符号“menu\u setup\u routine”。
无论如何,任何建议都是受欢迎的,我对C有点陌生,虽然我真的很喜欢在其中编程,但我想知道在这种情况下我是否正确使用了它。