Change start screen to pre-init the world

This commit is contained in:
Doyle Thai 2016-11-28 16:11:53 +11:00
parent 6df92e7aed
commit 15b4ff59f7
3 changed files with 179 additions and 121 deletions

View File

@ -7,9 +7,17 @@ INTERNAL void loadGameAssets(GameState *state)
MemoryArena_ *arena = &state->persistentArena; MemoryArena_ *arena = &state->persistentArena;
{ // Init font assets { // Init font assets
#if 0
i32 result = i32 result =
asset_fontLoadTTF(assetManager, arena, &state->transientArena, asset_fontLoadTTF(assetManager, arena, &state->transientArena,
"C:/Windows/Fonts/Arialbd.ttf", "Arial", 15); "C:/Windows/Fonts/Arialbd.ttf", "Arial", 15);
#endif
asset_fontLoadTTF(assetManager, arena, &state->transientArena,
"F:/Workspace/Dropbox/Apps/Fonts/"
"league-spartan-master/_webfonts/"
"leaguespartan-bold.ttf",
"Arial", 15);
} }
{ // Init shaders assets { // Init shaders assets
@ -64,8 +72,8 @@ INTERNAL void loadGameAssets(GameState *state)
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
v2 *createAsteroidVertexList(MemoryArena_ *arena, i32 iterations, INTERNAL v2 *createAsteroidVertexList(MemoryArena_ *arena, i32 iterations,
i32 asteroidRadius) i32 asteroidRadius)
{ {
f32 iterationAngle = 360.0f / iterations; f32 iterationAngle = 360.0f / iterations;
iterationAngle = DEGREES_TO_RADIANS(iterationAngle); iterationAngle = DEGREES_TO_RADIANS(iterationAngle);
@ -120,8 +128,8 @@ v2 *createAsteroidVertexList(MemoryArena_ *arena, i32 iterations,
return result; return result;
} }
v2 *createNormalEdgeList(MemoryArena_ *transientArena, v2 *vertexList, INTERNAL v2 *createNormalEdgeList(MemoryArena_ *transientArena, v2 *vertexList,
i32 vertexListSize) i32 vertexListSize)
{ {
v2 *result = memory_pushBytes(transientArena, sizeof(v2) * vertexListSize); v2 *result = memory_pushBytes(transientArena, sizeof(v2) * vertexListSize);
for (i32 i = 0; i < vertexListSize - 1; i++) for (i32 i = 0; i < vertexListSize - 1; i++)
@ -140,10 +148,10 @@ v2 *createNormalEdgeList(MemoryArena_ *transientArena, v2 *vertexList,
return result; return result;
} }
v2 calculateProjectionRangeForEdge(v2 *vertexList, i32 vertexListSize, INTERNAL v2 calculateProjectionRangeForEdge(v2 *vertexList, i32 vertexListSize,
v2 edgeNormal) v2 edgeNormal)
{ {
v2 result = {0}; v2 result = {0};
result.min = v2_dot(vertexList[0], edgeNormal); result.min = v2_dot(vertexList[0], edgeNormal);
result.max = result.min; result.max = result.min;
@ -160,9 +168,9 @@ v2 calculateProjectionRangeForEdge(v2 *vertexList, i32 vertexListSize,
return result; return result;
} }
b32 checkEdgeProjectionOverlap(v2 *vertexList, i32 listSize, INTERNAL b32 checkEdgeProjectionOverlap(v2 *vertexList, i32 listSize,
v2 *checkVertexList, i32 checkListSize, v2 *checkVertexList, i32 checkListSize,
v2 *edgeList, i32 totalNumEdges) v2 *edgeList, i32 totalNumEdges)
{ {
b32 result = TRUE; b32 result = TRUE;
for (i32 edgeIndex = 0; edgeIndex < totalNumEdges && result; edgeIndex++) for (i32 edgeIndex = 0; edgeIndex < totalNumEdges && result; edgeIndex++)
@ -443,18 +451,60 @@ INTERNAL void setCollisionRule(World *world, enum EntityType a,
world->collisionTable[b][a] = rule; world->collisionTable[b][a] = rule;
} }
INTERNAL AudioRenderer *getFreeAudioRenderer(World *world) INTERNAL AudioRenderer *getFreeAudioRenderer(World *world, AudioVorbis *vorbis,
i32 maxSimultaneousPlayers)
{ {
i32 freeIndex = -1;
i32 sameAudioPlayingCount = 0;
AudioRenderer *result = NULL;
for (i32 i = 0; i < world->numAudioRenderers; i++) for (i32 i = 0; i < world->numAudioRenderers; i++)
{ {
AudioRenderer *renderer = &world->audioRenderer[i]; AudioRenderer *renderer = &world->audioRenderer[i];
if (renderer->state == audiostate_stopped) if (renderer->state == audiostate_playing &&
common_strcmp(renderer->audio->key, vorbis->key) == 0)
{ {
return renderer; sameAudioPlayingCount++;
}
else if (renderer->state == audiostate_stopped && freeIndex == -1)
{
freeIndex = i;
} }
} }
return NULL; if (sameAudioPlayingCount < maxSimultaneousPlayers && freeIndex != -1)
{
result = &world->audioRenderer[freeIndex];
}
return result;
}
INTERNAL void addPlayer(World *world)
{
Entity *ship = &world->entityList[world->entityIndex++];
ship->id = world->entityIdCounter++;
ship->pos = math_rectGetCentre(world->camera);
ship->size = V2(25.0f, 50.0f);
ship->hitbox = ship->size;
ship->offset = v2_scale(ship->size, -0.5f);
ship->numVertexPoints = 3;
ship->vertexPoints = memory_pushBytes(&world->entityArena,
sizeof(v2) * ship->numVertexPoints);
v2 triangleBaseP = V2(0, 0);
v2 triangleTopP = V2(ship->size.w * 0.5f, ship->size.h);
v2 triangleRightP = V2(ship->size.w, triangleBaseP.y);
ship->vertexPoints[0] = triangleBaseP;
ship->vertexPoints[1] = triangleRightP;
ship->vertexPoints[2] = triangleTopP;
ship->scale = 1;
ship->type = entitytype_ship;
ship->renderMode = rendermode_polygon;
ship->color = V4(1.0f, 0.5f, 0.5f, 1.0f);
} }
INTERNAL void deleteEntity(World *world, i32 entityIndex) INTERNAL void deleteEntity(World *world, i32 entityIndex)
@ -497,37 +547,11 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
} }
{ // Init audio renderer { // Init audio renderer
world->numAudioRenderers = 6; world->numAudioRenderers = 8;
world->audioRenderer = MEMORY_PUSH_ARRAY( world->audioRenderer = MEMORY_PUSH_ARRAY(
&world->entityArena, world->numAudioRenderers, AudioRenderer); &world->entityArena, world->numAudioRenderers, AudioRenderer);
} }
{ // Init ship entity
Entity *ship = &world->entityList[world->entityIndex++];
ship->id = world->entityIdCounter++;
ship->pos = math_rectGetCentre(world->camera);
ship->size = V2(25.0f, 50.0f);
ship->hitbox = ship->size;
ship->offset = v2_scale(ship->size, -0.5f);
ship->numVertexPoints = 3;
ship->vertexPoints = memory_pushBytes(
&world->entityArena, sizeof(v2) * ship->numVertexPoints);
v2 triangleBaseP = V2(0, 0);
v2 triangleTopP = V2(ship->size.w * 0.5f, ship->size.h);
v2 triangleRightP = V2(ship->size.w, triangleBaseP.y);
ship->vertexPoints[0] = triangleBaseP;
ship->vertexPoints[1] = triangleRightP;
ship->vertexPoints[2] = triangleTopP;
ship->scale = 1;
ship->type = entitytype_ship;
ship->renderMode = rendermode_polygon;
ship->color = V4(1.0f, 0.5f, 0.5f, 1.0f);
}
{ // Global Collision Rules { // Global Collision Rules
setCollisionRule(world, entitytype_ship, entitytype_asteroid_small, setCollisionRule(world, entitytype_ship, entitytype_asteroid_small,
TRUE); TRUE);
@ -543,19 +567,32 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
entitytype_asteroid_large, TRUE); entitytype_asteroid_large, TRUE);
} }
world->init = TRUE; world->numStarP = 100;
world->onInitAsteroidSpawnTimer = 1.0f; world->starPList =
MEMORY_PUSH_ARRAY(&state->persistentArena, world->numStarP, v2);
for (i32 i = 0; i < world->numStarP; i++)
{
i32 randX = rand() % (i32)world->worldSize.x;
i32 randY = rand() % (i32)world->worldSize.y;
world->starPList[i] = V2i(randX, randY);
}
world->init = TRUE;
} }
if (world->onInitAsteroidSpawnTimer > 0) for (u32 i = world->asteroidCounter; i < world->numAsteroids; i++)
addAsteroid(world, (rand() % asteroidsize_count));
Radians starRotation = DEGREES_TO_RADIANS(45.0f);
v2 starSize = V2(2, 2);
for (i32 i = 0; i < world->numStarP; i++)
{ {
world->onInitAsteroidSpawnTimer -= dt; renderer_rect(&state->renderer, world->camera, world->starPList[i],
} starSize, V2(0, 0), starRotation, NULL,
else V4(1.0f, 1.0f, 0, 0.5f),
{ renderflag_no_texture | renderflag_wireframe);
for (u32 i = world->asteroidCounter; i < world->numAsteroids; i++)
addAsteroid(world, (rand() % asteroidsize_count));
} }
if (platform_queryKey(&state->input.keys[keycode_left_square_bracket], if (platform_queryKey(&state->input.keys[keycode_left_square_bracket],
@ -592,16 +629,17 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
{ {
addBullet(world, entity); addBullet(world, entity);
AudioRenderer *audioRenderer = getFreeAudioRenderer(world);
if (audioRenderer)
{
AudioVorbis *fire = AudioVorbis *fire =
asset_vorbisGet(&state->assetManager, "fire"); asset_vorbisGet(&state->assetManager, "fire");
// TODO(doyle): Atm transient arena is not used, this is AudioRenderer *audioRenderer =
// just to fill out the arguments getFreeAudioRenderer(world, fire, 2);
audio_vorbisPlay(&state->transientArena, if (audioRenderer)
&state->audioManager, audioRenderer, fire, {
1); // TODO(doyle): Atm transient arena is not used, this is
// just to fill out the arguments
audio_vorbisPlay(&state->transientArena,
&state->audioManager, audioRenderer,
fire, 1);
} }
} }
@ -863,26 +901,27 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
ASSERT(world->asteroidCounter >= 0); ASSERT(world->asteroidCounter >= 0);
AudioRenderer *audioRenderer = getFreeAudioRenderer(world); char *sound;
i32 choice = rand() % 3;
if (choice == 0)
{
sound = "bang_small";
}
else if (choice == 1)
{
sound = "bang_medium";
}
else
{
sound = "bang_large";
}
AudioVorbis *explode =
asset_vorbisGet(&state->assetManager, sound);
AudioRenderer *audioRenderer =
getFreeAudioRenderer(world, explode, 3);
if (audioRenderer) if (audioRenderer)
{ {
char *sound;
i32 choice = rand() % 3;
if (choice == 0)
{
sound = "bang_small";
}
else if (choice == 1)
{
sound = "bang_medium";
}
else
{
sound = "bang_large";
}
AudioVorbis *explode =
asset_vorbisGet(&state->assetManager, sound);
audio_vorbisPlay(&state->transientArena, audio_vorbisPlay(&state->transientArena,
&state->audioManager, audioRenderer, &state->audioManager, audioRenderer,
explode, 1); explode, 1);
@ -907,37 +946,60 @@ 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) INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
{ {
UiState *uiState = &state->uiState;
MemoryArena_ *transientArena = &state->transientArena;
AssetManager *assetManager = &state->assetManager; AssetManager *assetManager = &state->assetManager;
Renderer *renderer = &state->renderer;
World *world = &state->world;
InputBuffer *inputBuffer = &state->input; InputBuffer *inputBuffer = &state->input;
Renderer *renderer = &state->renderer;
MemoryArena_ *transientArena = &state->transientArena;
UiState *uiState = &state->uiState;
World *world = &state->world;
Font *arial15 = asset_fontGetOrCreateOnDemand( Font *arial15 = asset_fontGetOrCreateOnDemand(
assetManager, &state->persistentArena, transientArena, "Arial", 15); assetManager, &state->persistentArena, transientArena, "Arial", 15);
Font *arial25 = asset_fontGetOrCreateOnDemand( Font *arial25 = asset_fontGetOrCreateOnDemand(
assetManager, &state->persistentArena, transientArena, "Arial", 40); assetManager, &state->persistentArena, transientArena, "Arial", 40);
f32 margin = 20.0f; v2 screenCenter = v2_scale(renderer->size, 0.5f);
f32 padding = 20.0f;
v2 titleP = V2(margin, renderer->size.h - 100 + margin); const char *const title = "Asteroids";
renderer_stringFixed(renderer, transientArena, arial25, "Asteroids", v2 titleDim = asset_fontStringDimInPixels(arial25, title);
titleP, V2(0, 0), 0, V4(1, 0, 0, 1), 0); v2 halfTitleDim = v2_scale(titleDim, 0.5f);
v2 titleP = v2_add(screenCenter, V2(0, 40));
titleP = v2_sub(titleP, halfTitleDim);
renderer_stringFixed(renderer, transientArena, arial25, title, titleP,
V2(0, 0), 0, V4(1, 0, 0, 1), 0);
ui_beginState(uiState); ui_beginState(uiState);
Rect buttonRect = {0}; flashingGameStartTimer -= dt;
buttonRect.min = V2(margin, margin); if (flashingGameStartTimer < 0)
buttonRect.max = V2(margin + 100, margin + 40); {
buttonRect = math_rectShift(buttonRect, V2(0, titleP.y - 100)); toggleShowGameStart = (toggleShowGameStart) ? FALSE : TRUE;
if (ui_button(uiState, transientArena, assetManager, renderer, flashingGameStartTimer = flashingGameStartTimerThreshold;
arial15, *inputBuffer, 1, buttonRect, }
"Start Game"))
if (toggleShowGameStart)
{
const char *const gameStart = "Press enter to start";
v2 gameStartDim = asset_fontStringDimInPixels(arial25, gameStart);
v2 halfGameStartDim = v2_scale(gameStartDim, 0.5f);
v2 gameStartP = v2_add(screenCenter, V2(0, -40));
gameStartP = v2_sub(gameStartP, halfGameStartDim);
renderer_stringFixed(renderer, transientArena, arial25, gameStart,
gameStartP, 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; state->appState = appstate_game;
addPlayer(&state->world);
} }
ui_endState(uiState, inputBuffer); ui_endState(uiState, inputBuffer);
@ -976,10 +1038,10 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
{ {
case appstate_start_menu: case appstate_start_menu:
{ {
// 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); startMenuUpdate(state, memory, dt);
} }
break;
case appstate_game: case appstate_game:
{ {
gameUpdate(state, memory, dt); gameUpdate(state, memory, dt);

View File

@ -35,10 +35,10 @@ const SubTexture asset_atlasGetSubTex(TexAtlas *const atlas,
const char *const key); const char *const key);
Texture *asset_texGet(AssetManager *const assetManager, const char *const key); Texture *asset_texGet(AssetManager *const assetManager, const char *const key);
TexAtlas *asset_atlasGetFreeSlot(AssetManager *const assetManager, TexAtlas *asset_atlasGetFreeSlot(AssetManager *const assetManager,
MemoryArena_ *arena, const char *const key, MemoryArena_ *arena, const char *const key,
i32 numSubTex); i32 numSubTex);
TexAtlas *asset_atlasGet(AssetManager *const assetManager, TexAtlas *asset_atlasGet(AssetManager *const assetManager,
const char *const key); const char *const key);
Texture *asset_texGetFreeSlot(AssetManager *const assetManager, Texture *asset_texGetFreeSlot(AssetManager *const assetManager,
MemoryArena_ *const arena, const char *const key); MemoryArena_ *const arena, const char *const key);
Texture *asset_loadTextureImage(AssetManager *assetManager, MemoryArena_ *arena, Texture *asset_loadTextureImage(AssetManager *assetManager, MemoryArena_ *arena,
@ -49,10 +49,10 @@ Texture *asset_loadTextureImage(AssetManager *assetManager, MemoryArena_ *arena,
* Animation Asset Managing * Animation Asset Managing
********************************* *********************************
*/ */
void asset_animAdd(AssetManager *const assetManager, void asset_animAdd(AssetManager *const assetManager, MemoryArena_ *const arena,
MemoryArena_ *const arena, const char *const animName, const char *const animName, TexAtlas *const atlas,
TexAtlas *const atlas, char **const subTextureNames, char **const subTextureNames, const i32 numSubTextures,
const i32 numSubTextures, const f32 frameDuration); const f32 frameDuration);
Animation *asset_animGet(AssetManager *const assetManager, Animation *asset_animGet(AssetManager *const assetManager,
const char *const key); const char *const key);
@ -72,28 +72,27 @@ const i32 asset_vorbisLoad(AssetManager *assetManager, MemoryArena_ *arena,
********************************* *********************************
*/ */
const i32 asset_xmlLoad(AssetManager *const assetManager, const i32 asset_xmlLoad(AssetManager *const assetManager,
MemoryArena_ *const arena, MemoryArena_ *const arena,
const PlatformFileRead *const fileRead); const PlatformFileRead *const fileRead);
u32 asset_shaderGet(AssetManager *assetManager, const enum ShaderList type); u32 asset_shaderGet(AssetManager *assetManager, const enum ShaderList type);
const i32 asset_shaderLoad(AssetManager *assetManager, MemoryArena_ *arena, const i32 asset_shaderLoad(AssetManager *assetManager, MemoryArena_ *arena,
const char *const vertexPath, const char *const vertexPath,
const char *const fragmentPath, const char *const fragmentPath,
const enum ShaderList type); const enum ShaderList type);
Font *asset_fontGetOrCreateOnDemand(AssetManager *assetManager, Font *asset_fontGetOrCreateOnDemand(AssetManager *assetManager,
MemoryArena_ *persistentArena, MemoryArena_ *persistentArena,
MemoryArena_ *transientArena, char *name, MemoryArena_ *transientArena, char *name,
i32 size); i32 size);
Font *asset_fontGet(AssetManager *assetManager, char *name, Font *asset_fontGet(AssetManager *assetManager, char *name, i32 size);
i32 size);
const i32 asset_fontLoadTTF(AssetManager *assetManager, const i32 asset_fontLoadTTF(AssetManager *assetManager,
MemoryArena_ *persistentArena, MemoryArena_ *persistentArena,
MemoryArena_ *transientArena, char *filePath, MemoryArena_ *transientArena, char *filePath,
char *name, i32 targetFontHeight); char *name, i32 targetFontHeight);
const v2 asset_fontStringDimInPixels(const Font *const font, const v2 asset_fontStringDimInPixels(const Font *const font,
const char *const string); const char *const string);
void asset_unitTest(MemoryArena_ *arena); void asset_unitTest(MemoryArena_ *arena);

View File

@ -20,11 +20,6 @@ enum AppState
typedef struct World typedef struct World
{ {
b32 init; b32 init;
// NOTE(doyle): Grace period when game starts before asteroids start
// spawning
f32 onInitAsteroidSpawnTimer;
MemoryArena_ entityArena; MemoryArena_ entityArena;
v2 *entityVertexListCache[entitytype_count]; v2 *entityVertexListCache[entitytype_count];
@ -41,6 +36,9 @@ typedef struct World
v2 *bulletVertexCache; v2 *bulletVertexCache;
v2 *particleVertexCache; v2 *particleVertexCache;
v2 *starPList;
i32 numStarP;
// TODO(doyle): Audio mixing instead of multiple renderers // TODO(doyle): Audio mixing instead of multiple renderers
AudioRenderer *audioRenderer; AudioRenderer *audioRenderer;
i32 numAudioRenderers; i32 numAudioRenderers;
@ -68,7 +66,6 @@ typedef struct GameState {
UiState uiState; UiState uiState;
World world; World world;
} GameState; } GameState;
void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,