Add levelling
This commit is contained in:
110
game.c
110
game.c
@@ -8,7 +8,6 @@
|
||||
#include <assert.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SHIP_COLLIDE_R 0.05
|
||||
@@ -17,14 +16,14 @@
|
||||
#define FIRE_MEAN -0.15
|
||||
#define FIRE_JITTER 0.01
|
||||
|
||||
#define INIT_LEVEL 1
|
||||
|
||||
#define ASTEROID_MIN_VERTS 5
|
||||
#define ASTEROID_MAX_VERTS 8
|
||||
#define ASTEROID_VERT_RANGE (ASTEROID_MAX_VERTS - ASTEROID_MIN_VERTS)
|
||||
#define ASTEROID_A_JITTER 0.8
|
||||
#define ASTEROID_VEL_JITTER 0.001
|
||||
#define ASTEROID_OMG_JITTER 0.005
|
||||
#define INIT_ASTEROIDS 1
|
||||
|
||||
#define ASTEROID_SMALL 0.05f
|
||||
#define ASTEROID_MEDIUM 0.1f
|
||||
#define ASTEROID_LARGE 0.2f
|
||||
@@ -54,6 +53,10 @@
|
||||
#define MAX_SHAPES_PER_ENTITY 2
|
||||
#define MAX_COLLISIONS 128U
|
||||
|
||||
#define ARROW_SCALE 0.025
|
||||
#define ARROW_WIDTH 4
|
||||
#define ARROW_HEIGHT 4
|
||||
|
||||
#define COUNTER_MASK (1 << 6)
|
||||
|
||||
#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
@@ -103,6 +106,12 @@ static const vec2_t fire_verts[] = {
|
||||
};
|
||||
static const vec2_t shot_verts[] = { { 0.0, -0.02 }, { 0.0, 0.02 } };
|
||||
|
||||
static const vec2_t arrow_verts[][MAX_VERTS] = {
|
||||
{ { 1, 2 }, { 2, 0 }, { 1, -2 } },
|
||||
{ { -2, 0 }, { 2, 0 } },
|
||||
};
|
||||
static const unsigned arrow_counts[NELEMS(arrow_verts)] = { 3, 2 };
|
||||
|
||||
static entity_t entities[MAX_ENTITIES];
|
||||
static mat3_t transforms[MAX_ENTITIES];
|
||||
static shape_t shapes[MAX_SHAPES];
|
||||
@@ -110,25 +119,22 @@ static shape_t shapes[MAX_SHAPES];
|
||||
static unsigned entity_count;
|
||||
static unsigned shape_count;
|
||||
|
||||
static float aspect;
|
||||
static unsigned level;
|
||||
|
||||
static bool dead;
|
||||
static unsigned asteroid_count;
|
||||
static float aspect;
|
||||
static uint8_t counter;
|
||||
|
||||
static unsigned ship_entity_id;
|
||||
static unsigned ship_shape_id;
|
||||
static unsigned fire_shape_id;
|
||||
|
||||
static void restart()
|
||||
{
|
||||
game_init(aspect);
|
||||
}
|
||||
|
||||
static entity_t *add_entity(unsigned *id_out)
|
||||
{
|
||||
const unsigned id = entity_count++;
|
||||
memset(entities + id, 0, sizeof(entity_t));
|
||||
entities[id].dir = (mat2_t) { { 1, 0 }, { 0, 1 } };
|
||||
entities[id].dir = MAT2_ID;
|
||||
if (id_out != nullptr)
|
||||
*id_out = id;
|
||||
return entities + id;
|
||||
@@ -340,20 +346,28 @@ static void bounce(collision_t c)
|
||||
b->vel = vec2_add(b->vel, vec2_scale(n, vb2 - vb1));
|
||||
}
|
||||
|
||||
static void cleared()
|
||||
{
|
||||
renderer_set_wrap(false);
|
||||
}
|
||||
|
||||
static void destroy_asteroid(entity_t *a, vec2_t shot_vel)
|
||||
{
|
||||
a->dead = true;
|
||||
--asteroid_count;
|
||||
|
||||
float r;
|
||||
if (a->radius == ASTEROID_HUGE)
|
||||
if (a->radius == ASTEROID_HUGE) {
|
||||
r = ASTEROID_LARGE;
|
||||
else if (a->radius == ASTEROID_LARGE)
|
||||
} else if (a->radius == ASTEROID_LARGE) {
|
||||
r = ASTEROID_MEDIUM;
|
||||
else if (a->radius == ASTEROID_MEDIUM)
|
||||
} else if (a->radius == ASTEROID_MEDIUM) {
|
||||
r = ASTEROID_SMALL;
|
||||
else
|
||||
} else {
|
||||
if (asteroid_count == 0)
|
||||
cleared();
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned n = REPLACE_MIN + rng_uint32() % REPLACE_RANGE;
|
||||
const float da = 2 * PI / n;
|
||||
@@ -383,8 +397,6 @@ static void destroy_asteroid(entity_t *a, vec2_t shot_vel)
|
||||
|
||||
++asteroid_count;
|
||||
}
|
||||
|
||||
printf("asteroid count: %u\n", asteroid_count);
|
||||
}
|
||||
|
||||
static void handle_collisions(const collision_t *collisions, unsigned count)
|
||||
@@ -423,12 +435,27 @@ static void handle_collisions(const collision_t *collisions, unsigned count)
|
||||
}
|
||||
}
|
||||
|
||||
void game_init(float _aspect)
|
||||
static void draw_arrow()
|
||||
{
|
||||
input_on_shoot(shoot);
|
||||
input_on_restart(restart);
|
||||
const float tx = aspect - ARROW_SCALE * (ARROW_WIDTH / 2.0 + 2);
|
||||
const mat3_t m = {
|
||||
{ ARROW_SCALE, 0, 0 },
|
||||
{ 0, ARROW_SCALE, 0 },
|
||||
{ tx, 0, 1 },
|
||||
};
|
||||
|
||||
aspect = _aspect;
|
||||
const vec3_t c_mod = { 0, 0, 1 };
|
||||
const vec3_t s_mod = { ARROW_WIDTH + 2, ARROW_HEIGHT + 2, 0 };
|
||||
const vec3_t c = mat3_mul_vec3(m, c_mod);
|
||||
const vec3_t s = mat3_mul_vec3(m, s_mod);
|
||||
renderer_clear_rect(vec3_reduce(c), (vec2_t) { s.x, s.y });
|
||||
|
||||
for (unsigned i = 0; i < NELEMS(arrow_verts); ++i)
|
||||
renderer_draw(arrow_verts[i], arrow_counts[i], m, false);
|
||||
}
|
||||
|
||||
static void create_field()
|
||||
{
|
||||
dead = false;
|
||||
counter = 0;
|
||||
entity_count = shape_count = 0;
|
||||
@@ -450,19 +477,38 @@ void game_init(float _aspect)
|
||||
fire->vert_count = NELEMS(fire_verts);
|
||||
memcpy(fire->verts, fire_verts, sizeof(fire_verts));
|
||||
|
||||
for (unsigned i = 0; i < INIT_ASTEROIDS; ++i)
|
||||
for (unsigned i = 0; i < level; ++i)
|
||||
spawn_asteroid();
|
||||
}
|
||||
|
||||
static void win()
|
||||
{
|
||||
renderer_set_wrap(true);
|
||||
++level;
|
||||
create_field();
|
||||
}
|
||||
|
||||
static void reset()
|
||||
{
|
||||
level = INIT_LEVEL;
|
||||
create_field();
|
||||
}
|
||||
|
||||
void game_init(float _aspect)
|
||||
{
|
||||
input_on_shoot(shoot);
|
||||
input_on_restart(reset);
|
||||
aspect = _aspect;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void game_update()
|
||||
{
|
||||
if (dead) {
|
||||
if (dead || asteroid_count == 0)
|
||||
++counter;
|
||||
if (dead)
|
||||
return;
|
||||
}
|
||||
|
||||
if (asteroid_count == 0 && counter <= COUNTER_MASK)
|
||||
++counter;
|
||||
|
||||
ship_update();
|
||||
|
||||
@@ -472,6 +518,11 @@ void game_update()
|
||||
e->dir = mat2_mul_mat2(mat2_rotation(e->omg), e->dir);
|
||||
e->pos = vec2_add(e->pos, e->vel);
|
||||
|
||||
if (asteroid_count == 0 && i == ship_entity_id) {
|
||||
if (e->pos.x > aspect)
|
||||
win();
|
||||
}
|
||||
|
||||
if (e->pos.y > 1)
|
||||
e->pos.y -= 2;
|
||||
else if (e->pos.y <= -1)
|
||||
@@ -507,6 +558,9 @@ void game_draw()
|
||||
if (dead && !(counter & COUNTER_MASK))
|
||||
text_draw("GAME OVER");
|
||||
|
||||
if (asteroid_count == 0 && counter < COUNTER_MASK)
|
||||
text_draw("CLEAR");
|
||||
if (!dead && asteroid_count == 0) {
|
||||
draw_arrow();
|
||||
if (!(counter & COUNTER_MASK))
|
||||
text_draw("CLEAR");
|
||||
}
|
||||
}
|
||||
|
||||
5
maths.c
5
maths.c
@@ -41,6 +41,11 @@ float vec2_dot(vec2_t v1, vec2_t v2)
|
||||
return v1.x * v2.x + v1.y * v2.y;
|
||||
}
|
||||
|
||||
vec2_t vec3_reduce(vec3_t v)
|
||||
{
|
||||
return (vec2_t) { v.x / v.z, v.y / v.z };
|
||||
}
|
||||
|
||||
mat2_t mat2_rotation(float theta)
|
||||
{
|
||||
return (mat2_t) {
|
||||
|
||||
5
maths.h
5
maths.h
@@ -3,6 +3,9 @@
|
||||
|
||||
#define PI 3.14159265358979323846264
|
||||
|
||||
#define MAT2_ID ((mat2_t) { { 1, 0 }, { 0, 1 } })
|
||||
#define MAT3_ID ((mat3_t) { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } })
|
||||
|
||||
typedef struct {
|
||||
float x, y;
|
||||
} vec2_t;
|
||||
@@ -27,6 +30,8 @@ vec3_t vec2_extend(vec2_t v);
|
||||
vec2_t vec2_norm(vec2_t v);
|
||||
float vec2_dot(vec2_t v1, vec2_t v2);
|
||||
|
||||
vec2_t vec3_reduce(vec3_t v);
|
||||
|
||||
mat2_t mat2_rotation(float theta);
|
||||
vec2_t mat2_mul_vec2(mat2_t m, vec2_t v);
|
||||
mat2_t mat2_mul_mat2(mat2_t m1, mat2_t m2);
|
||||
|
||||
38
renderer.c
38
renderer.c
@@ -20,6 +20,8 @@ static int front, back;
|
||||
static uint32_t width, height;
|
||||
static mat3_t view;
|
||||
|
||||
static bool wrap;
|
||||
|
||||
static vec3_t vert_buf[MAX_VERTS];
|
||||
|
||||
static void page_flip_handler(int, unsigned, unsigned, unsigned, void *)
|
||||
@@ -34,6 +36,13 @@ static void set_pixel(uint32_t x, uint32_t y)
|
||||
|
||||
static void draw_line(vec3_t v1, vec3_t v2)
|
||||
{
|
||||
v1.x /= v1.z;
|
||||
v1.y /= v1.z;
|
||||
v1.z = 1;
|
||||
v2.x /= v2.z;
|
||||
v2.y /= v2.z;
|
||||
v2.z = 1;
|
||||
|
||||
const float delta_x = v2.x - v1.x;
|
||||
const float delta_y = v2.y - v1.y;
|
||||
const float step = fmaxf(fabsf(delta_x), fabsf(delta_y));
|
||||
@@ -43,16 +52,20 @@ static void draw_line(vec3_t v1, vec3_t v2)
|
||||
|
||||
for (unsigned i = 0; i <= step; ++i) {
|
||||
float x = roundf(v1.x + i * step_x);
|
||||
if (x >= width)
|
||||
x -= width;
|
||||
else if (x < 0)
|
||||
x += width;
|
||||
|
||||
float y = roundf(v1.y + i * step_y);
|
||||
if (y >= height)
|
||||
y -= height;
|
||||
else if (y < 0)
|
||||
y += height;
|
||||
|
||||
if (wrap) {
|
||||
if (x >= width)
|
||||
x -= width;
|
||||
else if (x < 0)
|
||||
x += width;
|
||||
if (y >= height)
|
||||
y -= height;
|
||||
else if (y < 0)
|
||||
y += height;
|
||||
} else if (x >= width || x < 0 || y >= height || y < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
set_pixel(x, y);
|
||||
}
|
||||
@@ -89,6 +102,8 @@ renderer_params_t renderer_init()
|
||||
width = mode.hdisplay;
|
||||
height = mode.vdisplay;
|
||||
|
||||
wrap = true;
|
||||
|
||||
const float aspect = (float)width / (float)height;
|
||||
const float scale = (float)height / 2.0f;
|
||||
view = (mat3_t) {
|
||||
@@ -136,6 +151,11 @@ void renderer_swap()
|
||||
back = (back + 1) & 1;
|
||||
}
|
||||
|
||||
void renderer_set_wrap(bool enable)
|
||||
{
|
||||
wrap = enable;
|
||||
}
|
||||
|
||||
void renderer_clear()
|
||||
{
|
||||
memset(fbs[back].buf, 0, fbs[back].size);
|
||||
|
||||
@@ -18,9 +18,9 @@ void renderer_cleanup();
|
||||
void renderer_handle();
|
||||
void renderer_swap();
|
||||
|
||||
void renderer_set_wrap(bool enable);
|
||||
void renderer_clear();
|
||||
void renderer_clear_rect(vec2_t centre, vec2_t size);
|
||||
|
||||
void renderer_draw(
|
||||
const vec2_t *vs, unsigned count, mat3_t model, bool connect);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user