diff --git a/CMakeLists.txt b/CMakeLists.txt index b528101..ff3e9dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ include_directories(inc) set(SOURCES src/main.c + src/vec.c src/util.c src/draw.c src/input.c @@ -19,6 +20,7 @@ set(SOURCES src/player.c src/polarity.c src/time.c + src/missile.c ) set(ASSETS diff --git a/inc/conf.h b/inc/conf.h index 5e57133..495eb0f 100644 --- a/inc/conf.h +++ b/inc/conf.h @@ -22,3 +22,6 @@ #define BOUNCE_SPEED -2.0f #define DRAW_OFF_X -2 #define GRAVS_MARGIN 0 +#define MISSILE_MAX_SPEED 4.0f +#define MISSILE_ACCEL 0.06f +#define MISSILE_FRICTION (MISSILE_ACCEL / MISSILE_MAX_SPEED) diff --git a/inc/input.h b/inc/input.h index ed0c5cf..2896117 100644 --- a/inc/input.h +++ b/inc/input.h @@ -12,6 +12,7 @@ enum Key { K_EDITOR, K_SCROLL_UP, K_SCROLL_DOWN, + K_DEBUG, K_COUNT }; enum KeyState { KS_UP, KS_DOWN, KS_PRESS }; diff --git a/inc/level.h b/inc/level.h index 24662b7..90f3ee5 100644 --- a/inc/level.h +++ b/inc/level.h @@ -39,4 +39,5 @@ int level_get_px(int x, int y); void level_set(int x, int y, int v); void level_set_px(int x, int y, int v); struct Vec level_find(enum Tile); +int level_count(enum Tile); struct Vec level_dim(void); diff --git a/inc/missile.h b/inc/missile.h new file mode 100644 index 0000000..0bd528b --- /dev/null +++ b/inc/missile.h @@ -0,0 +1,18 @@ +#pragma once +#include "vec.h" + +struct Missile { + int active; + struct VecF pos, spd; +}; + +struct MissileManager { + int n_missiles; + struct Missile *missiles; +}; + +void missile_manager_init(void); +void missile_manager_free(void); +void missile_manager_update(struct VecF target); +void missile_manager_draw(void); +struct Missile *missile_new(int x, int y); diff --git a/inc/player.h b/inc/player.h index ecb4f57..1adbafb 100644 --- a/inc/player.h +++ b/inc/player.h @@ -12,5 +12,7 @@ struct Player { void player_spawn(struct Player *); void player_update(struct Player *); -void player_draw(struct Player *); +void player_draw(const struct Player *); void player_move(struct Player *, struct Vec); + +struct Vec player_middle(const struct Player *); diff --git a/inc/tile.h b/inc/tile.h index 12befbb..dc90da5 100644 --- a/inc/tile.h +++ b/inc/tile.h @@ -16,6 +16,7 @@ enum Tile { TILE_WATER, TILE_BURN_RED, TILE_BURN_BLUE, + TILE_MISSILE_LAUNCHER, TILE_COUNT, TILE_OOB = TILE_BURN, }; diff --git a/inc/vec.h b/inc/vec.h index 11d51e5..fccf230 100644 --- a/inc/vec.h +++ b/inc/vec.h @@ -7,3 +7,8 @@ struct Vec { struct VecF { float x, y; }; + +struct VecF vecf(struct Vec); +struct Vec vec(struct VecF); + +struct VecF normalize(struct VecF); diff --git a/src/input.c b/src/input.c index e6b4718..303f67a 100644 --- a/src/input.c +++ b/src/input.c @@ -4,7 +4,7 @@ static struct Input input; static const int default_map[K_COUNT] = { KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_SHIFT, KEY_ALPHA, - KEY_EXIT, KEY_TAN, KEY_F3, KEY_F2, KEY_F1}; + KEY_EXIT, KEY_TAN, KEY_F3, KEY_F2, KEY_F1, KEY_F6}; void input_init(void) diff --git a/src/level.c b/src/level.c index 65dfef5..a1375b2 100644 --- a/src/level.c +++ b/src/level.c @@ -1,5 +1,6 @@ #include "level.h" #include "conf.h" +#include "missile.h" #include "player.h" #include "polarity.h" #include "tile.h" @@ -62,6 +63,7 @@ level_load(int id) polarity_reset(); level_regen_visual_data(0); player_spawn(level.player); + missile_manager_init(); } void @@ -169,6 +171,16 @@ level_find(enum Tile t) return (struct Vec){i % level.width, i / level.width}; } +int +level_count(enum Tile t) +{ + int c = 0; + int i = level.size; + while (i-- > 0) + c += level.data[i] == t; + return c; +} + struct Vec level_dim(void) { diff --git a/src/main.c b/src/main.c index 946c453..62f8aab 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ #include "editor.h" #include "input.h" #include "level.h" +#include "missile.h" #include "player.h" #include "time.h" #include "util.h" @@ -70,6 +71,7 @@ static void deinit(void) { level_deinit(); + missile_manager_free(); timer_stop(timer); } @@ -78,9 +80,12 @@ static void update(void) { input_update(); + missile_manager_update(vecf(player_middle(&player))); player_update(&player); /* enter editor */ if (input_pressed(K_EDITOR)) editor(); + /* debug: spawn missile */ + if (input_pressed(K_DEBUG)) missile_new(DWIDTH / 2, DHEIGHT / 2); } static void @@ -88,6 +93,7 @@ draw(void) { dclear(C_BLACK); level_draw(); + missile_manager_draw(); player_draw(&player); level_draw_name(); time_draw(); diff --git a/src/missile.c b/src/missile.c new file mode 100644 index 0000000..8c4bf9a --- /dev/null +++ b/src/missile.c @@ -0,0 +1,91 @@ +#include "missile.h" +#include "conf.h" +#include "level.h" +#include +#include + +static struct MissileManager manager = {.missiles = NULL}; + +static void missile_update(struct Missile *, struct VecF target); +static void missile_draw(const struct Missile *); + +void +missile_manager_init(void) +{ + int i; + missile_manager_free(); + /* debug: remove the `1 + ` later on */ + manager.n_missiles = 1 + level_count(TILE_MISSILE_LAUNCHER); + manager.missiles = malloc(manager.n_missiles * sizeof(struct Missile)); + + i = manager.n_missiles; + while (i-- > 0) + manager.missiles[i].active = 0; +} + +void +missile_manager_free(void) +{ + if (manager.missiles != NULL) free(manager.missiles); +} + +void +missile_manager_update(struct VecF target) +{ + int i = manager.n_missiles; + while (i-- > 0) + if (manager.missiles[i].active) + missile_update(&manager.missiles[i], target); +} + +void +missile_manager_draw(void) +{ + int i = manager.n_missiles; + while (i-- > 0) + if (manager.missiles[i].active) + missile_draw(&manager.missiles[i]); +} + +struct Missile * +missile_new(int x, int y) +{ + int i = manager.n_missiles; + struct Missile *m; + while (i-- > 0 && manager.missiles[i].active) + ; + m = &manager.missiles[(i > 0) ? (i) : (0)]; + + m->active = 1; + m->pos.x = x; + m->pos.y = y; + m->spd.x = 0.0f; + m->spd.y = 0.0f; + + return m; +} + +static void +missile_update(struct Missile *m, struct VecF target) +{ + const struct VecF diff = {target.x - m->pos.x, target.y - m->pos.y}; + const struct VecF dir = normalize(diff); + + /* acceleration */ + m->spd.x += dir.x * MISSILE_ACCEL; + m->spd.y += dir.y * MISSILE_ACCEL; + + /* friction */ + m->spd.x *= 1 - MISSILE_FRICTION; + m->spd.y *= 1 - MISSILE_FRICTION; + + /* move */ + m->pos.x += m->spd.x; + m->pos.y += m->spd.y; +} + +static void +missile_draw(const struct Missile *m) +{ + dpixel(m->pos.x + 0.5f, m->pos.y + 0.5f, C_RED); +} diff --git a/src/player.c b/src/player.c index 511638f..67b60d0 100644 --- a/src/player.c +++ b/src/player.c @@ -170,7 +170,7 @@ player_update(struct Player *p) } void -player_draw(struct Player *p) +player_draw(const struct Player *p) { draw_rectangle(C_WHITE, p->pos.x + DRAW_OFF_X, p->pos.y, PLAYER_WIDTH, PLAYER_HEIGHT); @@ -199,6 +199,13 @@ player_move(struct Player *p, struct Vec spd) p->pos.y -= sign_y; } +struct Vec +player_middle(const struct Player *p) +{ + return (struct Vec){p->pos.x + PLAYER_WIDTH / 2, + p->pos.y + PLAYER_HEIGHT / 2}; +} + static void reset_speed(struct Player *p, int x, int y) { diff --git a/src/vec.c b/src/vec.c new file mode 100644 index 0000000..d586b8c --- /dev/null +++ b/src/vec.c @@ -0,0 +1,23 @@ +#include "vec.h" +#include + +struct VecF +vecf(struct Vec v) +{ + return (struct VecF){v.x, v.y}; +} + +struct Vec +vec(struct VecF v) +{ + return (struct Vec){v.x, v.y}; +} + +struct VecF +normalize(struct VecF v) +{ + const float len = sqrt(v.x * v.x + v.y * v.y); + v.x /= len; + v.y /= len; + return v; +}