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 32typedef 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;
|