performance improvements with pathfinding
* Less queuing in Dijkstra by using distance[] to indicate the lowest queued distance (dir[] still doubles down as "seen" array). Drops iterations from ~350 to ~150, 5.5 ms -> 2.0 ms * Less raycast attempts in the shortcut method, barely noticeable but avoids massive spikes from 7 to 35/75 ms in Lab with 40 entities (!!) * General optimizations with -O3 instead of -Os (0.5-1.0 ms gained per frame for ~6 kB increase in size) * Compute pathfinding every 4th frame for each entity, instead of every frame Now basically a fairly 30 FPS, and that's 30 ms rendering + 3 ms simulation.
This commit is contained in:
parent
7bd5163dd6
commit
8d3a0994c5
|
@ -98,7 +98,7 @@ fxconv_declare_assets(${ASSETS} ${ASSETS} WITH_METADATA)
|
|||
fxconv_declare_converters(assets-cg/converters.py)
|
||||
|
||||
add_executable(addin ${SOURCES} ${ASSETS})
|
||||
target_compile_options(addin PRIVATE -Wall -Wextra -Os)
|
||||
target_compile_options(addin PRIVATE -Wall -Wextra -O3)
|
||||
target_include_directories(addin PRIVATE src)
|
||||
target_link_libraries(addin LibProf::LibProf Gint::Gint)
|
||||
target_link_options(addin PRIVATE -Wl,-Map=map)
|
||||
|
|
|
@ -162,8 +162,8 @@ static bool attack_apply(game_t *game, aoe_t *aoe, entity_t *target)
|
|||
|
||||
/* No friendly fire */
|
||||
bool origin_is_monster = !aoe->origin ? true :
|
||||
(origin_f && origin_f->enemy_data != NULL);
|
||||
bool target_is_monster = (target_f->enemy_data != NULL);
|
||||
(origin_f && origin_f->enemy != NULL);
|
||||
bool target_is_monster = (target_f->enemy != NULL);
|
||||
if(origin_is_monster == target_is_monster || target_f->HP == 0)
|
||||
return false;
|
||||
|
||||
|
@ -174,7 +174,7 @@ static bool attack_apply(game_t *game, aoe_t *aoe, entity_t *target)
|
|||
/* Knockback */
|
||||
fixed_t r = (rand() & (fix(0.125)-1)) + fix(0.375);
|
||||
/* Half knockback against players */
|
||||
if(target_f->enemy_data == NULL) r /= 2;
|
||||
if(!target_f->enemy) r /= 2;
|
||||
|
||||
vec2 dir = { 0, 0 };
|
||||
int damage = 0;
|
||||
|
@ -220,7 +220,7 @@ static bool attack_apply(game_t *game, aoe_t *aoe, entity_t *target)
|
|||
|
||||
/* Spawn damage particle */
|
||||
entity_t *particle = particle_make_damage(target, damage,
|
||||
(target_f->enemy_data == NULL) ? C_RED : C_WHITE);
|
||||
target_f->enemy ? C_WHITE : C_RED);
|
||||
game_add_entity(game, particle);
|
||||
|
||||
/* Quick screenshake for entities hit by a bullet */
|
||||
|
|
|
@ -68,6 +68,9 @@ void entity_destroy(entity_t *e)
|
|||
if(e->comps & ENTITY_COMP_aoe) {
|
||||
aoe_destroy(e);
|
||||
}
|
||||
if(e->comps & ENTITY_COMP_fighter) {
|
||||
fighter_destroy(e);
|
||||
}
|
||||
|
||||
/* Since there's only one allocation for all components, this is easy */
|
||||
free(e);
|
||||
|
|
|
@ -38,11 +38,11 @@ int fighter_damage(entity_t *e, int base_damage)
|
|||
if(f->HP < damage) f->HP = 0;
|
||||
else f->HP -= damage;
|
||||
|
||||
if(f->enemy_data != NULL) {
|
||||
if(f->enemy) {
|
||||
if(f->HP == 0)
|
||||
visible_set_anim(e, f->enemy_data->anim_death, 4);
|
||||
visible_set_anim(e, f->enemy->id->anim_death, 4);
|
||||
else
|
||||
visible_set_anim(e, f->enemy_data->anim_hit, 3);
|
||||
visible_set_anim(e, f->enemy->id->anim_hit, 3);
|
||||
}
|
||||
else {
|
||||
visible_set_anim(e, &anims_player_Hit, 3);
|
||||
|
@ -62,3 +62,9 @@ void fighter_invulnerability(entity_t *e, fixed_t duration)
|
|||
fighter_t *f = getcomp(e, fighter);
|
||||
f->invulnerability_delay = max(f->invulnerability_delay, duration);
|
||||
}
|
||||
|
||||
void fighter_destroy(entity_t *e)
|
||||
{
|
||||
fighter_t *f = getcomp(e, fighter);
|
||||
free(f->enemy);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,9 @@ typedef struct
|
|||
/* Whether attack follows movement */
|
||||
uint8_t attack_follows_movement;
|
||||
/* Pointer to enemy data (NULL if player) */
|
||||
struct enemy const *enemy_data;
|
||||
struct enemy_data *enemy;
|
||||
/* Pointer to player data (NULL if enemy) */
|
||||
struct player_data *player;
|
||||
/* Combat statistics */
|
||||
uint16_t HP, ATK, MAG, DEF, HP_max;
|
||||
|
||||
|
@ -65,3 +67,6 @@ void fighter_stun(entity_t *e, fixed_t duration);
|
|||
|
||||
/* Make the fighter invulnerable for a specified duration. */
|
||||
void fighter_invulnerability(entity_t *e, fixed_t duration);
|
||||
|
||||
/* Free dynamic data (enemy info). */
|
||||
void fighter_destroy(entity_t *e);
|
||||
|
|
|
@ -144,10 +144,13 @@ entity_t *enemy_make(int enemy_id)
|
|||
fighter_t *f = getcomp(e, fighter);
|
||||
memset(f, 0, sizeof *f);
|
||||
|
||||
f->enemy_data = data;
|
||||
fighter_set_stats(f, &data->stats, data->level, fix(1.0));
|
||||
f->HP = f->HP_max;
|
||||
f->combo_length = 1;
|
||||
f->enemy = malloc(sizeof *f->enemy);
|
||||
f->enemy->id = data;
|
||||
f->enemy->pathfind_dir = (vec2){ 0, 0 };
|
||||
f->enemy->pathfind_cycles = 0;
|
||||
|
||||
/* Specify skills */
|
||||
if(enemy_id == ENEMY_GUNSLINGER_8) {
|
||||
|
@ -162,22 +165,34 @@ entity_t *enemy_make(int enemy_id)
|
|||
static void move_towards_player(game_t *g, entity_t *e, fixed_t dt)
|
||||
{
|
||||
physical_t *p = getcomp(e, physical);
|
||||
fighter_t *f = getcomp(e, fighter);
|
||||
vec2 pos = physical_pos(e);
|
||||
vec2 direction;
|
||||
vec2 direction = { 0, 0 };
|
||||
|
||||
if(dist2(pos, physical_pos(g->player)) <= fix(0.25)) /* 0.5^2 */
|
||||
return;
|
||||
|
||||
pfg_path_t path = pfg_inwards(&g->paths_to_player, vec_f2i(pos));
|
||||
if(path.points) {
|
||||
direction = pfc_shortcut_one(&path, pos, physical_pos(g->player),
|
||||
p->hitbox);
|
||||
pfg_path_free(&path);
|
||||
if(f->enemy && f->enemy->pathfind_cycles > 0) {
|
||||
direction = f->enemy->pathfind_dir;
|
||||
f->enemy->pathfind_cycles--;
|
||||
}
|
||||
else {
|
||||
pfg_path_t path = pfg_inwards(&g->paths_to_player, vec_f2i(pos));
|
||||
if(path.points) {
|
||||
direction = pfc_shortcut_one(&path, pos, physical_pos(g->player),
|
||||
p->hitbox);
|
||||
pfg_path_free(&path);
|
||||
}
|
||||
|
||||
if(direction.x && direction.y) {
|
||||
direction.x -= pos.x;
|
||||
direction.y -= pos.y;
|
||||
if(direction.x && direction.y) {
|
||||
direction.x -= pos.x;
|
||||
direction.y -= pos.y;
|
||||
}
|
||||
|
||||
if(f->enemy) {
|
||||
f->enemy->pathfind_dir = direction;
|
||||
f->enemy->pathfind_cycles = 4;
|
||||
}
|
||||
}
|
||||
|
||||
mechanical_move(e, direction, dt, g->map);
|
||||
|
@ -214,7 +229,7 @@ static bool contact_attack(game_t *g, entity_t *e)
|
|||
|
||||
f->current_attack = aoe;
|
||||
f->attack_follows_movement = true;
|
||||
visible_set_anim(e, f->enemy_data->anim_attack, 2);
|
||||
visible_set_anim(e, f->enemy->id->anim_attack, 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -235,16 +250,16 @@ void enemy_ai(game_t *g, entity_t *e, fixed_t dt)
|
|||
{
|
||||
fighter_t *f = getcomp(e, fighter);
|
||||
|
||||
if(f->enemy_data == &slime_1 || f->enemy_data == &bat_2) {
|
||||
if(f->enemy->id == &slime_1 || f->enemy->id == &bat_2) {
|
||||
if(move_within_range_of_player(g, e, fix(1.0), dt)) {
|
||||
contact_attack(g, e);
|
||||
}
|
||||
}
|
||||
|
||||
else if(f->enemy_data == &fire_slime_4) {
|
||||
else if(f->enemy->id == &fire_slime_4) {
|
||||
}
|
||||
|
||||
else if(f->enemy_data == &gunslinger_8) {
|
||||
else if(f->enemy->id == &gunslinger_8) {
|
||||
rect hitbox = { fix(-1/16), fix(1/16), fix(-1/16), fix(1/16) };
|
||||
bool clear = raycast_clear_hitbox(g->map, physical_pos(e),
|
||||
physical_pos(g->player), hitbox);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "anim.h"
|
||||
|
||||
/* enemy_t: Static enemy information */
|
||||
typedef struct enemy
|
||||
typedef struct
|
||||
{
|
||||
/* Enemy name (shown in wave information) */
|
||||
char const *name;
|
||||
|
@ -44,6 +44,16 @@ enum {
|
|||
ENEMY_GUNSLINGER_8 = 4,
|
||||
};
|
||||
|
||||
/* Dynamic enemy information. */
|
||||
typedef struct enemy_data {
|
||||
enemy_t const *id;
|
||||
/* Current pathfinding direction */
|
||||
vec2 pathfind_dir;
|
||||
/* Number of frames left until next pathfinding cycle */
|
||||
uint8_t pathfind_cycles;
|
||||
|
||||
} enemy_data_t;
|
||||
|
||||
/* Get enemy data by ID. */
|
||||
enemy_t const *enemy_data(int enemy_id);
|
||||
|
||||
|
|
|
@ -180,9 +180,9 @@ void game_remove_dead_entities(game_t *g)
|
|||
visible_t *v = getcomp(e, visible);
|
||||
bool anim_finished = !v || (v->anim.frame == NULL);
|
||||
|
||||
if(f && f->HP == 0 && f->enemy_data != NULL && anim_finished) {
|
||||
if(f && f->HP == 0 && f->enemy != NULL && anim_finished) {
|
||||
/* Give XP points to player */
|
||||
bool lvup = player_add_xp(g->player_data, f->enemy_data->xp);
|
||||
bool lvup = player_add_xp(g->player_data, f->enemy->id->xp);
|
||||
|
||||
if(lvup) {
|
||||
g->hud_xp_anim.frame = anims_hud_xp_Explode.start[0];
|
||||
|
|
34
src/main.c
34
src/main.c
|
@ -132,7 +132,9 @@ int main(void)
|
|||
player_f->combo_length = 2;
|
||||
player_f->combo_next = 0;
|
||||
player_f->combo_delay = fix(0);
|
||||
player_f->enemy_data = NULL;
|
||||
player_f->enemy = NULL;
|
||||
// TODO: Set link to player data in entity
|
||||
// player_f->player = &player_data;
|
||||
player_f->skills[1] = SKILL_DASH;
|
||||
player_f->skills[2] = AOE_SHOCK;
|
||||
player_f->skills[3] = AOE_JUDGEMENT;
|
||||
|
@ -299,22 +301,6 @@ int main(void)
|
|||
ivec2 j = camera_map2screen(c, p);
|
||||
ivec2 k = camera_map2screen(c, q);
|
||||
dline(j.x, j.y, k.x, k.y, clear ? C_GREEN : C_RED);
|
||||
|
||||
extern int rch_c1, rch_c2;
|
||||
extern vec2 rch_p1[64], rch_p2[64];
|
||||
|
||||
for(int k = 0; k < rch_c1 && k < 64; k++) {
|
||||
ivec2 i = camera_map2screen(c, rch_p1[k]);
|
||||
|
||||
dline(i.x-2, i.y, i.x+2, i.y, C_RGB(0, 31, 31));
|
||||
dline(i.x, i.y-2, i.x, i.y+2, C_RGB(0, 31, 31));
|
||||
}
|
||||
for(int k = 0; k < rch_c2 && k < 64; k++) {
|
||||
ivec2 i = camera_map2screen(c, rch_p2[k]);
|
||||
|
||||
dline(i.x-2, i.y, i.x+2, i.y, C_RGB(0, 31, 31));
|
||||
dline(i.x, i.y-2, i.x, i.y+2, C_RGB(0, 31, 31));
|
||||
}
|
||||
}
|
||||
|
||||
if(debug.show_bfs_field && game.paths_to_player.direction) {
|
||||
|
@ -322,7 +308,9 @@ int main(void)
|
|||
}
|
||||
|
||||
if(debug.show_perf) {
|
||||
dprint(1, 15, C_WHITE, "Render: %.3D ms", time_render);
|
||||
extern uint32_t time_render_map, time_render_hud;
|
||||
dprint(1, 15, C_WHITE, "Render: map %.3D, hud %.3D, total %.3D ms",
|
||||
time_render_map, time_render_hud, time_render);
|
||||
dprint(1, 29, C_WHITE, "Simul: %.3D ms", time_simul);
|
||||
}
|
||||
|
||||
|
@ -484,15 +472,15 @@ int main(void)
|
|||
entity_t *e = game.entities[i];
|
||||
fighter_t *f = getcomp(e, fighter);
|
||||
mechanical_t *m = getcomp(e, mechanical);
|
||||
if(!f || !m || f->enemy_data == NULL || f->HP == 0)
|
||||
if(!f || !m || !f->enemy || f->HP == 0)
|
||||
continue;
|
||||
|
||||
enemy_ai(&game, e, dt);
|
||||
|
||||
if(mechanical_moving(e))
|
||||
visible_set_anim(e, f->enemy_data->anim_walking, 1);
|
||||
visible_set_anim(e, f->enemy->id->anim_walking, 1);
|
||||
else
|
||||
visible_set_anim(e, f->enemy_data->anim_idle, 1);
|
||||
visible_set_anim(e, f->enemy->id->anim_idle, 1);
|
||||
}
|
||||
|
||||
/* Player attack */
|
||||
|
@ -557,8 +545,8 @@ int main(void)
|
|||
entity_t *e = game.entities[i];
|
||||
fighter_t *f = getcomp(e, fighter);
|
||||
visible_t *v = getcomp(e, visible);
|
||||
if(f && f->enemy_data != NULL && v && !v->anim.frame) {
|
||||
visible_set_anim(e, f->enemy_data->anim_idle, 1);
|
||||
if(f && f->enemy && v && !v->anim.frame) {
|
||||
visible_set_anim(e, f->enemy->id->anim_idle, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,10 +68,9 @@ pfg_all2one_t pfg_dijkstra(map_t const *map, ivec2 center, uint8_t *occupation)
|
|||
/* Pop a node from the queue; ignore it if we've visited it before */
|
||||
pqueue_pop(&queue, &point);
|
||||
int point_i = idx(point.x, point.y);
|
||||
if(paths.distance[point_i] != -1)
|
||||
if(paths.direction[point_i] != -1)
|
||||
continue;
|
||||
|
||||
paths.distance[point_i] = point.cost;
|
||||
paths.direction[point_i] = point.dir;
|
||||
|
||||
for(int dir = 0; dir < 4; dir++) {
|
||||
|
@ -88,6 +87,11 @@ pfg_all2one_t pfg_dijkstra(map_t const *map, ivec2 center, uint8_t *occupation)
|
|||
is [dir] due to how [dx_array] and [dy_array] are laid out */
|
||||
struct point next = { .x=point.x+dx, .y=point.y+dy };
|
||||
next.cost = paths.distance[point_i] + 1 + 2*occ;
|
||||
|
||||
if(paths.distance[next_i]>=0 && paths.distance[next_i]<=next.cost)
|
||||
continue;
|
||||
paths.distance[next_i] = next.cost;
|
||||
|
||||
next.dir = dir;
|
||||
pqueue_add(&queue, &next);
|
||||
}
|
||||
|
@ -145,9 +149,6 @@ pfg_path_t pfg_outwards(pfg_all2one_t const *field, ivec2 p)
|
|||
// Raycasting tools
|
||||
//---
|
||||
|
||||
int raycast_clear_points = 0;
|
||||
vec2 *raycast_clear_p;
|
||||
|
||||
bool raycast_clear(map_t const *map, vec2 start, vec2 end)
|
||||
{
|
||||
vec2 u = { end.x - start.x, end.y - start.y };
|
||||
|
@ -156,30 +157,22 @@ bool raycast_clear(map_t const *map, vec2 start, vec2 end)
|
|||
fixed_t inv_ux = u.x ? fdiv(fix(1), u.x) : 0;
|
||||
fixed_t inv_uy = u.y ? fdiv(fix(1), u.y) : 0;
|
||||
|
||||
/* Current point is [start + t*u]; when t = 1, we're reached [end] */
|
||||
/* Current point is [start + t*u]; when t = 1, we've reached [end] */
|
||||
fixed_t t = fix(0);
|
||||
|
||||
raycast_clear_points = 0;
|
||||
|
||||
while(t < fix(1)) {
|
||||
fixed_t x = start.x + fmul(t, u.x);
|
||||
fixed_t y = start.y + fmul(t, u.y);
|
||||
|
||||
/* Re-check current cell to avoid diagonal clips, where we change tiles
|
||||
diagonally in a single stpe (which happens quite often when snapping
|
||||
to points with integer or half-integer coordinates) as things align
|
||||
perfectly */
|
||||
diagonally in a single step (which happens quite often when snapping
|
||||
to points with integer or half-integer coordinates as things align
|
||||
perfectly) */
|
||||
int current_x = ffloor(x-(u.x < 0));
|
||||
int current_y = ffloor(y-(u.y < 0));
|
||||
tile_t *tile = map_tile(map, current_x, current_y);
|
||||
if(tile && tile->solid) return false;
|
||||
|
||||
if(raycast_clear_points < 64) {
|
||||
raycast_clear_p[raycast_clear_points].x = x;
|
||||
raycast_clear_p[raycast_clear_points].y = y;
|
||||
}
|
||||
raycast_clear_points++;
|
||||
|
||||
/* Distance to the next horizontal, and vertical line */
|
||||
fixed_t dist_y = (u.y >= 0) ? fix(1) - fdec(y) : -(fdec(y-1) + 1);
|
||||
fixed_t dist_x = (u.x >= 0) ? fix(1) - fdec(x) : -(fdec(x-1) + 1);
|
||||
|
@ -188,36 +181,28 @@ bool raycast_clear(map_t const *map, vec2 start, vec2 end)
|
|||
fixed_t dty = fmul(dist_y, inv_uy);
|
||||
fixed_t dtx = fmul(dist_x, inv_ux);
|
||||
|
||||
int next_x = current_x;
|
||||
int next_y = current_y;
|
||||
|
||||
/* Move to the next point */
|
||||
if(!u.x || (u.y && dty <= dtx)) {
|
||||
/* Make sure we don't get stuck, at all costs */
|
||||
t += dty + (dty == 0);
|
||||
if(t > fix(1)) break;
|
||||
|
||||
int next_x = ffloor(x-(u.x < 0));
|
||||
int next_y = ffloor(y-(u.y < 0)) + (u.y >= 0 ? 1 : -1);
|
||||
|
||||
tile_t *tile = map_tile(map, next_x, next_y);
|
||||
if(tile && tile->solid) return false;
|
||||
next_y += (u.y >= 0 ? 1 : -1);
|
||||
}
|
||||
else {
|
||||
t += dtx + (dtx == 0);
|
||||
if(t > fix(1)) break;
|
||||
|
||||
int next_x = ffloor(x-(u.x < 0)) + (u.x >= 0 ? 1 : -1);
|
||||
int next_y = ffloor(y-(u.y < 0));
|
||||
|
||||
tile_t *tile = map_tile(map, next_x, next_y);
|
||||
if(tile && tile->solid) return false;
|
||||
next_x += (u.x >= 0 ? 1 : -1);
|
||||
}
|
||||
|
||||
if(t > fix(1)) break;
|
||||
tile = map_tile(map, next_x, next_y);
|
||||
if(tile && tile->solid) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int rch_c1=0, rch_c2=0;
|
||||
vec2 rch_p1[64], rch_p2[64];
|
||||
|
||||
bool raycast_clear_hitbox(map_t const *map, vec2 start, vec2 end,
|
||||
rect hitbox)
|
||||
{
|
||||
|
@ -241,15 +226,7 @@ bool raycast_clear_hitbox(map_t const *map, vec2 start, vec2 end,
|
|||
vec2 e1 = { end.x + p1.x, end.y + p1.y };
|
||||
vec2 e2 = { end.x + p2.x, end.y + p2.y };
|
||||
|
||||
raycast_clear_p = rch_p1;
|
||||
bool b1 = raycast_clear(map, s1, e1);
|
||||
rch_c1 = raycast_clear_points;
|
||||
|
||||
raycast_clear_p = rch_p2;
|
||||
bool b2 = raycast_clear(map, s2, e2);
|
||||
rch_c2 = raycast_clear_points;
|
||||
|
||||
return b1 && b2;
|
||||
return raycast_clear(map, s1, e1) && raycast_clear(map, s2, e2);
|
||||
}
|
||||
|
||||
//---
|
||||
|
@ -308,8 +285,8 @@ vec2 pfc_shortcut_one(pfg_path_t const *grid, vec2 start, vec2 end,
|
|||
vec2 target = start;
|
||||
if(!grid->points) return target;
|
||||
|
||||
/* Find the furthest point that can be reached */
|
||||
for(int next = grid->length + 1; next >= 0; next--) {
|
||||
/* Find a point that can be reached directly by bisecting the path */
|
||||
for(int next = grid->length + 1; next >= 0; next /= 2) {
|
||||
vec2 p2 = (next == grid->length + 1) ? end :
|
||||
vec_i2f_center(grid->points[next]);
|
||||
|
||||
|
@ -317,6 +294,8 @@ vec2 pfc_shortcut_one(pfg_path_t const *grid, vec2 start, vec2 end,
|
|||
target = p2;
|
||||
break;
|
||||
}
|
||||
if(next == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return target;
|
||||
|
|
16
src/render.c
16
src/render.c
|
@ -13,6 +13,7 @@
|
|||
#include <gint/display.h>
|
||||
#include <gint/defs/util.h>
|
||||
#include <stdio.h>
|
||||
#include <libprof.h>
|
||||
|
||||
//---
|
||||
// Camera management
|
||||
|
@ -348,6 +349,9 @@ void render_window(int x, int y, int w, int h)
|
|||
dsubimage(x+w-20, y+h-11, &img_hud_window, 40, 11, 20, 11, DIMAGE_NONE);
|
||||
}
|
||||
|
||||
uint32_t time_render_map = 0;
|
||||
uint32_t time_render_hud = 0;
|
||||
|
||||
void render_game(game_t const *g, bool show_hitboxes)
|
||||
{
|
||||
camera_t const *camera = &g->camera;
|
||||
|
@ -360,6 +364,9 @@ void render_game(game_t const *g, bool show_hitboxes)
|
|||
ss_y = rand() % amp - (amp/2);
|
||||
}
|
||||
|
||||
prof_t ctx = prof_make();
|
||||
prof_enter(ctx);
|
||||
|
||||
/* Render map floor and floor entities */
|
||||
render_map_layer(g->map, camera, ss_x, ss_y, HORIZONTAL);
|
||||
render_entities(g, camera, floor_depth_measure, ss_x, ss_y, show_hitboxes);
|
||||
|
@ -373,9 +380,15 @@ void render_game(game_t const *g, bool show_hitboxes)
|
|||
render_map_layer(g->map, camera, ss_x, ss_y, CEILING);
|
||||
render_entities(g, camera, ceiling_depth_measure, ss_x,ss_y,show_hitboxes);
|
||||
|
||||
prof_leave(ctx);
|
||||
time_render_map = prof_time(ctx);
|
||||
|
||||
extern font_t font_rogue;
|
||||
font_t const *old_font = dfont(&font_rogue);
|
||||
|
||||
ctx = prof_make();
|
||||
prof_enter(ctx);
|
||||
|
||||
/* Render wave information */
|
||||
render_wave_info(g);
|
||||
|
||||
|
@ -446,6 +459,9 @@ void render_game(game_t const *g, bool show_hitboxes)
|
|||
}
|
||||
}
|
||||
|
||||
prof_leave(ctx);
|
||||
time_render_hud = prof_time(ctx);
|
||||
|
||||
dfont(old_font);
|
||||
}
|
||||
|
||||
|
|
16
src/skills.c
16
src/skills.c
|
@ -35,19 +35,19 @@ void skill_use(game_t *game, entity_t *e, int slot, vec2 dir)
|
|||
entity_t *aoe = aoe_make_attack(AOE_PROJECTILE, e, dir);
|
||||
game_add_entity(game, aoe);
|
||||
|
||||
if(!f->enemy_data)
|
||||
if(!f->enemy)
|
||||
visible_set_anim(e, &anims_player_Attack, 2);
|
||||
else
|
||||
visible_set_anim(e, f->enemy_data->anim_attack, 2);
|
||||
visible_set_anim(e, f->enemy->id->anim_attack, 2);
|
||||
}
|
||||
else if(skill == AOE_SHOCK) {
|
||||
entity_t *aoe = aoe_make_attack(AOE_SHOCK, e, dir);
|
||||
game_add_entity(game, aoe);
|
||||
|
||||
if(!f->enemy_data)
|
||||
if(!f->enemy)
|
||||
visible_set_anim(e, &anims_player_Attack, 2);
|
||||
else
|
||||
visible_set_anim(e, f->enemy_data->anim_attack, 2);
|
||||
visible_set_anim(e, f->enemy->id->anim_attack, 2);
|
||||
|
||||
f->current_attack = aoe;
|
||||
f->attack_follows_movement = true;
|
||||
|
@ -58,10 +58,10 @@ void skill_use(game_t *game, entity_t *e, int slot, vec2 dir)
|
|||
entity_t *aoe = aoe_make_attack(AOE_JUDGEMENT, e, dir);
|
||||
game_add_entity(game, aoe);
|
||||
|
||||
if(!f->enemy_data)
|
||||
if(!f->enemy)
|
||||
visible_set_anim(e, &anims_player_Attack, 2);
|
||||
else
|
||||
visible_set_anim(e, f->enemy_data->anim_attack, 2);
|
||||
visible_set_anim(e, f->enemy->id->anim_attack, 2);
|
||||
|
||||
game_shake(game, 3, fix(1.3));
|
||||
}
|
||||
|
@ -69,9 +69,9 @@ void skill_use(game_t *game, entity_t *e, int slot, vec2 dir)
|
|||
entity_t *aoe = aoe_make_attack(AOE_BULLET, e, dir);
|
||||
game_add_entity(game, aoe);
|
||||
|
||||
if(!f->enemy_data)
|
||||
if(!f->enemy)
|
||||
visible_set_anim(e, &anims_player_Attack, 2);
|
||||
else
|
||||
visible_set_anim(e, f->enemy_data->anim_attack, 2);
|
||||
visible_set_anim(e, f->enemy->id->anim_attack, 2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ pqueue_t pqueue_alloc(size_t size, size_t elsize,
|
|||
.alloc_size = size,
|
||||
.size = 0,
|
||||
.elsize = elsize,
|
||||
.array = malloc(size * elsize),
|
||||
.array = malloc((size+1) * elsize),
|
||||
.compare = compare,
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue