2021-05-30 21:59:09 +02:00
|
|
|
#include "map.h"
|
|
|
|
#include "level.h"
|
|
|
|
#include "render.h"
|
2021-06-01 17:49:29 +02:00
|
|
|
#include "geometry.h"
|
|
|
|
#include "entities.h"
|
2021-06-04 15:14:12 +02:00
|
|
|
#include "game.h"
|
2021-06-09 20:47:39 +02:00
|
|
|
#include "anim.h"
|
2021-05-30 21:59:09 +02:00
|
|
|
|
|
|
|
#include <gint/display.h>
|
|
|
|
#include <gint/keyboard.h>
|
|
|
|
#include <gint/usb.h>
|
|
|
|
#include <gint/usb-ff-bulk.h>
|
|
|
|
#include <gint/cpu.h>
|
|
|
|
#include <gint/timer.h>
|
2021-06-09 12:18:51 +02:00
|
|
|
|
|
|
|
#include <fxlibc/printf.h>
|
2021-06-02 15:40:32 +02:00
|
|
|
#include <libprof.h>
|
2021-05-30 21:59:09 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
static bool getkey_global_shortcuts(key_event_t e)
|
|
|
|
{
|
|
|
|
if(usb_is_open() && e.key == KEY_OPTN && !e.shift && !e.alpha) {
|
|
|
|
usb_fxlink_screenshot(true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-06-02 09:38:59 +02:00
|
|
|
extern level_t lv_demo;
|
2021-05-30 21:59:09 +02:00
|
|
|
|
2021-06-09 20:47:39 +02:00
|
|
|
int OVERLAY_HITBOXES = 0;
|
|
|
|
|
2021-05-30 21:59:09 +02:00
|
|
|
int main(void)
|
|
|
|
{
|
|
|
|
getkey_set_feature_function(getkey_global_shortcuts);
|
2021-06-09 12:18:51 +02:00
|
|
|
__printf_enable_fp();
|
2021-06-01 17:49:29 +02:00
|
|
|
srand(0xc0ffee);
|
2021-06-02 15:40:32 +02:00
|
|
|
prof_init();
|
2021-05-30 21:59:09 +02:00
|
|
|
|
|
|
|
usb_interface_t const *interfaces[] = { &usb_ff_bulk, NULL };
|
|
|
|
usb_open(interfaces, GINT_CALL_NULL);
|
|
|
|
|
2021-06-04 15:14:12 +02:00
|
|
|
game_t game = { 0 };
|
|
|
|
map_t *m = &game.map;
|
|
|
|
camera_t *c = &game.camera;
|
2021-05-30 21:59:09 +02:00
|
|
|
|
2021-06-04 15:14:12 +02:00
|
|
|
game_load(&game, &lv_demo);
|
2021-05-30 21:59:09 +02:00
|
|
|
|
2021-06-01 17:49:29 +02:00
|
|
|
//---
|
2021-06-04 15:14:12 +02:00
|
|
|
// Load random entities on the map
|
2021-06-01 17:49:29 +02:00
|
|
|
//---
|
|
|
|
|
2021-06-04 15:14:12 +02:00
|
|
|
entity_movement_params_t emp_none = {
|
|
|
|
.max_speed = fix(0),
|
2021-06-05 11:38:51 +02:00
|
|
|
.propulsion = fix(0),
|
2021-06-04 15:14:12 +02:00
|
|
|
};
|
|
|
|
entity_movement_params_t emp_player = {
|
|
|
|
.max_speed = PLAYER_SPEED,
|
2021-06-09 20:47:39 +02:00
|
|
|
.propulsion = fix(11),
|
|
|
|
.dash_speed = fix(45),
|
|
|
|
.dash_duration = fix(1) / 32,
|
2021-06-05 11:38:51 +02:00
|
|
|
.dash_cooldown = fix(1) / 2,
|
2021-06-04 15:14:12 +02:00
|
|
|
};
|
|
|
|
|
2021-06-01 17:49:29 +02:00
|
|
|
for(int i = 0; i < 10; i++) {
|
2021-06-02 16:45:02 +02:00
|
|
|
entity_t *e = malloc(sizeof *e);
|
2021-06-01 17:49:29 +02:00
|
|
|
if(!e) continue;
|
|
|
|
|
|
|
|
int x=1, y=1;
|
|
|
|
for(int i = 0; i < 1000; i++) {
|
|
|
|
x = rand() % m->width;
|
|
|
|
y = rand() % m->height;
|
|
|
|
|
|
|
|
struct tile *t = map_tile(m, x, y);
|
|
|
|
if(t && !t->solid) break;
|
|
|
|
}
|
2021-06-04 15:14:12 +02:00
|
|
|
e->movement.x = fix(x) + fix(1) / 2;
|
|
|
|
e->movement.y = fix(y) + fix(1) / 2;
|
|
|
|
e->movement.vx = 0;
|
|
|
|
e->movement.vy = 0;
|
|
|
|
e->movement.facing = rand() % 4;
|
2021-06-05 11:38:51 +02:00
|
|
|
e->movement.dash = 0;
|
|
|
|
e->movement.dash_facing = 0;
|
2021-06-04 15:14:12 +02:00
|
|
|
e->movement_params = &emp_none;
|
2021-06-09 20:47:39 +02:00
|
|
|
e->anim.frame = NULL;
|
|
|
|
e->anim.elapsed = 0;
|
2021-06-01 17:49:29 +02:00
|
|
|
|
|
|
|
if(rand() % 2) {
|
2021-06-04 15:14:12 +02:00
|
|
|
e->hitbox = (shape_t){ SHAPE_RECT,
|
|
|
|
.rect = { .l=-fix(1)/4, .r=fix(1)/4, .t=-fix(1)/4, .b=fix(1)/4 },
|
2021-06-02 16:45:02 +02:00
|
|
|
.color = C_GREEN,
|
2021-06-01 17:49:29 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
else {
|
2021-06-04 15:14:12 +02:00
|
|
|
e->hitbox = (shape_t){ SHAPE_CIRCLE,
|
|
|
|
.circle = { .x=0, .y=0, .r=fix(1)/4 },
|
2021-06-02 16:45:02 +02:00
|
|
|
.color = C_GREEN,
|
2021-06-01 17:49:29 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-06-04 15:14:12 +02:00
|
|
|
game_add_entity(&game, e);
|
2021-06-01 17:49:29 +02:00
|
|
|
}
|
|
|
|
|
2021-06-04 15:14:12 +02:00
|
|
|
entity_t *player = game.entities[5];
|
|
|
|
game.player = player;
|
|
|
|
player->hitbox.color = C_BLUE;
|
|
|
|
player->movement_params = &emp_player;
|
2021-06-01 22:06:58 +02:00
|
|
|
|
2021-06-09 20:47:39 +02:00
|
|
|
extern anim_frame_t anim_player_idle_left[];
|
|
|
|
extern anim_frame_t anim_player_idle_right[];
|
|
|
|
extern anim_frame_t anim_player_idle_up[];
|
|
|
|
extern anim_frame_t anim_player_idle_down[];
|
|
|
|
|
|
|
|
player->anim.frame = &anim_player_idle_down[0];
|
|
|
|
player->anim.elapsed = 0;
|
|
|
|
|
2021-05-30 21:59:09 +02:00
|
|
|
//---
|
|
|
|
// Main loop
|
|
|
|
//---
|
|
|
|
|
|
|
|
volatile int frame_tick = 1;
|
|
|
|
int timer_id = timer_configure(TIMER_ANY, 1000000 / FRAME_RATE,
|
|
|
|
GINT_CALL_SET(&frame_tick));
|
|
|
|
if(timer_id >= 0)
|
|
|
|
timer_start(timer_id);
|
|
|
|
|
2021-06-02 15:40:32 +02:00
|
|
|
uint32_t time_render = 0;
|
2021-06-04 16:24:47 +02:00
|
|
|
bool stop = false;
|
|
|
|
bool show_vars = false;
|
2021-06-02 15:40:32 +02:00
|
|
|
|
2021-06-04 16:24:47 +02:00
|
|
|
while(!stop) {
|
2021-05-30 21:59:09 +02:00
|
|
|
while(!frame_tick) sleep();
|
2021-06-04 16:24:47 +02:00
|
|
|
bool attack = false;
|
2021-05-30 21:59:09 +02:00
|
|
|
|
|
|
|
/* Assume the frame is not late */
|
|
|
|
fixed_t dt = fix(1) / FRAME_RATE;
|
|
|
|
|
2021-06-02 15:40:32 +02:00
|
|
|
time_render = prof_exec({
|
|
|
|
dclear(C_RGB(2,1,1));
|
2021-06-04 15:14:12 +02:00
|
|
|
render_game(&game);
|
2021-06-04 16:24:47 +02:00
|
|
|
|
|
|
|
if(show_vars) {
|
|
|
|
for(int i = 0; i < 396 * 224; i++) {
|
|
|
|
gint_vram[i] = (gint_vram[i] & 0xf7de) >> 1;
|
|
|
|
}
|
|
|
|
|
2021-06-05 11:38:51 +02:00
|
|
|
uint16_t gray = C_RGB(16, 16, 16);
|
2021-06-04 16:24:47 +02:00
|
|
|
|
2021-06-05 11:38:51 +02:00
|
|
|
dprint(3, 40, C_WHITE, "Max player speed: %g tiles/s",
|
2021-06-04 16:24:47 +02:00
|
|
|
f2double(emp_player.max_speed));
|
2021-06-05 11:38:51 +02:00
|
|
|
dprint(15, 55, gray, "More with [X,0,T], less with [frac]");
|
|
|
|
|
|
|
|
dprint(3, 70, C_WHITE, "Propulsion: %g s^-1",
|
|
|
|
f2double(emp_player.propulsion));
|
|
|
|
dprint(15, 85, gray, "More with [log], less with [F<>D]");
|
|
|
|
dprint(15, 100, C_WHITE, "(Equivalent friction: %g)",
|
|
|
|
f2double(fix(1) - emp_player.propulsion / FRAME_RATE));
|
2021-06-04 16:24:47 +02:00
|
|
|
|
2021-06-05 11:38:51 +02:00
|
|
|
dprint(3, 115, C_WHITE, "Dash speed: %g tiles/s",
|
|
|
|
f2double(emp_player.dash_speed));
|
|
|
|
dprint(15, 130, gray, "More with [ln], less with [(]");
|
2021-06-04 16:24:47 +02:00
|
|
|
|
2021-06-05 11:38:51 +02:00
|
|
|
dprint(3, 145, C_WHITE, "Dash duration: %g s",
|
|
|
|
f2double(emp_player.dash_duration));
|
|
|
|
dprint(15, 160, gray, "More with [sin], less with [)]");
|
2021-06-04 16:24:47 +02:00
|
|
|
|
2021-06-05 11:38:51 +02:00
|
|
|
dprint(3, 175, C_WHITE, "Dash cooldown: %g s",
|
|
|
|
f2double(emp_player.dash_cooldown));
|
|
|
|
dprint(15, 190, gray, "More with [cos], less with [,]");
|
2021-06-04 16:24:47 +02:00
|
|
|
}
|
|
|
|
|
2021-06-05 11:38:51 +02:00
|
|
|
// dprint(1, 1, C_WHITE, "Frame: %.3j ms", time_render);
|
|
|
|
dprint(1, 1, C_WHITE, "dash:%g", f2double(player->movement.dash));
|
2021-06-02 15:40:32 +02:00
|
|
|
dupdate();
|
|
|
|
});
|
2021-05-30 21:59:09 +02:00
|
|
|
|
2021-06-09 20:47:39 +02:00
|
|
|
game_update_animations(&game, dt);
|
|
|
|
|
2021-06-04 16:24:47 +02:00
|
|
|
key_event_t ev;
|
2021-06-05 11:38:51 +02:00
|
|
|
while((ev = pollevent()).type != KEYEV_NONE) {
|
|
|
|
if(ev.type == KEYEV_UP) continue;
|
|
|
|
|
2021-06-04 16:24:47 +02:00
|
|
|
if(ev.key == KEY_MENU)
|
|
|
|
gint_osmenu();
|
|
|
|
if(ev.key == KEY_EXIT)
|
|
|
|
stop = true;
|
2021-06-05 11:38:51 +02:00
|
|
|
if(ev.key == KEY_F6 && usb_is_open())
|
2021-06-04 16:24:47 +02:00
|
|
|
usb_fxlink_screenshot(true);
|
2021-06-09 20:47:39 +02:00
|
|
|
if(ev.key == KEY_F5)
|
|
|
|
OVERLAY_HITBOXES ^= 1;
|
2021-06-04 16:24:47 +02:00
|
|
|
|
|
|
|
/* Parameter adjustement */
|
|
|
|
if(ev.key == KEY_VARS)
|
|
|
|
show_vars = !show_vars;
|
2021-06-05 11:38:51 +02:00
|
|
|
|
2021-06-04 16:24:47 +02:00
|
|
|
if(ev.key == KEY_XOT)
|
2021-06-05 11:38:51 +02:00
|
|
|
emp_player.max_speed += fix(1)/8;
|
2021-06-04 16:24:47 +02:00
|
|
|
if(ev.key == KEY_FRAC) {
|
2021-06-05 11:38:51 +02:00
|
|
|
emp_player.max_speed -= fix(1)/8;
|
|
|
|
if(emp_player.max_speed < 0)
|
|
|
|
emp_player.max_speed = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ev.key == KEY_LOG) {
|
|
|
|
emp_player.propulsion += fix(1) / 8;
|
|
|
|
if(emp_player.propulsion > fix(FRAME_RATE))
|
|
|
|
emp_player.propulsion = fix(FRAME_RATE);
|
2021-06-04 16:24:47 +02:00
|
|
|
}
|
|
|
|
if(ev.key == KEY_FD) {
|
2021-06-05 11:38:51 +02:00
|
|
|
emp_player.propulsion -= fix(1) / 8;
|
|
|
|
if(emp_player.propulsion <= 0)
|
|
|
|
emp_player.propulsion = 0;
|
2021-06-04 16:24:47 +02:00
|
|
|
}
|
2021-06-05 11:38:51 +02:00
|
|
|
|
2021-06-04 16:24:47 +02:00
|
|
|
if(ev.key == KEY_LN)
|
2021-06-05 11:38:51 +02:00
|
|
|
emp_player.dash_speed += fix(1) / 2;
|
2021-06-04 16:24:47 +02:00
|
|
|
if(ev.key == KEY_LEFTP) {
|
2021-06-05 11:38:51 +02:00
|
|
|
emp_player.dash_speed -= fix(1) / 2;
|
|
|
|
if(emp_player.dash_speed <= 0)
|
|
|
|
emp_player.dash_speed = 0;
|
2021-06-04 16:24:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(ev.key == KEY_SIN)
|
2021-06-05 11:38:51 +02:00
|
|
|
emp_player.dash_duration += fix(1) / 64;
|
2021-06-04 16:24:47 +02:00
|
|
|
if(ev.key == KEY_RIGHTP) {
|
2021-06-05 11:38:51 +02:00
|
|
|
emp_player.dash_duration -= fix(1) / 64;
|
|
|
|
if(emp_player.dash_duration <= 0)
|
|
|
|
emp_player.dash_duration = 0;
|
2021-06-04 16:24:47 +02:00
|
|
|
}
|
2021-06-05 11:38:51 +02:00
|
|
|
|
2021-06-04 16:24:47 +02:00
|
|
|
if(ev.key == KEY_COS)
|
2021-06-05 11:38:51 +02:00
|
|
|
emp_player.dash_cooldown += fix(1) / 8;
|
2021-06-04 16:24:47 +02:00
|
|
|
if(ev.key == KEY_COMMA) {
|
2021-06-05 11:38:51 +02:00
|
|
|
emp_player.dash_cooldown -= fix(1) / 8;
|
|
|
|
if(emp_player.dash_cooldown <= 0)
|
|
|
|
emp_player.dash_cooldown = 0;
|
2021-06-04 16:24:47 +02:00
|
|
|
}
|
2021-05-30 21:59:09 +02:00
|
|
|
|
2021-06-04 16:24:47 +02:00
|
|
|
if(ev.key == KEY_PLUS)
|
|
|
|
camera_zoom(c, c->zoom + 1);
|
|
|
|
if(ev.key == KEY_MINUS)
|
|
|
|
camera_zoom(c, c->zoom - 1);
|
|
|
|
if(ev.key == KEY_SHIFT)
|
|
|
|
attack = true;
|
|
|
|
}
|
2021-05-30 21:59:09 +02:00
|
|
|
|
2021-06-04 16:24:47 +02:00
|
|
|
/* Camera movement */
|
2021-05-30 21:59:09 +02:00
|
|
|
fixed_t vx = CAMERA_SPEED_X;
|
|
|
|
fixed_t vy = CAMERA_SPEED_Y;
|
|
|
|
|
2021-06-01 17:49:29 +02:00
|
|
|
if(keydown(KEY_4) || keydown(KEY_7) || keydown(KEY_1))
|
2021-05-30 21:59:09 +02:00
|
|
|
camera_move(c, -fmul(dt, vx), 0);
|
2021-06-01 17:49:29 +02:00
|
|
|
if(keydown(KEY_6) || keydown(KEY_9) || keydown(KEY_3))
|
2021-05-30 21:59:09 +02:00
|
|
|
camera_move(c, fmul(dt, vx), 0);
|
2021-06-01 17:49:29 +02:00
|
|
|
if(keydown(KEY_8) || keydown(KEY_7) || keydown(KEY_9))
|
2021-05-30 21:59:09 +02:00
|
|
|
camera_move(c, 0, -fmul(dt, vy));
|
2021-06-01 17:49:29 +02:00
|
|
|
if(keydown(KEY_2) || keydown(KEY_1) || keydown(KEY_3))
|
2021-05-30 21:59:09 +02:00
|
|
|
camera_move(c, 0, fmul(dt, vy));
|
|
|
|
|
2021-06-01 22:06:58 +02:00
|
|
|
/* Player movement */
|
2021-06-04 15:14:12 +02:00
|
|
|
int dir = -1;
|
|
|
|
if(keydown(KEY_UP)) dir = UP;
|
|
|
|
if(keydown(KEY_DOWN)) dir = DOWN;
|
|
|
|
if(keydown(KEY_LEFT)) dir = LEFT;
|
|
|
|
if(keydown(KEY_RIGHT)) dir = RIGHT;
|
2021-06-02 16:45:02 +02:00
|
|
|
|
2021-06-05 11:38:51 +02:00
|
|
|
if(keydown(KEY_F1)) {
|
|
|
|
int dash_dir = (dir >= 0) ? dir : player->movement.facing;
|
|
|
|
entity_dash(player, dash_dir);
|
|
|
|
}
|
|
|
|
entity_movement_t next = entity_move(player, dir, dt);
|
2021-06-01 22:06:58 +02:00
|
|
|
|
2021-06-04 15:14:12 +02:00
|
|
|
shape_t player_hitbox = player->hitbox;
|
|
|
|
shape_translate(&player_hitbox, (fpoint_t){ next.x, next.y });
|
2021-06-02 16:45:02 +02:00
|
|
|
|
2021-06-09 20:47:39 +02:00
|
|
|
if(player->movement.facing != next.facing) {
|
|
|
|
anim_frame_t *dirs[4] = {
|
|
|
|
anim_player_idle_up,
|
|
|
|
anim_player_idle_right,
|
|
|
|
anim_player_idle_down,
|
|
|
|
anim_player_idle_left,
|
|
|
|
};
|
|
|
|
player->anim.frame = dirs[next.facing];
|
|
|
|
}
|
|
|
|
|
2021-06-04 15:14:12 +02:00
|
|
|
if(!game_shape_collides(&game, player, &player_hitbox)) {
|
|
|
|
player->movement = next;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
player->movement.facing = next.facing;
|
|
|
|
player->movement.vx = fix(0);
|
|
|
|
player->movement.vy = fix(0);
|
2021-06-05 11:38:51 +02:00
|
|
|
player->movement.dash = next.dash;
|
2021-06-04 15:14:12 +02:00
|
|
|
}
|
2021-06-02 16:45:02 +02:00
|
|
|
|
|
|
|
/* Attack */
|
2021-06-04 16:24:47 +02:00
|
|
|
if(attack) {
|
2021-06-02 16:45:02 +02:00
|
|
|
fixed_t reach2 = fmul(ATTACK_REACH, ATTACK_REACH);
|
|
|
|
fixed_t angle_cos2 = fmul(ATTACK_ANGLE_COS, ATTACK_ANGLE_COS);
|
2021-06-04 15:14:12 +02:00
|
|
|
fpoint_t dir = fdir(player->movement.facing);
|
2021-06-02 16:45:02 +02:00
|
|
|
|
2021-06-04 15:14:12 +02:00
|
|
|
for(int i = 0; i < game.entity_count; i++) {
|
|
|
|
entity_t *e = game.entities[i];
|
|
|
|
if(e == player) continue;
|
2021-06-02 16:45:02 +02:00
|
|
|
|
|
|
|
/* Distance to player */
|
2021-06-04 15:14:12 +02:00
|
|
|
fixed_t dx = e->movement.x - player->movement.x;
|
|
|
|
fixed_t dy = e->movement.y - player->movement.y;
|
2021-06-02 16:45:02 +02:00
|
|
|
fixed_t dist2 = fmul(dx, dx) + fmul(dy, dy);
|
|
|
|
if(dist2 > reach2) continue;
|
|
|
|
|
|
|
|
/* Attack angle */
|
|
|
|
fixed_t dotp = fmul(dir.x, dx) + fmul(dir.y, dy);
|
|
|
|
if(dotp < 0 || fmul(dotp, dotp) < fmul(dist2, angle_cos2))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Inflict damage */
|
2021-06-04 15:14:12 +02:00
|
|
|
e->hitbox.color = C_RED;
|
2021-06-02 16:45:02 +02:00
|
|
|
}
|
|
|
|
}
|
2021-05-30 21:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
timer_stop(timer_id);
|
2021-06-02 15:40:32 +02:00
|
|
|
prof_quit();
|
2021-05-30 21:59:09 +02:00
|
|
|
usb_close();
|
2021-06-02 10:06:10 +02:00
|
|
|
return 1;
|
2021-05-30 21:59:09 +02:00
|
|
|
}
|