prepare more attacks (skills/combos)
This commit is contained in:
parent
89ee5234ea
commit
35718b93ac
|
@ -57,6 +57,7 @@ set(ASSETS
|
|||
assets-cg/skills/swing_right.png
|
||||
assets-cg/skills/swing_down.png
|
||||
assets-cg/skills/swing_left.png
|
||||
assets-cg/skills/impale_right.png
|
||||
assets-cg/skills/hit.png
|
||||
assets-cg/skills/teleport.png
|
||||
# Enemies: Slime
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
swing_*.png:
|
||||
frame_duration: 30, 60, 30, 30, 30, 60, 30
|
||||
|
||||
impale_*.png:
|
||||
frame_duration: 60, 60, 60, 60, 60
|
||||
|
||||
hit.png:
|
||||
frame_duration: 60, 90, 90, 60, 90
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 181 B |
|
@ -17,6 +17,10 @@ DIRECTIONAL_ANIM(anim_player_attack);
|
|||
DIRECTIONAL_ANIM(anim_player_damage);
|
||||
DIRECTIONAL_ANIM(anim_swing);
|
||||
|
||||
extern anim_frame_t anim_impale_right[];
|
||||
anim_frame_t *anim_impale[4] = {
|
||||
anim_impale_right, anim_impale_right, anim_impale_right, anim_impale_right };
|
||||
|
||||
/* Animation functions. */
|
||||
|
||||
fixed_t (anim_duration)(anim_frame_t const *first_frame)
|
||||
|
|
|
@ -72,3 +72,4 @@ extern anim_frame_t *anim_player_idle[4];
|
|||
extern anim_frame_t *anim_player_attack[4];
|
||||
extern anim_frame_t *anim_player_damage[4];
|
||||
extern anim_frame_t *anim_swing[4];
|
||||
extern anim_frame_t *anim_impale[4];
|
||||
|
|
|
@ -177,6 +177,48 @@ effect_area_t *effect_area_new(uint16_t type)
|
|||
return ea;
|
||||
}
|
||||
|
||||
effect_area_t *effect_area_new_attack(uint16_t type, entity_t *e, int facing)
|
||||
{
|
||||
effect_area_t *area = effect_area_new(type);
|
||||
if(!area) return NULL;
|
||||
|
||||
frect_t hitbox = { 0 };
|
||||
fixed_t distance = fix(0.75);
|
||||
fpoint_t dir = fdir(facing);
|
||||
anim_frame_t *anim = NULL;
|
||||
|
||||
if(type == EFFECT_ATTACK_HIT) {
|
||||
anim = anim_hit;
|
||||
hitbox = (frect_t){ -fix(4)/16, fix(3)/16, -fix(4)/16, fix(3)/16 };
|
||||
}
|
||||
else if(type == EFFECT_ATTACK_SLASH) {
|
||||
anim = anim_swing[facing];
|
||||
hitbox = (frect_t){ -fix(10)/16, fix(10)/16, -fix(4)/16, fix(4)/16 };
|
||||
}
|
||||
else if(type == EFFECT_ATTACK_IMPALE) {
|
||||
anim = anim_impale[facing];
|
||||
hitbox = (frect_t){ -fix(4)/16, fix(4)/16, -fix(5)/16, fix(5)/16 };
|
||||
}
|
||||
|
||||
area->sprite = rect_rotate(hitbox, UP, facing);
|
||||
area->anchor = rect_center(entity_sprite(e));
|
||||
area->anchor.x += fmul(distance, dir.x);
|
||||
area->anchor.y += fmul(distance, dir.y);
|
||||
area->lifetime = anim_duration(anim);
|
||||
area->repeat_delay = 0;
|
||||
area->origin = e;
|
||||
|
||||
if(type == EFFECT_ATTACK_HIT
|
||||
|| type == EFFECT_ATTACK_SLASH
|
||||
|| type == EFFECT_ATTACK_IMPALE) {
|
||||
area->data.slash.strength = e->ATK;
|
||||
area->data.slash.dir = facing;
|
||||
}
|
||||
|
||||
effect_area_set_anim(area, anim);
|
||||
return area;
|
||||
}
|
||||
|
||||
void effect_area_set_anim(effect_area_t *ea, anim_frame_t *frame)
|
||||
{
|
||||
ea->anim.frame = frame;
|
||||
|
@ -236,9 +278,9 @@ void effect_area_apply(game_t *game, effect_area_t *ea, entity_t *e)
|
|||
if(rec && ea->repeat_delay == 0) return;
|
||||
if(rec && ea->lifetime > rec->lifetime - ea->repeat_delay) return;
|
||||
|
||||
if(ea->type == EFFECT_HIT)
|
||||
was_hit = slash_hit_apply(game, ea, e);
|
||||
else if(ea->type == EFFECT_SLASH)
|
||||
if(ea->type == EFFECT_ATTACK_HIT
|
||||
|| ea->type == EFFECT_ATTACK_SLASH
|
||||
|| ea->type == EFFECT_ATTACK_IMPALE)
|
||||
was_hit = slash_hit_apply(game, ea, e);
|
||||
|
||||
if(!was_hit) return;
|
||||
|
|
|
@ -42,6 +42,14 @@ typedef struct {
|
|||
|
||||
} entity_movement_t;
|
||||
|
||||
typedef struct {
|
||||
/* Number of hits in the main combo (TODO: delegate to weapon?) */
|
||||
uint8_t combo_length;
|
||||
/* Next hit to be dealt */
|
||||
uint8_t combo_next;
|
||||
|
||||
} entity_player_t;
|
||||
|
||||
/* Alive agents with hitboxes and movement control */
|
||||
typedef struct {
|
||||
/* Map hitbox, centered around (movement.x, movement.y) */
|
||||
|
@ -52,6 +60,8 @@ typedef struct {
|
|||
entity_movement_t movement;
|
||||
/* Cinematic parameters */
|
||||
entity_movement_params_t const *movement_params;
|
||||
/* Player-only parameters */
|
||||
entity_player_t const *player;
|
||||
/* Animated image and state */
|
||||
anim_state_t anim;
|
||||
/* Current attack's effect area */
|
||||
|
@ -107,9 +117,11 @@ int entity_damage(entity_t *e, int base_damage);
|
|||
|
||||
enum {
|
||||
/* Bare-hand fist/close-contact attack */
|
||||
EFFECT_HIT,
|
||||
EFFECT_ATTACK_HIT,
|
||||
/* Normal attack by a slashing weapon */
|
||||
EFFECT_SLASH,
|
||||
EFFECT_ATTACK_SLASH,
|
||||
/* Impaling attack using a slashing weapon */
|
||||
EFFECT_ATTACK_IMPALE,
|
||||
/* Monster spawning */
|
||||
EFFECT_SPAWN,
|
||||
};
|
||||
|
@ -156,6 +168,10 @@ typedef struct effect_area {
|
|||
* sprite, anchor, lifetime, anim, repeat_delay, and data should be set. */
|
||||
effect_area_t *effect_area_new(uint16_t type);
|
||||
|
||||
/* Create an effect area for a particular attack
|
||||
All additional parameters are set by this function. */
|
||||
effect_area_t *effect_area_new_attack(uint16_t type, entity_t *e, int facing);
|
||||
|
||||
/* Set area animation */
|
||||
void effect_area_set_anim(effect_area_t *ea, anim_frame_t *frame);
|
||||
|
||||
|
|
53
src/main.c
53
src/main.c
|
@ -223,8 +223,13 @@ int main(void)
|
|||
fkey_button(5, "PERF", debug.show_perf ? fg : C_WHITE);
|
||||
}
|
||||
|
||||
if(keydown(KEY_F6) && !keydown(KEY_VARS) && usb_is_open())
|
||||
usb_fxlink_screenshot(false);
|
||||
static bool record = false;
|
||||
if(keydown(KEY_F6) && !keydown(KEY_VARS) && usb_is_open()) {
|
||||
record = !record;
|
||||
}
|
||||
if(record) {
|
||||
usb_fxlink_videocapture(false);
|
||||
}
|
||||
|
||||
/* Instead of dupdate(); for accurate performance measurements. Leaving
|
||||
the DMA running during the simulation affects the results in extreme
|
||||
|
@ -392,32 +397,15 @@ int main(void)
|
|||
enemies[e->identity]->anim_idle[e->movement.facing == RIGHT]);
|
||||
|
||||
if(in_range && !e->current_attack) {
|
||||
/* Attack */
|
||||
frect_t hitbox = {
|
||||
-fix(4)/16, fix(3)/16, -fix(4)/16, fix(3)/16,
|
||||
};
|
||||
/* Enemy attack */
|
||||
int facing = frdir((fpoint_t){
|
||||
player->movement.x - e->movement.x,
|
||||
player->movement.y - e->movement.y });
|
||||
hitbox = rect_rotate(hitbox, UP, facing);
|
||||
fpoint_t dir = fdir(facing);
|
||||
|
||||
fpoint_t anchor = rect_center(entity_sprite(e));
|
||||
anchor.x += fmul(fix(0.75), dir.x);
|
||||
anchor.y += fmul(fix(0.75), dir.y);
|
||||
|
||||
effect_area_t *area = effect_area_new(EFFECT_HIT);
|
||||
area->sprite = hitbox;
|
||||
area->anchor = anchor;
|
||||
area->lifetime = anim_duration(anim_hit);
|
||||
area->repeat_delay = 0;
|
||||
area->origin = e;
|
||||
area->data.slash.strength = e->ATK;
|
||||
area->data.slash.dir = e->movement.facing;
|
||||
effect_area_set_anim(area, anim_hit);
|
||||
effect_area_t *area = effect_area_new_attack(EFFECT_ATTACK_HIT,
|
||||
e, facing);
|
||||
game_add_effect_area(&game, area);
|
||||
|
||||
// entity_set_anim(player, anim_player_attack);
|
||||
e->current_attack = area;
|
||||
e->attack_follows_movement = true;
|
||||
}
|
||||
|
@ -425,25 +413,8 @@ int main(void)
|
|||
|
||||
/* Player attack */
|
||||
if(player->HP > 0 && attack && !player->current_attack) {
|
||||
frect_t hitbox = {
|
||||
-fix(10)/16, fix(10)/16, -fix(4)/16, fix(4)/16,
|
||||
};
|
||||
hitbox = rect_rotate(hitbox, UP, player->movement.facing);
|
||||
fpoint_t dir = fdir(player->movement.facing);
|
||||
|
||||
fpoint_t anchor = rect_center(entity_sprite(player));
|
||||
anchor.x += fmul(fix(0.75), dir.x);
|
||||
anchor.y += fmul(fix(0.75), dir.y);
|
||||
|
||||
effect_area_t *area = effect_area_new(EFFECT_SLASH);
|
||||
area->sprite = hitbox;
|
||||
area->anchor = anchor;
|
||||
area->lifetime = anim_duration(anim_swing);
|
||||
area->repeat_delay = 0;
|
||||
area->origin = player;
|
||||
area->data.slash.strength = player->ATK;
|
||||
area->data.slash.dir = player->movement.facing;
|
||||
effect_area_set_anim(area, anim_swing[player->movement.facing]);
|
||||
effect_area_t *area = effect_area_new_attack(EFFECT_ATTACK_SLASH,
|
||||
player, player->movement.facing);
|
||||
game_add_effect_area(&game, area);
|
||||
|
||||
entity_set_anim(player, anim_player_attack);
|
||||
|
|
15
src/render.c
15
src/render.c
|
@ -224,16 +224,16 @@ void render_game(game_t const *g, bool show_hitboxes)
|
|||
g->level->waves[g->wave-1].enemy_count, img_hud_wave2.height,
|
||||
DIMAGE_NONE);
|
||||
|
||||
if(enemies_left > 0)
|
||||
if(g->wave_spawned < game_current_wave(g)->enemy_count)
|
||||
dprint_opt(DWIDTH / 2, 2, C_WHITE, C_NONE, DTEXT_CENTER, DTEXT_TOP,
|
||||
"Wave %d: %d/%d enemies left", g->wave, enemies_left,
|
||||
g->level->waves[g->wave-1].enemy_count);
|
||||
else if(g->wave_spawned >= game_current_wave(g)->enemy_count)
|
||||
"Wave %d: %d enemies spawning", g->wave,
|
||||
game_current_wave(g)->enemy_count - g->wave_spawned);
|
||||
else if(enemies_left > 0)
|
||||
dprint_opt(DWIDTH / 2, 2, C_WHITE, C_NONE, DTEXT_CENTER, DTEXT_TOP,
|
||||
"Wave %d: Victory!", g->wave);
|
||||
"Wave %d: %d enemies left", g->wave, enemies_left);
|
||||
else
|
||||
dprint_opt(DWIDTH / 2, 2, C_WHITE, C_NONE, DTEXT_CENTER, DTEXT_TOP,
|
||||
"Wave %d: Starting...", g->wave);
|
||||
"Wave %d: Victory!", g->wave);
|
||||
|
||||
entity_t const *player = g->player;
|
||||
dprint(2, 2, C_WHITE, "HP: %d", player->HP);
|
||||
|
@ -249,6 +249,9 @@ void render_game(game_t const *g, bool show_hitboxes)
|
|||
cooldown_total = player->movement_params->dash_cooldown;
|
||||
cooldown_remaining = -player->movement.dash;
|
||||
}
|
||||
else if(i > 0) {
|
||||
cooldown_remaining=fix(1);
|
||||
}
|
||||
|
||||
int x=15+68*i, y=DHEIGHT-28, bg=(cooldown_remaining!=0);
|
||||
dsubimage(x, y, &img_skillicons, 23*bg, 0, 23, 23, DIMAGE_NONE);
|
||||
|
|
Loading…
Reference in New Issue