Add state data buffer to hold generic configs
Add some system that allows us to automatically define and allocate different application states at runtime without having to manually make the entries into our game state structure. It's basically an array of pointers determined by the app states defined in the appstate enum. This is necessary since different modes, (start menu, options, game world) have different data and we'd like to be able to define them uniquely.
This commit is contained in:
parent
15b4ff59f7
commit
aeeef1a60f
116
src/Asteroid.c
116
src/Asteroid.c
@ -191,7 +191,7 @@ INTERNAL b32 checkEdgeProjectionOverlap(v2 *vertexList, i32 listSize,
|
||||
return result;
|
||||
}
|
||||
|
||||
INTERNAL u32 moveEntity(World *world, MemoryArena_ *transientArena,
|
||||
INTERNAL u32 moveEntity(GameWorldState *world, MemoryArena_ *transientArena,
|
||||
Entity *entity, i32 entityIndex, v2 ddP, f32 dt,
|
||||
f32 ddPSpeed)
|
||||
{
|
||||
@ -301,7 +301,8 @@ typedef struct {
|
||||
v2 dP;
|
||||
} AsteroidSpec;
|
||||
|
||||
INTERNAL void addAsteroidWithSpec(World *world, enum AsteroidSize asteroidSize,
|
||||
INTERNAL void addAsteroidWithSpec(GameWorldState *world,
|
||||
enum AsteroidSize asteroidSize,
|
||||
AsteroidSpec *spec)
|
||||
{
|
||||
world->asteroidCounter++;
|
||||
@ -405,15 +406,15 @@ INTERNAL void addAsteroidWithSpec(World *world, enum AsteroidSize asteroidSize,
|
||||
}
|
||||
|
||||
asteroid->vertexPoints = vertexCache[cacheIndex];
|
||||
asteroid->color = V4(0.0f, 0.5f, 0.5f, 1.0f);
|
||||
asteroid->color = V4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
INTERNAL void addAsteroid(World *world, enum AsteroidSize asteroidSize)
|
||||
INTERNAL void addAsteroid(GameWorldState *world, enum AsteroidSize asteroidSize)
|
||||
{
|
||||
addAsteroidWithSpec(world, asteroidSize, NULL);
|
||||
}
|
||||
|
||||
INTERNAL void addBullet(World *world, Entity *shooter)
|
||||
INTERNAL void addBullet(GameWorldState *world, Entity *shooter)
|
||||
{
|
||||
Entity *bullet = &world->entityList[world->entityIndex++];
|
||||
bullet->id = world->entityIdCounter++;
|
||||
@ -442,7 +443,7 @@ INTERNAL void addBullet(World *world, Entity *shooter)
|
||||
bullet->color = V4(1.0f, 1.0f, 0, 1.0f);
|
||||
}
|
||||
|
||||
INTERNAL void setCollisionRule(World *world, enum EntityType a,
|
||||
INTERNAL void setCollisionRule(GameWorldState *world, enum EntityType a,
|
||||
enum EntityType b, b32 rule)
|
||||
{
|
||||
ASSERT(a <= entitytype_count);
|
||||
@ -451,7 +452,8 @@ INTERNAL void setCollisionRule(World *world, enum EntityType a,
|
||||
world->collisionTable[b][a] = rule;
|
||||
}
|
||||
|
||||
INTERNAL AudioRenderer *getFreeAudioRenderer(World *world, AudioVorbis *vorbis,
|
||||
INTERNAL AudioRenderer *getFreeAudioRenderer(GameWorldState *world,
|
||||
AudioVorbis *vorbis,
|
||||
i32 maxSimultaneousPlayers)
|
||||
{
|
||||
i32 freeIndex = -1;
|
||||
@ -480,7 +482,7 @@ INTERNAL AudioRenderer *getFreeAudioRenderer(World *world, AudioVorbis *vorbis,
|
||||
return result;
|
||||
}
|
||||
|
||||
INTERNAL void addPlayer(World *world)
|
||||
INTERNAL void addPlayer(GameWorldState *world)
|
||||
{
|
||||
Entity *ship = &world->entityList[world->entityIndex++];
|
||||
ship->id = world->entityIdCounter++;
|
||||
@ -507,7 +509,7 @@ INTERNAL void addPlayer(World *world)
|
||||
ship->color = V4(1.0f, 0.5f, 0.5f, 1.0f);
|
||||
}
|
||||
|
||||
INTERNAL void deleteEntity(World *world, i32 entityIndex)
|
||||
INTERNAL void deleteEntity(GameWorldState *world, i32 entityIndex)
|
||||
{
|
||||
ASSERT(entityIndex > 0);
|
||||
ASSERT(entityIndex < ARRAY_COUNT(world->entityList));
|
||||
@ -520,9 +522,51 @@ INTERNAL void deleteEntity(World *world, i32 entityIndex)
|
||||
world->entityList[--world->entityIndex] = emptyEntity;
|
||||
}
|
||||
|
||||
#define GET_STATE_DATA(state, arena, type) \
|
||||
(type *)getStateData_(state, arena, appstate_##type)
|
||||
INTERNAL void *getStateData_(GameState *state, MemoryArena_ *persistentArena,
|
||||
enum AppState appState)
|
||||
{
|
||||
void *result = NULL;
|
||||
switch (appState)
|
||||
{
|
||||
case appstate_StartMenuState:
|
||||
{
|
||||
if (!state->appStateData[appState])
|
||||
{
|
||||
state->appStateData[appState] =
|
||||
MEMORY_PUSH_STRUCT(persistentArena, StartMenuState);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case appstate_GameWorldState:
|
||||
{
|
||||
if (!state->appStateData[appState])
|
||||
{
|
||||
state->appStateData[appState] =
|
||||
MEMORY_PUSH_STRUCT(persistentArena, GameWorldState);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ASSERT(INVALID_CODE_PATH);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERT(state->appStateData[appState]);
|
||||
result = state->appStateData[appState];
|
||||
return result;
|
||||
}
|
||||
|
||||
INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
|
||||
{
|
||||
World *world = &state->world;
|
||||
GameWorldState *world =
|
||||
GET_STATE_DATA(state, &state->persistentArena, GameWorldState);
|
||||
|
||||
if (!world->init)
|
||||
{
|
||||
world->pixelsPerMeter = 70.0f;
|
||||
@ -946,9 +990,6 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL_PERSIST f32 flashingGameStartTimerThreshold = 1.0f;
|
||||
LOCAL_PERSIST f32 flashingGameStartTimer = 1.0f;
|
||||
LOCAL_PERSIST b32 toggleShowGameStart = TRUE;
|
||||
INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
|
||||
{
|
||||
AssetManager *assetManager = &state->assetManager;
|
||||
@ -956,7 +997,8 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
|
||||
Renderer *renderer = &state->renderer;
|
||||
MemoryArena_ *transientArena = &state->transientArena;
|
||||
UiState *uiState = &state->uiState;
|
||||
World *world = &state->world;
|
||||
StartMenuState *menuState =
|
||||
GET_STATE_DATA(state, &state->persistentArena, StartMenuState);
|
||||
|
||||
Font *arial15 = asset_fontGetOrCreateOnDemand(
|
||||
assetManager, &state->persistentArena, transientArena, "Arial", 15);
|
||||
@ -976,14 +1018,16 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
|
||||
|
||||
ui_beginState(uiState);
|
||||
|
||||
flashingGameStartTimer -= dt;
|
||||
if (flashingGameStartTimer < 0)
|
||||
{ // Draw blinking Start Game prompt
|
||||
menuState->startMenuGameStartBlinkTimer -= dt;
|
||||
if (menuState->startMenuGameStartBlinkTimer < 0.0f)
|
||||
{
|
||||
toggleShowGameStart = (toggleShowGameStart) ? FALSE : TRUE;
|
||||
flashingGameStartTimer = flashingGameStartTimerThreshold;
|
||||
menuState->startMenuGameStartBlinkTimer = 1.0f;
|
||||
menuState->startMenuToggleShow =
|
||||
(menuState->startMenuToggleShow) ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
if (toggleShowGameStart)
|
||||
if (menuState->startMenuToggleShow)
|
||||
{
|
||||
const char *const gameStart = "Press enter to start";
|
||||
v2 gameStartDim = asset_fontStringDimInPixels(arial25, gameStart);
|
||||
@ -994,17 +1038,39 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
|
||||
renderer_stringFixed(renderer, transientArena, arial25, gameStart,
|
||||
gameStartP, V2(0, 0), 0, V4(1, 1, 0, 1), 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const char *const optionPrompt = "Press [o] for options ";
|
||||
v2 dim = asset_fontStringDimInPixels(arial25, optionPrompt);
|
||||
v2 halfDim = v2_scale(dim, 0.5f);
|
||||
v2 p = v2_add(screenCenter, V2(0, -120));
|
||||
p = v2_sub(p, halfDim);
|
||||
renderer_stringFixed(renderer, transientArena, arial25, optionPrompt, p,
|
||||
V2(0, 0), 0, V4(1, 1, 0, 1), 0);
|
||||
}
|
||||
|
||||
if (platform_queryKey(&inputBuffer->keys[keycode_enter],
|
||||
readkeytype_one_shot, KEY_DELAY_NONE))
|
||||
{
|
||||
state->appState = appstate_game;
|
||||
addPlayer(&state->world);
|
||||
state->currState = appstate_GameWorldState;
|
||||
|
||||
GameWorldState *world =
|
||||
GET_STATE_DATA(state, &state->persistentArena, GameWorldState);
|
||||
addPlayer(world);
|
||||
}
|
||||
|
||||
ui_endState(uiState, inputBuffer);
|
||||
}
|
||||
|
||||
#define ASTEROID_GET_STATE_DATA(state, type) \
|
||||
(type *)asteroid_getStateData_(state, appstate_##type)
|
||||
void *asteroid_getStateData_(GameState *state, enum AppState appState)
|
||||
{
|
||||
void *result = state->appStateData[appState];
|
||||
return result;
|
||||
}
|
||||
|
||||
void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
||||
v2 windowSize, f32 dt)
|
||||
{
|
||||
@ -1028,21 +1094,21 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
||||
Font *arial15 = asset_fontGet(&state->assetManager, "Arial", 15);
|
||||
debug_init(&state->persistentArena, windowSize, *arial15);
|
||||
|
||||
state->appState = appstate_start_menu;
|
||||
state->currState = appstate_StartMenuState;
|
||||
state->init = TRUE;
|
||||
}
|
||||
|
||||
platform_inputBufferProcess(&state->input, dt);
|
||||
|
||||
switch (state->appState)
|
||||
switch (state->currState)
|
||||
{
|
||||
case appstate_start_menu:
|
||||
case appstate_StartMenuState:
|
||||
{
|
||||
// NOTE(doyle): Let menu overlay the game menu. We add player on "enter"
|
||||
// So fall through to appstate_game is valid here!
|
||||
startMenuUpdate(state, memory, dt);
|
||||
}
|
||||
case appstate_game:
|
||||
case appstate_GameWorldState:
|
||||
{
|
||||
gameUpdate(state, memory, dt);
|
||||
}
|
||||
|
@ -278,13 +278,17 @@ void debug_drawUi(GameState *state, f32 dt)
|
||||
v2 persistentUsage = V2i(persistentUsedInKbs, persistentSizeInKbs);
|
||||
DEBUG_PUSH_VAR("Permanent Usage: %.0f/%.0f", persistentUsage, "v2");
|
||||
|
||||
MemoryArena_ *entityArena = &state->world.entityArena;
|
||||
GameWorldState *world = ASTEROID_GET_STATE_DATA(state, GameWorldState);
|
||||
if (world)
|
||||
{
|
||||
MemoryArena_ *entityArena = &world->entityArena;
|
||||
i32 entitySizeInKbs = entityArena->size / 1024;
|
||||
i32 entityUsedInKbs = entityArena->used / 1024;
|
||||
v2 entityUsage = V2i(entityUsedInKbs, entitySizeInKbs);
|
||||
DEBUG_PUSH_VAR("Entity Usage: %.0f/%.0f", entityUsage, "v2");
|
||||
DEBUG_PUSH_STRING("== ==");
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_PUSH_VAR("Num Vertex: %d",
|
||||
GLOBAL_debug.callCount[debugcount_numVertex], "i32");
|
||||
|
@ -206,7 +206,7 @@ i32 main(void)
|
||||
glfwPollEvents();
|
||||
|
||||
/* Rendering commands here*/
|
||||
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
asteroid_gameUpdateAndRender(gameState, &memory, windowSize,
|
||||
@ -236,10 +236,16 @@ i32 main(void)
|
||||
f32 msPerFrame = secondsElapsed * 1000.0f;
|
||||
f32 framesPerSecond = 1.0f / secondsElapsed;
|
||||
|
||||
i32 entityCount = 0;
|
||||
GameWorldState *world =
|
||||
ASTEROID_GET_STATE_DATA(gameState, GameWorldState);
|
||||
|
||||
if (world) entityCount = world->entityIndex;
|
||||
|
||||
char textBuffer[256];
|
||||
snprintf(textBuffer, ARRAY_COUNT(textBuffer),
|
||||
"Dengine | %f ms/f | %f fps | Entity Count: %d",
|
||||
msPerFrame, framesPerSecond, gameState->world.entityIndex);
|
||||
msPerFrame, framesPerSecond, entityCount);
|
||||
|
||||
glfwSetWindowTitle(window, textBuffer);
|
||||
titleUpdateFrequencyInSeconds = 0.5f;
|
||||
|
@ -12,14 +12,15 @@
|
||||
|
||||
enum AppState
|
||||
{
|
||||
appstate_start_menu,
|
||||
appstate_game,
|
||||
appstate_StartMenuState,
|
||||
appstate_GameWorldState,
|
||||
appstate_count,
|
||||
};
|
||||
|
||||
typedef struct World
|
||||
typedef struct GameWorldState
|
||||
{
|
||||
b32 init;
|
||||
|
||||
MemoryArena_ entityArena;
|
||||
|
||||
v2 *entityVertexListCache[entitytype_count];
|
||||
@ -49,12 +50,20 @@ typedef struct World
|
||||
|
||||
// TODO(doyle): Ensure we change this if it gets too big
|
||||
b32 collisionTable[entitytype_count][entitytype_count];
|
||||
} World;
|
||||
} GameWorldState;
|
||||
|
||||
typedef struct GameState {
|
||||
typedef struct StartMenuState
|
||||
{
|
||||
f32 startMenuGameStartBlinkTimer;
|
||||
b32 startMenuToggleShow;
|
||||
} StartMenuState;
|
||||
|
||||
typedef struct GameState
|
||||
{
|
||||
b32 init;
|
||||
|
||||
enum AppState appState;
|
||||
enum AppState currState;
|
||||
void *appStateData[appstate_count];
|
||||
|
||||
MemoryArena_ transientArena;
|
||||
MemoryArena_ persistentArena;
|
||||
@ -65,9 +74,12 @@ typedef struct GameState {
|
||||
Renderer renderer;
|
||||
|
||||
UiState uiState;
|
||||
World world;
|
||||
} GameState;
|
||||
|
||||
#define ASTEROID_GET_STATE_DATA(state, type) \
|
||||
(type *)asteroid_getStateData_(state, appstate_##type)
|
||||
void *asteroid_getStateData_(GameState *state, enum AppState appState);
|
||||
|
||||
void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
||||
v2 windowSize, f32 dt);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user