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
*/
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);
v2 oldDp = entity->dP;
v2 resistance = v2_scale(oldDp, 2.0f);
@ -418,39 +426,133 @@ INTERNAL u32 moveEntity(World *world, MemoryArena_ *transientArena,
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++;
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++];
asteroid->id = world->entityIdCounter++;
i32 randValue = rand();
i32 randX = (randValue % (i32)windowSize.w);
i32 randY = (randValue % (i32)windowSize.h);
asteroid->pos = V2i(randX, randY);
if (!spec)
{
i32 randX = (randValue % (i32)world->worldSize.w);
i32 randY = (randValue % (i32)world->worldSize.h);
asteroid->size = V2(100.0f, 100.0f);
asteroid->hitbox = asteroid->size;
asteroid->offset = v2_scale(asteroid->size, -0.5f);
asteroid->type = entitytype_asteroid;
asteroid->direction = direction_null;
asteroid->renderMode = rendermode_polygon;
v2 midpoint = v2_scale(world->worldSize, 0.5f);
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;
i32 cacheIndex = randValue % ARRAY_COUNT(world->asteroidVertexCache);
if (!world->asteroidVertexCache[cacheIndex])
i32 cacheIndex = randValue % ARRAY_COUNT(world->asteroidSmallVertexCache);
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,
(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);
}
INTERNAL void addAsteroid(World *world, enum AsteroidSize asteroidSize)
{
addAsteroidWithSpec(world, asteroidSize, NULL);
}
INTERNAL void addBullet(World *world, Entity *shooter)
{
Entity *bullet = &world->entityList[world->entityIndex++];
@ -570,9 +672,18 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
}
{ // Global Collision Rules
setCollisionRule(world, entitytype_ship, entitytype_asteroid, TRUE);
setCollisionRule(world, entitytype_bullet, entitytype_asteroid,
setCollisionRule(world, entitytype_ship, entitytype_asteroid_small,
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);
@ -586,7 +697,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
}
for (u32 i = world->asteroidCounter; i < world->numAsteroids; i++)
addAsteroid(world, windowSize);
addAsteroid(world, (rand() % asteroidsize_count));
{
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],
readkeytype_repeat, 0.2f, dt))
{
addAsteroid(world, windowSize);
addAsteroid(world, (rand() % asteroidsize_count));
}
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;
DEBUG_PUSH_VAR("Pos: %5.2f, %5.2f", entity->pos, "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,
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();
@ -704,12 +808,8 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
v2 ddP = {0};
switch (entity->direction)
{
case direction_north:
{
ddP.y = 1.0f;
}
break;
case direction_north:
case direction_northwest:
{
ddP.x = 1.0f;
@ -718,11 +818,6 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
break;
case direction_west:
{
ddP.x = -1.0f;
}
break;
case direction_southwest:
{
ddP.x = -1.0f;
@ -731,11 +826,6 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
break;
case direction_south:
{
ddP.y = -1.0f;
}
break;
case direction_southeast:
{
ddP.x = 1.0f;
@ -744,11 +834,6 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
break;
case direction_east:
{
ddP.x = 1.0f;
}
break;
case direction_northeast:
{
ddP.x = 1.0f;
@ -763,8 +848,9 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
break;
}
f32 dirOffset = ((randValue % 10) + 1) / 100.0f;
v2_scale(ddP, dirOffset);
f32 dirOffsetX = ((randValue % 10) + 1) / 100.0f;
f32 dirOffsetY = ((randValue % 10) + 1) / 100.0f;
v2_hadamard(ddP, V2(dirOffsetX, dirOffsetY));
// NOTE(doyle): Make asteroids start and move at constant speed by
// 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)
entity->pos.y = 0;
else if (entity->pos.y < 0)
@ -823,8 +909,34 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
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);
world->entityList[collisionIndex] =
world->entityList[--world->entityIndex];
@ -836,7 +948,6 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
AudioRenderer *audioRenderer = getFreeAudioRenderer(world);
if (audioRenderer)
{
char *sound;
i32 choice = rand() % 3;
if (choice == 0)

View File

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

View File

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

View File

@ -23,13 +23,41 @@ enum Direction
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
enum EntityType
{
entitytype_invalid,
entitytype_null,
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_count,
};

View File

@ -5,10 +5,12 @@
#include "Dengine/Common.h"
#define MATH_PI 3.14159265359f
#define SQUARED(x) (x * x)
#define ABS(x) ((x) > 0 ? (x) : -(x))
#define DEGREES_TO_RADIANS(x) ((x * (MATH_PI / 180.0f)))
#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))
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; } \
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; \
for (i32 i = 0; i < ##num; i++) { result.e[i] = a.e[i] * b.e[i]; } \