Add Asteroid sizing and asteroid split on destroy

This commit is contained in:
Doyle Thai 2016-11-25 13:17:24 +11:00
parent ea6ea02404
commit 6bc37dbe44
5 changed files with 201 additions and 58 deletions

View File

@ -341,6 +341,14 @@ INTERNAL u32 moveEntity(World *world, MemoryArena_ *transientArena,
newPos = (a*t^2)/2 + oldVelocity*t + oldPos newPos = (a*t^2)/2 + oldVelocity*t + oldPos
*/ */
if (ddP.x > 0.0f && ddP.y > 0.0f)
{
// NOTE(doyle): Cheese it and pre-compute the vector for
// diagonal using pythagoras theorem on a unit triangle 1^2
// + 1^2 = c^2
ddP = v2_scale(ddP, 0.70710678118f);
}
ddP = v2_scale(ddP, world->pixelsPerMeter * ddPSpeed); ddP = v2_scale(ddP, world->pixelsPerMeter * ddPSpeed);
v2 oldDp = entity->dP; v2 oldDp = entity->dP;
v2 resistance = v2_scale(oldDp, 2.0f); v2 resistance = v2_scale(oldDp, 2.0f);
@ -418,39 +426,133 @@ INTERNAL u32 moveEntity(World *world, MemoryArena_ *transientArena,
return collisionIndex; return collisionIndex;
} }
INTERNAL void addAsteroid(World *world, v2 windowSize) enum AsteroidSize
{
asteroidsize_small,
asteroidsize_medium,
asteroidsize_large,
asteroidsize_count,
};
typedef struct {
v2 pos;
v2 dP;
enum Direction direction;
} AsteroidSpec;
INTERNAL void addAsteroidWithSpec(World *world, enum AsteroidSize asteroidSize,
AsteroidSpec *spec)
{ {
world->asteroidCounter++; world->asteroidCounter++;
enum EntityType type;
v2 size;
v2 **vertexCache = NULL;
if (asteroidSize == asteroidsize_small)
{
size = V2i(25, 25);
type = entitytype_asteroid_small;
vertexCache = world->asteroidSmallVertexCache;
}
else if (asteroidSize == asteroidsize_medium)
{
size = V2i(50, 50);
type = entitytype_asteroid_medium;
vertexCache = world->asteroidMediumVertexCache;
}
else if (asteroidSize == asteroidsize_large)
{
type = entitytype_asteroid_large;
size = V2i(100, 100);
vertexCache = world->asteroidLargeVertexCache;
}
else
{
ASSERT(INVALID_CODE_PATH);
}
Entity *asteroid = &world->entityList[world->entityIndex++]; Entity *asteroid = &world->entityList[world->entityIndex++];
asteroid->id = world->entityIdCounter++; asteroid->id = world->entityIdCounter++;
i32 randValue = rand(); i32 randValue = rand();
i32 randX = (randValue % (i32)windowSize.w); if (!spec)
i32 randY = (randValue % (i32)windowSize.h); {
asteroid->pos = V2i(randX, randY); i32 randX = (randValue % (i32)world->worldSize.w);
i32 randY = (randValue % (i32)world->worldSize.h);
asteroid->size = V2(100.0f, 100.0f); v2 midpoint = v2_scale(world->worldSize, 0.5f);
asteroid->hitbox = asteroid->size;
asteroid->offset = v2_scale(asteroid->size, -0.5f);
asteroid->type = entitytype_asteroid;
asteroid->direction = direction_null;
asteroid->renderMode = rendermode_polygon;
Rect topLeftQuadrant = {V2(0, midpoint.y),
V2(midpoint.x, world->worldSize.y)};
Rect botLeftQuadrant = {V2(0, 0), midpoint};
Rect topRightQuadrant = {midpoint, world->worldSize};
Rect botRightQuadrant = {V2(midpoint.x, 0),
V2(world->worldSize.x, midpoint.y)};
// NOTE(doyle): Off-screen so asteroids "float" into view. There's no
// particular order, just pushing things offscreen when they get
// generated
// to float back into game space
v2 newP = V2i(randX, randY);
if (math_pointInRect(topLeftQuadrant, newP))
{
newP.y += midpoint.y;
}
else if (math_pointInRect(botLeftQuadrant, newP))
{
newP.x -= midpoint.x;
}
else if (math_pointInRect(topRightQuadrant, newP))
{
newP.y -= midpoint.y;
}
else if (math_pointInRect(botRightQuadrant, newP))
{
newP.x += midpoint.x;
}
else
{
ASSERT(INVALID_CODE_PATH);
}
asteroid->pos = newP;
asteroid->direction = direction_null;
}
else
{
asteroid->pos = spec->pos;
asteroid->direction = spec->direction;
}
asteroid->size = size;
asteroid->hitbox = asteroid->size;
asteroid->offset = v2_scale(asteroid->size, -0.5f);
asteroid->type = type;
asteroid->renderMode = rendermode_polygon;
asteroid->numVertexPoints = 10; asteroid->numVertexPoints = 10;
i32 cacheIndex = randValue % ARRAY_COUNT(world->asteroidVertexCache); i32 cacheIndex = randValue % ARRAY_COUNT(world->asteroidSmallVertexCache);
if (!world->asteroidVertexCache[cacheIndex]) ASSERT(ARRAY_COUNT(world->asteroidSmallVertexCache) ==
ARRAY_COUNT(world->asteroidMediumVertexCache));
ASSERT(ARRAY_COUNT(world->asteroidSmallVertexCache) ==
ARRAY_COUNT(world->asteroidLargeVertexCache));
if (!vertexCache[cacheIndex])
{ {
world->asteroidVertexCache[cacheIndex] = createAsteroidVertexList( vertexCache[cacheIndex] = createAsteroidVertexList(
&world->entityArena, asteroid->numVertexPoints, &world->entityArena, asteroid->numVertexPoints,
(i32)(asteroid->size.w * 0.5f)); (i32)(asteroid->size.w * 0.5f));
} }
asteroid->vertexPoints = world->asteroidVertexCache[cacheIndex]; asteroid->vertexPoints = vertexCache[cacheIndex];
asteroid->color = V4(0.0f, 0.5f, 0.5f, 1.0f); asteroid->color = V4(0.0f, 0.5f, 0.5f, 1.0f);
} }
INTERNAL void addAsteroid(World *world, enum AsteroidSize asteroidSize)
{
addAsteroidWithSpec(world, asteroidSize, NULL);
}
INTERNAL void addBullet(World *world, Entity *shooter) INTERNAL void addBullet(World *world, Entity *shooter)
{ {
Entity *bullet = &world->entityList[world->entityIndex++]; Entity *bullet = &world->entityList[world->entityIndex++];
@ -570,9 +672,18 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
} }
{ // Global Collision Rules { // Global Collision Rules
setCollisionRule(world, entitytype_ship, entitytype_asteroid, TRUE); setCollisionRule(world, entitytype_ship, entitytype_asteroid_small,
setCollisionRule(world, entitytype_bullet, entitytype_asteroid,
TRUE); TRUE);
setCollisionRule(world, entitytype_ship, entitytype_asteroid_medium,
TRUE);
setCollisionRule(world, entitytype_ship, entitytype_asteroid_large,
TRUE);
setCollisionRule(world, entitytype_bullet,
entitytype_asteroid_small, TRUE);
setCollisionRule(world, entitytype_bullet,
entitytype_asteroid_medium, TRUE);
setCollisionRule(world, entitytype_bullet,
entitytype_asteroid_large, TRUE);
} }
world->camera.min = V2(0, 0); world->camera.min = V2(0, 0);
@ -586,7 +697,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
} }
for (u32 i = world->asteroidCounter; i < world->numAsteroids; i++) for (u32 i = world->asteroidCounter; i < world->numAsteroids; i++)
addAsteroid(world, windowSize); addAsteroid(world, (rand() % asteroidsize_count));
{ {
KeyState *keys = state->input.keys; KeyState *keys = state->input.keys;
@ -616,7 +727,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
if (getKeyStatus(&state->input.keys[keycode_left_square_bracket], if (getKeyStatus(&state->input.keys[keycode_left_square_bracket],
readkeytype_repeat, 0.2f, dt)) readkeytype_repeat, 0.2f, dt))
{ {
addAsteroid(world, windowSize); addAsteroid(world, (rand() % asteroidsize_count));
} }
ASSERT(world->entityList[0].id == NULL_ENTITY_ID); ASSERT(world->entityList[0].id == NULL_ENTITY_ID);
@ -674,14 +785,6 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
} }
} }
if (ddP.x > 0.0f && ddP.y > 0.0f)
{
// NOTE(doyle): Cheese it and pre-compute the vector for
// diagonal using pythagoras theorem on a unit triangle 1^2
// + 1^2 = c^2
ddP = v2_scale(ddP, 0.70710678118f);
}
ddPSpeedInMs = 25; ddPSpeedInMs = 25;
DEBUG_PUSH_VAR("Pos: %5.2f, %5.2f", entity->pos, "v2"); DEBUG_PUSH_VAR("Pos: %5.2f, %5.2f", entity->pos, "v2");
DEBUG_PUSH_VAR("Velocity: %5.2f, %5.2f", entity->dP, "v2"); DEBUG_PUSH_VAR("Velocity: %5.2f, %5.2f", entity->dP, "v2");
@ -692,7 +795,8 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
DEGREES_TO_RADIANS(entity->rotation), NULL, DEGREES_TO_RADIANS(entity->rotation), NULL,
V4(1.0f, 1.0f, 1.0f, 1.0f), renderflag_no_texture); V4(1.0f, 1.0f, 1.0f, 1.0f), renderflag_no_texture);
} }
else if (entity->type == entitytype_asteroid) else if (entity->type >= entitytype_asteroid_small &&
entity->type <= entitytype_asteroid_large)
{ {
i32 randValue = rand(); i32 randValue = rand();
@ -704,12 +808,8 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
v2 ddP = {0}; v2 ddP = {0};
switch (entity->direction) switch (entity->direction)
{ {
case direction_north:
{
ddP.y = 1.0f;
}
break;
case direction_north:
case direction_northwest: case direction_northwest:
{ {
ddP.x = 1.0f; ddP.x = 1.0f;
@ -718,11 +818,6 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
break; break;
case direction_west: case direction_west:
{
ddP.x = -1.0f;
}
break;
case direction_southwest: case direction_southwest:
{ {
ddP.x = -1.0f; ddP.x = -1.0f;
@ -731,11 +826,6 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
break; break;
case direction_south: case direction_south:
{
ddP.y = -1.0f;
}
break;
case direction_southeast: case direction_southeast:
{ {
ddP.x = 1.0f; ddP.x = 1.0f;
@ -744,11 +834,6 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
break; break;
case direction_east: case direction_east:
{
ddP.x = 1.0f;
}
break;
case direction_northeast: case direction_northeast:
{ {
ddP.x = 1.0f; ddP.x = 1.0f;
@ -763,8 +848,9 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
break; break;
} }
f32 dirOffset = ((randValue % 10) + 1) / 100.0f; f32 dirOffsetX = ((randValue % 10) + 1) / 100.0f;
v2_scale(ddP, dirOffset); f32 dirOffsetY = ((randValue % 10) + 1) / 100.0f;
v2_hadamard(ddP, V2(dirOffsetX, dirOffsetY));
// NOTE(doyle): Make asteroids start and move at constant speed by // NOTE(doyle): Make asteroids start and move at constant speed by
// ensuring that dP is "refreshed" with non-decaying acceleration // ensuring that dP is "refreshed" with non-decaying acceleration
@ -788,7 +874,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
} }
// Loop entity around world /* Loop entity around world */
if (entity->pos.y >= world->worldSize.h) if (entity->pos.y >= world->worldSize.h)
entity->pos.y = 0; entity->pos.y = 0;
else if (entity->pos.y < 0) else if (entity->pos.y < 0)
@ -823,8 +909,34 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
colliderB = collideEntity; colliderB = collideEntity;
} }
if (colliderA->type == entitytype_asteroid) if (colliderA->type >= entitytype_asteroid_small &&
colliderA->type <= entitytype_asteroid_large)
{ {
if (colliderA->type == entitytype_asteroid_medium)
{
AsteroidSpec spec = {0};
spec.pos = colliderA->pos;
spec.dP = v2_scale(colliderA->dP, -1.0f);
spec.direction = invertDirection(colliderA->direction);
addAsteroidWithSpec(world, asteroidsize_small, &spec);
}
else if (colliderA->type == entitytype_asteroid_large)
{
AsteroidSpec spec = {0};
spec.pos = colliderA->pos;
spec.dP = v2_scale(colliderA->dP, -1.0f);
spec.direction = invertDirection(colliderA->direction);
addAsteroidWithSpec(world, asteroidsize_medium, &spec);
spec.dP = v2_perpendicular(spec.dP);
spec.direction = rotateDirectionWest90(spec.direction);
addAsteroidWithSpec(world, asteroidsize_small, &spec);
spec.dP = v2_perpendicular(colliderA->dP);
spec.direction = invertDirection(spec.direction);
addAsteroidWithSpec(world, asteroidsize_small, &spec);
}
ASSERT(colliderB->type == entitytype_bullet); ASSERT(colliderB->type == entitytype_bullet);
world->entityList[collisionIndex] = world->entityList[collisionIndex] =
world->entityList[--world->entityIndex]; world->entityList[--world->entityIndex];
@ -836,7 +948,6 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
AudioRenderer *audioRenderer = getFreeAudioRenderer(world); AudioRenderer *audioRenderer = getFreeAudioRenderer(world);
if (audioRenderer) if (audioRenderer)
{ {
char *sound; char *sound;
i32 choice = rand() % 3; i32 choice = rand() % 3;
if (choice == 0) if (choice == 0)

View File

@ -163,8 +163,8 @@ i32 main(void)
******************* *******************
*/ */
Memory memory = {0}; Memory memory = {0};
MemoryIndex persistentSize = MEGABYTES(128); MemoryIndex persistentSize = MEGABYTES(32);
MemoryIndex transientSize = MEGABYTES(128); MemoryIndex transientSize = MEGABYTES(32);
memory.persistentSize = persistentSize; memory.persistentSize = persistentSize;
memory.persistent = PLATFORM_MEM_ALLOC_(NULL, persistentSize, u8); memory.persistent = PLATFORM_MEM_ALLOC_(NULL, persistentSize, u8);

View File

@ -20,8 +20,10 @@ typedef struct World
u32 asteroidCounter; u32 asteroidCounter;
u32 numAsteroids; u32 numAsteroids;
v2 *asteroidSmallVertexCache[3];
v2 *asteroidMediumVertexCache[3];
v2 *asteroidLargeVertexCache[3];
v2 *asteroidVertexCache[10];
v2 *bulletVertexCache; v2 *bulletVertexCache;
// TODO(doyle): Audio mixing instead of multiple renderers // TODO(doyle): Audio mixing instead of multiple renderers

View File

@ -23,13 +23,41 @@ enum Direction
direction_num, direction_num,
}; };
INTERNAL inline enum Direction invertDirection(enum Direction direction)
{
enum Direction result = (direction + 4) % direction_count;
return result;
}
INTERNAL inline enum Direction rotateDirectionWest90(enum Direction direction)
{
enum Direction result = (direction + 2) % direction_count;
return result;
}
INTERNAL inline enum Direction rotateDirectionEast90(enum Direction direction)
{
enum Direction result = (direction + 2) % direction_count;
return result;
}
#define NULL_ENTITY_ID 0 #define NULL_ENTITY_ID 0
enum EntityType enum EntityType
{ {
entitytype_invalid, entitytype_invalid,
entitytype_null, entitytype_null,
entitytype_ship, entitytype_ship,
entitytype_asteroid,
// NOTE(doyle): Asteroids must be grouped since we use >= and <= logic to
// combine asteroid logic together
entitytype_asteroid_small,
entitytype_asteroid_medium,
entitytype_asteroid_large,
entitytype_bullet, entitytype_bullet,
entitytype_count, entitytype_count,
}; };

View File

@ -5,10 +5,12 @@
#include "Dengine/Common.h" #include "Dengine/Common.h"
#define MATH_PI 3.14159265359f #define MATH_PI 3.14159265359f
#define SQUARED(x) (x * x)
#define ABS(x) ((x) > 0 ? (x) : -(x)) #define ABS(x) ((x) > 0 ? (x) : -(x))
#define DEGREES_TO_RADIANS(x) ((x * (MATH_PI / 180.0f))) #define DEGREES_TO_RADIANS(x) ((x * (MATH_PI / 180.0f)))
#define RADIANS_TO_DEGREES(x) ((x * (180.0f / MATH_PI))) #define RADIANS_TO_DEGREES(x) ((x * (180.0f / MATH_PI)))
#define MAX(a, b) ((a) < (b) ? (b) : (a))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define SQUARED(x) ((x) * (x))
#define SQRT(x) (sqrtf(x)) #define SQRT(x) (sqrtf(x))
typedef f32 Radians; typedef f32 Radians;
@ -137,7 +139,7 @@ INTERNAL inline v##num v##num##_scale(const v##num a, const f32 b) \
for (i32 i = 0; i < ##num; i++) { result.e[i] = a.e[i] * b; } \ for (i32 i = 0; i < ##num; i++) { result.e[i] = a.e[i] * b; } \
return result; \ return result; \
} \ } \
INTERNAL inline v##num v##num##_mul(const v##num a, const v##num b) \ INTERNAL inline v##num v##num##_hadamard(const v##num a, const v##num b) \
{ \ { \
v##num result; \ v##num result; \
for (i32 i = 0; i < ##num; i++) { result.e[i] = a.e[i] * b.e[i]; } \ for (i32 i = 0; i < ##num; i++) { result.e[i] = a.e[i] * b.e[i]; } \