add judgement skill, improve anim format

This commit is contained in:
Lephenixnoir 2021-10-17 16:22:09 +02:00
parent 59c7a9282d
commit a2e35698fe
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
23 changed files with 108 additions and 63 deletions

View File

@ -47,16 +47,17 @@ set(ASSETS
assets-cg/player/player_down.aseprite
assets-cg/player/player_left.aseprite
# Skill animations
assets-cg/skills/swing_up.png
assets-cg/skills/swing_right.png
assets-cg/skills/swing_down.png
assets-cg/skills/swing_left.png
assets-cg/skills/impale_up.png
assets-cg/skills/impale_right.png
assets-cg/skills/impale_down.png
assets-cg/skills/impale_left.png
assets-cg/skills/hit.png
assets-cg/skills/teleport.png
assets-cg/skills/swing_up.aseprite
assets-cg/skills/swing_right.aseprite
assets-cg/skills/swing_down.aseprite
assets-cg/skills/swing_left.aseprite
assets-cg/skills/impale_up.aseprite
assets-cg/skills/impale_right.aseprite
assets-cg/skills/impale_down.aseprite
assets-cg/skills/impale_left.aseprite
assets-cg/skills/hit.aseprite
assets-cg/skills/judgement.aseprite
assets-cg/skills/teleport.aseprite
assets-cg/skills/shock.aseprite
# Enemies: Slime
assets-cg/enemies/slime_idle_left.png

View File

@ -215,7 +215,8 @@ def convert_aseprite_anim(input, output, params):
print(f"{os.path.basename(input)} ({ase.header.width}x{ase.header.height})",
f"has {len(tags)} animations:")
for (name, from_, to) in tags:
print(f" '{name}': Frames {from_} to {to}", end="")
name = f"'{name}'" if name else "(untagged)"
print(f" {name}: Frames {from_} to {to}", end="")
durations = [ase.frames[i].frame_duration for i in range(from_, to+1)]
print(" (" + ", ".join(f"{d} ms" for d in durations) + ")")
@ -232,6 +233,12 @@ def convert_aseprite_anim(input, output, params):
if chunk.chunk_type == 0x2005: # Cel
# Render only visible layers
if ase.layers[chunk.layer_index].flags & 1:
# Resolve linked cells
if chunk.cel_type == 1: # Linked cel
x = ase.frames[chunk.data['link'][0]].chunks
x = [c for c in x if c.chunk_type == 0x2005]
chunk = x[chunk.layer_index]
cel = _aseprite_render_cel(chunk)
img.paste(cel, (chunk.x_pos, chunk.y_pos))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 707 B

After

Width:  |  Height:  |  Size: 769 B

View File

@ -1,24 +1,34 @@
*.png:
custom-type: animation
name_regex: (.*)\.png anim_\1
center: 0, 0
profile: p8
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
teleport.png:
frame_duration: 90, 90, 90, 60, 60
*.aseprite:
custom-type: aseprite-anim
name_regex: (.*)\.aseprite anims_skill_\1
center: 0, 0
profile: p8
profile: p4
hit.aseprite:
center: 3, 3
impale_up.aseprite:
center: 4, 10
impale_right.aseprite:
center: 0, 4
impale_left.aseprite:
center: 10, 4
impale_down.aseprite:
center: 4, 0
judgement.aseprite:
center: 10, 26
teleport.aseprite:
center: 8, 19
shock.aseprite:
center: 18, 18
swing_up.aseprite:
center: 9, 8
swing_right.aseprite:
center: 0, 9
swing_left.aseprite:
center: 8, 9
swing_down.aseprite:
center: 9, 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

View File

@ -24,8 +24,8 @@
prefix ## _left_ ## suffix, \
};
DIRECTIONAL_ANIM(anim_swing);
DIRECTIONAL_ANIM(anim_impale);
DIRECTIONAL_ANIM(anims_skill_swing);
DIRECTIONAL_ANIM(anims_skill_impale);
ANIM_4DIRECTIONAL(anims_player, Idle);
ANIM_4DIRECTIONAL(anims_player, Walking);

View File

@ -48,9 +48,10 @@ void anim_state_update(anim_state_t *state, fixed_t dt);
/* List of animations. */
/* Basic animations. */
extern anim_frame_t anim_hit[];
extern anim_frame_t anim_teleport[];
extern anim_frame_t anims_skill_hit[];
extern anim_frame_t anims_skill_teleport[];
extern anim_frame_t anims_skill_shock[];
extern anim_frame_t anims_skill_judgement[];
/* Enemy animations (bidirectional). */
@ -73,5 +74,5 @@ extern anim_frame_t *anims_player_Idle[4];
extern anim_frame_t *anims_player_Walking[4];
extern anim_frame_t *anims_player_Attack[4];
extern anim_frame_t *anims_player_Hit[4];
extern anim_frame_t *anim_swing[4];
extern anim_frame_t *anim_impale[4];
extern anim_frame_t *anims_skill_swing[4];
extern anim_frame_t *anims_skill_impale[4];

View File

@ -192,30 +192,45 @@ effect_area_t *effect_area_new_attack(uint16_t type, entity_t *e, int facing)
if(!area) return NULL;
frect_t hitbox = { 0 };
fixed_t distance = fix(0.75);
fixed_t distance = fix(0.625);
fpoint_t dir = fdir(facing);
fpoint_t anchor = rect_center(entity_sprite(e));
anim_frame_t *anim = NULL;
bool rotate = true;
if(type == EFFECT_ATTACK_HIT) {
anim = anim_hit;
anim = anims_skill_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 };
anim = anims_skill_swing[facing];
hitbox = (frect_t){ -fix(10)/16, fix(10)/16, -fix(8)/16, 0 };
if(facing == UP || facing == DOWN)
anchor = entity_pos(e);
}
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 };
anim = anims_skill_impale[facing];
hitbox = (frect_t){ -fix(4)/16, fix(4)/16, -fix(10)/16, 0 };
if(facing == UP || facing == DOWN)
anchor = entity_pos(e);
}
else if(type == EFFECT_ATTACK_SHOCK) {
anim = anims_skill_shock;
hitbox = (frect_t){ -fix(18)/16, fix(18)/16, -fix(19)/16, fix(19)/16 };
hitbox = (frect_t){ -fix(17)/16, fix(18)/16, -fix(17)/16, fix(18)/16 };
anchor = entity_pos(e);
distance = fix(0);
rotate = false;
}
else if(type == EFFECT_ATTACK_JUDGEMENT) {
anim = anims_skill_judgement;
hitbox = (frect_t){ -fix(10)/16, fix(11)/16, -fix(6)/16, fix(6)/16 };
anchor = entity_pos(e);
distance = fix(1.5);
rotate = false;
}
area->sprite = rect_rotate(hitbox, UP, facing);
area->anchor = rect_center(entity_sprite(e));
area->sprite = rotate ? rect_rotate(hitbox, UP, facing) : hitbox;
area->anchor = anchor;
area->anchor.x += fmul(distance, dir.x);
area->anchor.y += fmul(distance, dir.y);
area->lifetime = anim_duration(anim);
@ -224,9 +239,10 @@ effect_area_t *effect_area_new_attack(uint16_t type, entity_t *e, int facing)
if(type == EFFECT_ATTACK_HIT
|| type == EFFECT_ATTACK_SLASH
|| type == EFFECT_ATTACK_IMPALE) {
area->data.slash.strength = e->ATK;
area->data.slash.dir = facing;
|| type == EFFECT_ATTACK_IMPALE
|| type == EFFECT_ATTACK_JUDGEMENT) {
area->data.generic.strength = e->ATK;
area->data.generic.dir = facing;
}
else if(type == EFFECT_ATTACK_SHOCK) {
area->data.shock.strength = e->ATK;
@ -275,8 +291,8 @@ static bool attack_apply(game_t *game, effect_area_t *ea, entity_t *e)
if(ea->type == EFFECT_ATTACK_HIT
|| ea->type == EFFECT_ATTACK_SLASH
|| ea->type == EFFECT_ATTACK_IMPALE) {
dir = fdir(ea->data.slash.dir);
damage = ea->data.slash.strength;
dir = fdir(ea->data.generic.dir);
damage = ea->data.generic.strength;
}
else if(ea->type == EFFECT_ATTACK_SHOCK) {
dir.x = e->movement.x - ea->data.shock.origin.x;
@ -284,6 +300,10 @@ static bool attack_apply(game_t *game, effect_area_t *ea, entity_t *e)
dir = fnormalize(dir);
damage = ea->data.shock.strength * 3 / 2;
}
else if(ea->type == EFFECT_ATTACK_JUDGEMENT) {
r = fix(0);
damage = ea->data.generic.strength * 5;
}
/* Inflict damage */
damage = entity_damage(e, damage);
@ -316,7 +336,8 @@ void effect_area_apply(game_t *game, effect_area_t *ea, entity_t *e)
if(ea->type == EFFECT_ATTACK_HIT
|| ea->type == EFFECT_ATTACK_SLASH
|| ea->type == EFFECT_ATTACK_IMPALE
|| ea->type == EFFECT_ATTACK_SHOCK)
|| ea->type == EFFECT_ATTACK_SHOCK
|| ea->type == EFFECT_ATTACK_JUDGEMENT)
was_hit = attack_apply(game, ea, e);
if(!was_hit) return;

View File

@ -130,8 +130,9 @@ enum {
EFFECT_ATTACK_SLASH,
/* Impaling attack using a slashing weapon */
EFFECT_ATTACK_IMPALE,
/* Shock attack */
/* Skills */
EFFECT_ATTACK_SHOCK,
EFFECT_ATTACK_JUDGEMENT,
/* Monster spawning */
EFFECT_SPAWN,
};
@ -166,10 +167,8 @@ typedef struct effect_area {
uint16_t type;
/* Effect data (type-dependent) */
union {
/* EFFECT_ATTACK_HIT: source and ATK strength */
struct { int strength; int dir; } hit;
/* EFFECT_ATTACK_SLASH: source and ATK strength */
struct { int strength; int dir; } slash;
/* Generic attacks: source and ATK strength */
struct { int strength; int dir; } generic;
/* EFFECT_ATTACK_SHOCK: origin and ATK strength */
struct { int strength; fpoint_t origin; } shock;
} data;

View File

@ -112,10 +112,10 @@ void game_spawn_entity(game_t *g, entity_t *e, fpoint_t pos)
effect_area_t *area = effect_area_new(EFFECT_SPAWN);
area->sprite = hitbox;
area->anchor = entity_pos(e);
area->lifetime = anim_duration(anim_teleport);
area->lifetime = anim_duration(anims_skill_teleport);
area->repeat_delay = 0;
area->origin = e;
effect_area_set_anim(area, anim_teleport);
effect_area_set_anim(area, anims_skill_teleport);
game_add_effect_area(g, area);
e->current_attack = area;

View File

@ -459,6 +459,15 @@ int main(void)
player->current_attack = area;
player->attack_follows_movement = true;
}
if(player->HP > 0 && keydown(KEY_F3) && !player->current_attack) {
effect_area_t *area = effect_area_new_attack(
EFFECT_ATTACK_JUDGEMENT, player, player->movement.facing);
game_add_effect_area(&game, area);
entity_set_anim(player, anims_player_Attack, 2);
player->current_attack = area;
player->attack_follows_movement = false;
}
/* Remove dead entities first as it will kill their attack areas */
game_remove_dead_entities(&game);

View File

@ -145,10 +145,7 @@ static void render_effect_area(effect_area_t const *ea, camera_t const *c,
ipoint_t anchor = camera_map2screen(c, ea->anchor);
if(ea->anim.frame) {
fpoint_t top_left = {
ea->anchor.x + ea->sprite.l,
ea->anchor.y + ea->sprite.t };
ipoint_t p = camera_map2screen(c, top_left);
ipoint_t p = camera_map2screen(c, ea->anchor);
anim_frame_render(p.x, p.y, ea->anim.frame);
}
if(!ea->anim.frame || show_hitboxes) {