1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // initialization renderer_t *renderer = create_renderer(); world_t *world = create_world(); enemies_t *enemies = spawn_enemies(); player_t player; input_t input; // main loop while(1) { // handle events here update_and_render(renderer, world, enemies, player, input); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | struct TitleScreenData { //...whatever a title screen would have }; struct GameData { //entities, map, camera, etc. }; enum StateType { STATE_TITLE, STATE_GAME, MAX_STATE }; struct Gamestate { int type; union { TitleScreenData *title; GameData *game; }; }; Gamestate *new_title(/*stuff you need to initialize a title screen*/); //allocates title, etc. Gamestate *new_game(/*stuff you need to initialize a game... for instance, a path to a player save file*/); //allocates game, etc. Gamestate *update_gamestate(Gamestate *g); void render_gamestate(Gamestate *g); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | Gamestate *update_gamestate(Gamestate *g) { switch(g->type) { case STATE_TITLE: { //update the title screen, using the TitleScreenData struct break; } case STATE_GAME: { //update the game, using the GameData struct break; } //note: my strategy is to branch further into specific update_title and update_game // functions; this isn't necessarily fastest as it causes more indirection but it helps // with organization (game functions can be thrown into a separate file, and same with // title functions) default: break; } return g; } |
1 2 3 4 5 6 7 8 9 10 11 | Gamestate *current = NULL, *next = NULL; current = new_title(); //... //at the end of a game loop, maybe somewhere you set next to be the result of new_game() if(next) { free_gamestate(current); current = next; next = NULL; } |
1 2 3 4 5 6 7 8 9 | //in title update function if(play_button_clicked) { next = new_game(); } //at the end of this loop, the current state will be freed and reassigned to next //this will begin updating and rendering using the /GameData/ instead of the //TitleScreenData. This, of course, assumes that new_game() returns a valid Gamestate * //that properly allocates and initializes a GameData struct. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | struct game_state_t { renderer_t renderer; world_t world; enemies_t enemies; player_t player; input_t input; }; void main( void ) { game_state_t state; // Allocate the state the way you want (global, stack, malloc... ). // Initialize where you want (e.g. instead of here, it could be the first time you enter update_and_render). create_renderer( &state.renderer ); create_world( &state.world ); spawn_enemies( &state.enemies ); while ( 1 ) { update_and_render( &state ); } } void update_and_render( game_state_t* state ) { simulate( &state->world ); ... render( &state->renderer ); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | typedef struct { double x; double y; v2 velocity; texture_t image; int w; int h; } player_h; typedef struct { double x; double y; v2 velocity; texture_t image; int w; int h; behavior_t behavior; skill_t skills[5]; // array of skills int skills_count; // how many skills does he have } enemy_t; typedef struct { double x; double y; v2 velocity; texture_t image; int w; int h; } particle_t; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | enum Entity_Type { PLAYER_ENTITY, ENEMY_ENTITY, PARTICLE_ENTITY }; typedef struct { float x; float y; Vector2 velocity; Texture image; int w; int h; int type; union { struct { // Enemy Data: Behavior behavior; Skill skills[5]; int skills_count; }; struct { // Player Data: // Player Data... }; }; } Entity; // You don't necessarily need these: typedef Entity Player; typedef Entity Enemy; typedef Entity Particle; |
1 2 3 | void simulate_gravity(Entity *e) { // Simulate Gravity... } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | typedef struct { double x; double y; v2 velocity; texture_t image; int w; int h; } particle_t; typedef struct { particle_t particle; } player_h; typedef struct { particle_t particle; behavior_t behavior; skill_t skills[5]; // array of skills int skills_count; // how many skills does he have } enemy_t; |
nyeecola
Ok, thanks for the help, you guys are awesome. Can I ask one more question?
I have 3 structures like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 typedef struct { double x; double y; v2 velocity; texture_t image; int w; int h; } player_h; typedef struct { double x; double y; v2 velocity; texture_t image; int w; int h; behavior_t behavior; skill_t skills[5]; // array of skills int skills_count; // how many skills does he have } enemy_t; typedef struct { double x; double y; v2 velocity; texture_t image; int w; int h; } particle_t;
So, it seems like there's a lot of duplicated data above. How would you guys go about "fixing" that? Or should I just leave it as is and not care about this?
And, on the enemy_t structure, is that a dumb way of handling enemies with different skills/skill counts?
1 2 3 4 5 6 | struct Position { double x; double y; v2 velocity; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | typedef struct { Position p; texture_t image; int w; int h; } player_h; typedef struct { Position p; texture_t image; int w; int h; behavior_t behavior; skill_t skills[5]; // array of skills int skills_count; // how many skills does he have } enemy_t; typedef struct { Position p;; texture_t image; int w; int h; } particle_t; |
1 2 3 4 5 6 | struct Texture { texture_t image; int w; int h; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | typedef struct { Position p; Texture tex; } player_h; typedef struct { Position p; Texture tex; behavior_t behavior; skill_t skills[5]; // array of skills int skills_count; // how many skills does he have } enemy_t; typedef struct { Position p; Texture tex; } particle_t; |