Add score multiplier into game

This commit is contained in:
Doyle Thai 2016-11-30 21:21:28 +11:00
parent fb254b06ec
commit 35e0569f8d
7 changed files with 267 additions and 38 deletions

View File

@ -1484,7 +1484,7 @@ const i32 asset_fontLoadTTF(AssetManager *assetManager,
}
const v2 asset_fontStringDimInPixels(const Font *const font,
const char *const string)
const char *const string)
{
v2 stringDim = V2(0, 0);
for (i32 i = 0; i < common_strlen(string); i++)

View File

@ -562,13 +562,38 @@ INTERNAL void *getStateData_(GameState *state, MemoryArena_ *persistentArena,
return result;
}
INTERNAL v2 wrapPAroundBounds(v2 p, Rect bounds)
{
v2 result = p;
if (p.y >= bounds.max.y)
result.y = 0;
else if (p.y < bounds.min.y)
result.y = bounds.max.y;
if (p.x >= bounds.max.x)
result.x = 0;
else if (p.x < bounds.min.x)
result.x = bounds.max.x;
return result;
}
INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
{
GameWorldState *world =
GET_STATE_DATA(state, &state->persistentArena, GameWorldState);
if (!world->init)
if (!common_isSet(world->flags, gameworldstateflags_init))
{
#ifdef DENGINE_DEBUG
{
u8 *data = (u8 *)world;
for (i32 i = 0; i < sizeof(GameWorldState); i++)
ASSERT(data[i] == 0);
}
#endif
world->pixelsPerMeter = 70.0f;
MemoryIndex entityArenaSize =
@ -628,7 +653,92 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
world->starPList[i] = V2i(randX, randY);
}
world->init = TRUE;
world->flags |= gameworldstateflags_init;
world->scoreMultiplier = 5;
world->scoreMultiplierBarTimer = 0.0f;
world->scoreMultiplierBarThresholdInS = 2.0f;
}
if (common_isSet(world->flags, gameworldstateflags_level_started))
{
Font *arial40 = asset_fontGet(&state->assetManager, "Arial", 40);
Renderer *renderer = &state->renderer;
/* Render scores onto screen */
v2 stringP =
V2((renderer->size.w * 0.5f), renderer->size.h - arial40->size);
char gamePointsString[COMMON_ITOA_MAX_BUFFER_32BIT] = {0};
common_itoa(world->score, gamePointsString,
ARRAY_COUNT(gamePointsString));
renderer_stringFixedCentered(renderer, &state->transientArena, arial40,
gamePointsString, stringP, V2(0, 0), 0,
V4(1.0f, 1.0f, 1.0f, 1.0f), 1, 0);
/* Render multiplier accumulator bar onto screen */
v2 stringDim = asset_fontStringDimInPixels(arial40, gamePointsString);
v2 multiplierOutlineSize =
V2(renderer->size.w * 0.5f, stringDim.h * 0.25f);
v2 multiplierOutlineP = V2(renderer->size.w * 0.5f, stringP.h);
multiplierOutlineP.x -= (multiplierOutlineSize.w * 0.5f);
multiplierOutlineP.y -= stringDim.h * 1.5f;
renderer_rectFixedOutline(
renderer, multiplierOutlineP, multiplierOutlineSize, V2(0, 0), 2, 0,
NULL, V4(0.2f, 0.3f, 0.8f, 1.0f), 2, renderflag_no_texture);
f32 progressNormalised = world->scoreMultiplierBarTimer /
world->scoreMultiplierBarThresholdInS;
renderer_rectFixed(renderer, multiplierOutlineP,
V2(multiplierOutlineSize.w * progressNormalised,
multiplierOutlineSize.h),
V2(0, 0), 0, NULL, V4(0.2f, 0.3f, 0.8f, 1.0f), 1,
renderflag_no_texture);
/* Render multiplier counter hud onto screen */
v2 multiplierHudP = V2(0, 0.05f * renderer->size.h);
v2 multiplierHudSize =
V2((arial40->maxSize.w * 3.5f), arial40->fontHeight * 1.2f);
renderer_rectFixed(renderer, multiplierHudP, multiplierHudSize,
V2(0, 0), 0, NULL, V4(1, 1, 1, 0.1f), 2,
renderflag_no_texture);
/* Render multiplier counter string to hud */
char multiplierToString[COMMON_ITOA_MAX_BUFFER_32BIT + 1] = {0};
common_itoa(world->scoreMultiplier, multiplierToString + 1,
ARRAY_COUNT(multiplierToString) - 1);
multiplierToString[0] = 'x';
v2 multiplierToStringP = multiplierHudP;
multiplierToStringP =
v2_add(multiplierToStringP, v2_scale(multiplierHudSize, 0.5f));
renderer_stringFixedCentered(
renderer, &state->transientArena, arial40, multiplierToString,
multiplierToStringP, V2(0, 0), 0, V4(1.0f, 1.0f, 1.0f, 1.0f), 3, 0);
/* Process multiplier bar updates */
f32 barTimerPenalty = 1.0f;
if (world->timeSinceLastShot < 1.5f)
{
barTimerPenalty = 0.1f;
}
world->scoreMultiplierBarTimer += (barTimerPenalty * dt);
world->timeSinceLastShot += dt;
if (world->scoreMultiplierBarTimer >
world->scoreMultiplierBarThresholdInS)
{
world->scoreMultiplierBarTimer = 0;
world->scoreMultiplier++;
if (world->scoreMultiplier > 9999) world->scoreMultiplier = 9999;
}
}
for (u32 i = world->asteroidCounter; i < world->numAsteroids; i++)
@ -660,10 +770,14 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
for (i32 i = 0; i < world->numStarP; i++)
{
world->starPList[i] = v2_add(world->starPList[i], V2(4.0f * dt, 0));
world->starPList[i] = wrapPAroundBounds(
world->starPList[i], math_rectCreate(V2(0, 0), world->size));
renderer_rect(&state->renderer, world->camera, world->starPList[i],
starSize, V2(0, 0), starRotation, NULL,
V4(0.8f, 0.8f, 0.8f, world->starOpacity),
0, renderflag_no_texture | renderflag_wireframe);
V4(0.8f, 0.8f, 0.8f, world->starOpacity), 0,
renderflag_no_texture | renderflag_wireframe);
}
if (platform_queryKey(&state->input.keys[keycode_left_square_bracket],
@ -700,6 +814,14 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
{
addBullet(world, entity);
if (world->timeSinceLastShot >= 0)
{
world->timeSinceLastShot = 0;
f32 multiplierPenalty = -2.0f;
world->timeSinceLastShot += multiplierPenalty;
}
AudioVorbis *fire =
asset_vorbisGet(&state->assetManager, "fire");
AudioRenderer *audioRenderer =
@ -733,6 +855,9 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
DEBUG_PUSH_VAR("Velocity: %5.2f, %5.2f", entity->dP, "v2");
DEBUG_PUSH_VAR("Rotation: %5.2f", entity->rotation, "f32");
DEBUG_PUSH_VAR("TimeSinceLastShot: %5.2f", world->timeSinceLastShot,
"f32");
renderer_rect(&state->renderer, world->camera, entity->pos,
V2(5, 5), V2(0, 0),
DEGREES_TO_RADIANS(entity->rotation), NULL,
@ -850,17 +975,10 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
entity->color.a = maxDp / divisor;
}
entity->pos = wrapPAroundBounds(entity->pos,
math_rectCreate(V2(0, 0), world->size));
/* Loop entity around world */
if (entity->pos.y >= world->size.h)
entity->pos.y = 0;
else if (entity->pos.y < 0)
entity->pos.y = world->size.h;
if (entity->pos.x >= world->size.w)
entity->pos.x = 0;
else if (entity->pos.x < 0)
entity->pos.x = world->size.w;
i32 collisionIndex = moveEntity(world, &state->transientArena, entity,
i, ddP, dt, ddPSpeedInMs);
@ -888,7 +1006,6 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
if (colliderA->type >= entitytype_asteroid_small &&
colliderA->type <= entitytype_asteroid_large)
{
f32 numParticles = 4;
if (colliderA->type == entitytype_asteroid_medium)
{
@ -898,6 +1015,7 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
addAsteroidWithSpec(world, asteroidsize_small, &spec);
numParticles = 8;
world->score += (10 * world->scoreMultiplier);
}
else if (colliderA->type == entitytype_asteroid_large)
{
@ -913,6 +1031,11 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
addAsteroidWithSpec(world, asteroidsize_small, &spec);
numParticles = 16;
world->score += (20 * world->scoreMultiplier);
}
else
{
world->score += (5 * world->scoreMultiplier);
}
for (i32 i = 0; i < numParticles; i++)
@ -1070,7 +1193,7 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
Font *arial15 = asset_fontGetOrCreateOnDemand(
assetManager, &state->persistentArena, transientArena, "Arial", 15);
Font *arial25 = asset_fontGetOrCreateOnDemand(
Font *arial40 = asset_fontGetOrCreateOnDemand(
assetManager, &state->persistentArena, transientArena, "Arial", 40);
v2 screenCenter = v2_scale(renderer->size, 0.5f);
@ -1132,12 +1255,12 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
}
}
f32 textYOffset = arial25->size * 1.5f;
f32 textYOffset = arial40->size * 1.5f;
{ // Options Title String Display
const char *const title = "Options";
v2 p = v2_add(screenCenter, V2(0, textYOffset));
renderer_stringFixedCentered(renderer, transientArena, arial25,
renderer_stringFixedCentered(renderer, transientArena, arial40,
title, p, V2(0, 0), 0,
V4(1, 1, 1, 1), uiZDepth, 0);
}
@ -1148,7 +1271,7 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
const char *const resolutionLabel = "Resolution";
v2 p = v2_add(screenCenter, V2(0, 0));
renderer_stringFixedCentered(renderer, transientArena, arial25,
renderer_stringFixedCentered(renderer, transientArena, arial40,
resolutionLabel, p, V2(0, 0), 0,
V4(1, 1, 1, 1), uiZDepth, 0);
@ -1157,22 +1280,18 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
menuState->resStrings[menuState->resStringDisplayIndex];
p = v2_add(screenCenter, V2(0, -textYOffset));
renderer_stringFixedCentered(renderer, transientArena, arial25,
renderer_stringFixedCentered(renderer, transientArena, arial40,
resStringToDisplay, p, V2(0, 0), 0,
V4(1, 1, 1, 1), uiZDepth, 0);
}
}
renderer_rectFixed(renderer, V2(100, 100), V2(1000, 500), V2(0, 0), 0,
NULL, V4(1.0f, 0.5f, 0.8f, 0.5f), uiZDepth - 1,
renderflag_no_texture);
}
else
{
/* Draw title text */
const char *const title = "Asteroids";
v2 p = v2_add(screenCenter, V2(0, 40));
renderer_stringFixedCentered(renderer, transientArena, arial25, title,
renderer_stringFixedCentered(renderer, transientArena, arial40, title,
p, V2(0, 0), 0, V4(1, 1, 1, 1), uiZDepth,
0);
@ -1189,7 +1308,7 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
{
const char *const gameStart = "Press enter to start";
v2 p = v2_add(screenCenter, V2(0, -40));
renderer_stringFixedCentered(renderer, transientArena, arial25,
renderer_stringFixedCentered(renderer, transientArena, arial40,
gameStart, p, V2(0, 0), 0,
V4(1, 1, 1, 1), uiZDepth, 0);
}
@ -1197,7 +1316,7 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
{ // Draw show options prompt
const char *const optionPrompt = "Press [o] for options ";
v2 p = v2_add(screenCenter, V2(0, -120));
renderer_stringFixedCentered(renderer, transientArena, arial25,
renderer_stringFixedCentered(renderer, transientArena, arial40,
optionPrompt, p, V2(0, 0), 0,
V4(1, 1, 1, 1), uiZDepth, 0);
}
@ -1211,6 +1330,7 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
addPlayer(world);
state->currState = appstate_GameWorldState;
world->flags |= gameworldstateflags_level_started;
}
else if (platform_queryKey(&inputBuffer->keys[keycode_o],
readkeytype_one_shot, KEY_DELAY_NONE))

View File

@ -226,9 +226,14 @@ void common_itoa(i32 value, char *buf, i32 bufSize)
{
if (!buf || bufSize == 0) return;
if (value == 0)
{
buf[0] = '0';
return;
}
// NOTE(doyle): Max 32bit integer (+-)2147483647
i32 charIndex = 0;
b32 negative = FALSE;
if (value < 0) negative = TRUE;
@ -242,8 +247,16 @@ void common_itoa(i32 value, char *buf, i32 bufSize)
val /= 10;
}
// NOTE(doyle): The actual string length may differ from the bufSize
reverseString(buf, common_strlen(buf));
// NOTE(doyle): If string is negative, we only want to reverse starting
// from the second character, so we don't put the negative sign at the end
if (negative)
{
reverseString(buf + 1, charIndex - 1);
}
else
{
reverseString(buf, charIndex);
}
}
// TODO(doyle): Consider if we should trash ptrs in string operations in general

View File

@ -107,6 +107,11 @@ INTERNAL void setGlfwWindowHints()
i32 main(void)
{
#ifdef DENGINE_DEBUG
common_unitTest();
#endif
/*
**************************
* INIT APPLICATION WINDOW

View File

@ -17,9 +17,15 @@ enum AppState
appstate_count,
};
enum GameWorldStateFlags
{
gameworldstateflags_init = (1 << 0),
gameworldstateflags_level_started = (1 << 1),
};
typedef struct GameWorldState
{
b32 init;
enum GameWorldStateFlags flags;
MemoryArena_ entityArena;
@ -54,6 +60,14 @@ typedef struct GameWorldState
// TODO(doyle): Ensure we change this if it gets too big
b32 collisionTable[entitytype_count][entitytype_count];
i32 score;
i32 scoreMultiplier;
f32 scoreMultiplierBarTimer;
f32 scoreMultiplierBarThresholdInS;
f32 timeSinceLastShot;
} GameWorldState;
typedef struct StartMenuState

View File

@ -79,9 +79,11 @@ i32 common_strlen(const char *const string);
i32 common_strcmp(const char *a, const char *b);
void common_strncat(char *dest, const char *src, i32 numChars);
char *common_strncpy(char *dest, const char *src, i32 numChars);
u8 *common_memset(u8 *const ptr, const i32 value, const i32 numBytes);
// Max buffer size should be 11 for 32 bit integers
#define COMMON_ITOA_MAX_BUFFER_32BIT 11
void common_itoa(i32 value, char *buf, i32 bufSize);
i32 common_atoi(const char *string, const i32 len);
@ -93,6 +95,42 @@ inline b32 common_isSet(u32 bitfield, u32 flags)
return result;
}
inline void common_unitTest()
{
{
char itoa[COMMON_ITOA_MAX_BUFFER_32BIT] = {0};
common_itoa(0, itoa, ARRAY_COUNT(itoa));
ASSERT(itoa[0] == '0');
ASSERT(itoa[1] == 0);
common_memset(itoa, 1, ARRAY_COUNT(itoa));
for (i32 i = 0; i < ARRAY_COUNT(itoa); i++) ASSERT(itoa[i] == 1);
common_memset(itoa, 0, ARRAY_COUNT(itoa));
for (i32 i = 0; i < ARRAY_COUNT(itoa); i++) ASSERT(itoa[i] == 0);
common_itoa(-123, itoa, ARRAY_COUNT(itoa));
ASSERT(itoa[0] == '-');
ASSERT(itoa[1] == '1');
ASSERT(itoa[2] == '2');
ASSERT(itoa[3] == '3');
ASSERT(itoa[4] == 0);
common_memset(itoa, 0, ARRAY_COUNT(itoa));
for (i32 i = 0; i < ARRAY_COUNT(itoa); i++) ASSERT(itoa[i] == 0);
common_itoa(93, itoa, ARRAY_COUNT(itoa));
ASSERT(itoa[0] == '9');
ASSERT(itoa[1] == '3');
ASSERT(itoa[2] == 0);
common_memset(itoa, 0, ARRAY_COUNT(itoa));
for (i32 i = 0; i < ARRAY_COUNT(itoa); i++) ASSERT(itoa[i] == 0);
common_itoa(-0, itoa, ARRAY_COUNT(itoa));
ASSERT(itoa[0] == '0');
ASSERT(itoa[1] == 0);
}
}
//-----------------------------------------------------------------------------
// MurmurHash2, by Austin Appleby

View File

@ -92,16 +92,38 @@ void renderer_init(Renderer *renderer, AssetManager *assetManager,
RenderTex renderer_createNullRenderTex(AssetManager *const assetManager);
// TODO(doyle): Clean up lines
// Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); }
// TODO(doyle): Rectangles with gradient alphas/gradient colours
void renderer_rect(Renderer *const renderer, Rect camera, v2 pos, v2 size,
v2 pivotPoint, Radians rotate, RenderTex *renderTex,
v4 color, i32 zDepth, RenderFlags flags);
void renderer_polygon(Renderer *const renderer, Rect camera, v2 *polygonPoints,
i32 numPoints, v2 pivotPoint, Radians rotate,
RenderTex *renderTex, v4 color, i32 zDepth,
RenderFlags flags);
inline void renderer_rectOutline(Renderer *const renderer, Rect camera, v2 pos,
v2 size, f32 thickness, v2 pivotPoint,
Radians rotate, RenderTex *renderTex, v4 color,
i32 zDepth, RenderFlags flags)
{
// TODO(doyle): Pivot point is probably not correct!
// TODO(doyle): Rotation doesn't work!
ASSERT(rotate == 0);
/* Bottom line */
renderer_rect(renderer, camera, pos, V2(size.w, thickness), pivotPoint,
rotate, renderTex, color, zDepth, flags);
/* Top line */
v2 topP = v2_add(pos, V2(0, size.h - thickness));
renderer_rect(renderer, camera, topP, V2(size.w, thickness), pivotPoint,
rotate, renderTex, color, zDepth, flags);
/* Left line */
renderer_rect(renderer, camera, pos, V2(thickness, size.h), pivotPoint,
rotate, renderTex, color, zDepth, flags);
/* Right line */
v2 rightP = v2_add(pos, V2(size.w - thickness, 0));
renderer_rect(renderer, camera, rightP, V2(thickness, size.h), pivotPoint,
rotate, renderTex, color, zDepth, flags);
}
inline void renderer_rectFixed(Renderer *const renderer, v2 pos, v2 size,
v2 pivotPoint, Radians rotate,
@ -113,6 +135,23 @@ inline void renderer_rectFixed(Renderer *const renderer, v2 pos, v2 size,
renderTex, color, zDepth, flags);
}
inline void renderer_rectFixedOutline(Renderer *const renderer, v2 pos, v2 size,
v2 pivotPoint, f32 thickness,
Radians rotate, RenderTex *renderTex,
v4 color, i32 zDepth, RenderFlags flags)
{
Rect staticCamera = {V2(0, 0), renderer->size};
renderer_rectOutline(renderer, staticCamera, pos, size, thickness,
pivotPoint, rotate, renderTex, color, zDepth, flags);
}
void renderer_polygon(Renderer *const renderer, Rect camera, v2 *polygonPoints,
i32 numPoints, v2 pivotPoint, Radians rotate,
RenderTex *renderTex, v4 color, i32 zDepth,
RenderFlags flags);
void renderer_string(Renderer *const renderer, MemoryArena_ *arena, Rect camera,
Font *const font, const char *const string, v2 pos,
v2 pivotPoint, Radians rotate, v4 color, i32 zDepth,