jtmm2/src/missile.c

147 lines
3.1 KiB
C

#include "missile.h"
#include "conf.h"
#include "level.h"
#include "polarity.h"
#include "tile.h"
#include <gint/display.h>
#include <stdlib.h>
static struct MissileManager manager = {.missiles = NULL};
static void missile_init(struct Missile *);
static void missile_update(struct Missile *, struct VecF target);
static void missile_draw(const struct Missile *);
static int collide(int x, int y, int tile);
static int collide_stopper(int x, int y);
void
missile_manager_init(void)
{
int i;
missile_manager_free();
manager.n_missiles = 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;
manager.missiles[i].cooldown = MISSILE_COOLDOWN;
}
}
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) {
struct Missile *const m = &manager.missiles[i];
if (m->active)
missile_update(m, target);
else if (m->cooldown && !--m->cooldown)
missile_init(m);
}
}
void
missile_manager_draw(void)
{
int i = manager.n_missiles;
while (i-- > 0)
if (manager.missiles[i].active)
missile_draw(&manager.missiles[i]);
}
void
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->spawn.x = x;
m->spawn.y = y;
missile_init(m);
}
void
missile_init(struct Missile *m)
{
m->active = 1;
m->cooldown = MISSILE_COOLDOWN;
m->pos.x = m->spawn.x;
m->pos.y = m->spawn.y;
m->spd.x = 0.0f;
m->spd.y = 0.0f;
}
int
missile_collide_player(const struct Player *p)
{
const float x1 = p->pos.x;
const float y1 = p->pos.y;
const float x2 = x1 + PLAYER_WIDTH - 1.0f;
const float y2 = y1 + PLAYER_HEIGHT - 1.0f;
int i = manager.n_missiles;
while (i-- > 0) {
const struct Missile *m = &manager.missiles[i];
if (m->active && m->pos.x > x1 && m->pos.x < x2 &&
m->pos.y > y1 && m->pos.y < y2)
return 1;
}
return 0;
}
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;
/* destroy */
if (collide_stopper(m->pos.x + 0.5f, m->pos.y + 0.5f))
m->active = false;
}
static void
missile_draw(const struct Missile *m)
{
extern bopti_image_t bimg_missile;
const int x = (int)(m->pos.x + 0.5f) - bimg_missile.width / 2;
const int y = (int)(m->pos.y + 0.5f) - bimg_missile.height / 2;
dimage(x, y, &bimg_missile);
}
static int
collide(int x, int y, int tile)
{
return level_get_px(x, y) == tile;
}
static int
collide_stopper(int x, int y)
{
return collide(x, y, TILE_SOLID) ||
(!polarity() && collide(x, y, TILE_RED)) ||
(polarity() && collide(x, y, TILE_BLUE));
}