screenshake during major attacks

This commit is contained in:
Lephenixnoir 2022-02-02 10:16:59 +01:00
parent 45b13d898c
commit b04333ddda
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
5 changed files with 53 additions and 8 deletions

View File

@ -191,6 +191,10 @@ static bool attack_apply(game_t *game, aoe_t *aoe, entity_t *target)
(target_f->enemy_data == NULL) ? C_RED : C_WHITE);
game_add_entity(game, particle);
/* Quick screenshake for entities hit by a bullet */
if(aoe->type == AOE_BULLET)
game_shake(game, 3, fix(0.1));
return true;
}

View File

@ -9,6 +9,7 @@
#include "comp/particle.h"
#include "aoe.h"
#include <gint/defs/util.h>
#include <stdlib.h>
bool game_load(game_t *g, level_t const *level)
@ -87,6 +88,15 @@ void game_next_wave(game_t *g)
g->wave_left[i] = wave->entries[i].amount;
}
void game_shake(game_t *g, int amplitude, fixed_t duration)
{
if(g->screenshake_amplitude > amplitude)
return;
g->screenshake_duration = max(g->screenshake_duration, duration);
g->screenshake_amplitude = amplitude;
}
//---
// Object management functions
//---

View File

@ -23,6 +23,9 @@ typedef struct game {
/* Time when victory was reached or defeat was dealt */
fixed_t time_victory;
fixed_t time_defeat;
/* Screenshake duration left (effect disabled when 0), and amplitude */
fixed_t screenshake_duration;
int screenshake_amplitude;
/* List of entities */
entity_t **entities;
int entity_count;
@ -59,6 +62,9 @@ bool game_current_wave_finished(game_t const *g);
/* Move to next wave */
void game_next_wave(game_t *g);
/* Shake the screen for the specified amount of time */
void game_shake(game_t *g, int amplitude, fixed_t duration);
//---
// Managing dynamic game elements
//---

View File

@ -24,6 +24,7 @@
#include <gint/timer.h>
#include <gint/kmalloc.h>
#include <gint/drivers/r61524.h>
#include <gint/defs/util.h>
#include <stdlib.h>
#include <string.h>
@ -568,6 +569,8 @@ int main(void)
visible_set_anim(player, &anims_player_Attack, 2);
player_f->current_attack = aoe;
player_f->attack_follows_movement = true;
game_shake(&game, 9, fix(0.7));
}
if(can_attack && keydown(KEY_F3)) {
entity_t *aoe = aoe_make_attack( AOE_JUDGEMENT, player,
@ -577,6 +580,8 @@ int main(void)
visible_set_anim(player, &anims_player_Attack, 2);
player_f->current_attack = aoe;
player_f->attack_follows_movement = false;
game_shake(&game, 5, fix(1.3));
}
if(can_attack && keydown(KEY_F4)) {
entity_t *aoe = aoe_make_attack(AOE_BULLET, player,
@ -619,6 +624,13 @@ int main(void)
}
}
/* Reduce screenshake time */
game.screenshake_duration -= dt;
if(game.screenshake_duration < 0) {
game.screenshake_duration = 0;
game.screenshake_amplitude = 0;
}
game.time_total += dt;
game.time_wave += dt;

View File

@ -120,7 +120,8 @@ fixed_t camera_ppu(camera_t const *c)
// Rendering
//---
static void render_map_layer(map_t const *m, camera_t const *c, int layer)
static void render_map_layer(map_t const *m, camera_t const *c, int ss_x,
int ss_y, int layer)
{
/* Render floor and walls */
for(int row = -2; row < m->height + 2; row++)
@ -128,6 +129,8 @@ static void render_map_layer(map_t const *m, camera_t const *c, int layer)
tile_t *t = map_tile(m, col, row);
vec2 tile_pos = { fix(col), fix(row) };
ivec2 p = camera_map2screen(c, tile_pos);
p.x += ss_x;
p.y += ss_y;
if(!t && layer == CEILING) {
drect(p.x, p.y, p.x+15, p.y+15, C_BLACK);
@ -208,7 +211,7 @@ static void render_shadow(int cx, int cy, int shadow_size)
}
static void render_entities(game_t const *g, camera_t const *camera,
entity_measure_t *measure, bool show_hitboxes)
entity_measure_t *measure, int ss_x, int ss_y, bool show_hitboxes)
{
uint16_t *rendering_order;
int count = game_sort_entities(g, measure, &rendering_order);
@ -231,6 +234,8 @@ static void render_entities(game_t const *g, camera_t const *camera,
}
ivec2 scr = camera_map2screen(camera, xy);
scr.x += ss_x;
scr.y += ss_y;
int elevated_y = scr.y - fround(16 * z);
/* Show shadow */
@ -346,18 +351,26 @@ void render_game(game_t const *g, bool show_hitboxes)
{
camera_t const *camera = &g->camera;
/* Screenshake displacement */
int ss_x=0, ss_y=0;
if(g->screenshake_duration > 0) {
int amp = g->screenshake_amplitude;
ss_x = rand() % amp - (amp/2);
ss_y = rand() % amp - (amp/2);
}
/* Render map floor and floor entities */
render_map_layer(g->map, camera, HORIZONTAL);
render_entities(g, camera, floor_depth_measure, show_hitboxes);
render_map_layer(g->map, camera, ss_x, ss_y, HORIZONTAL);
render_entities(g, camera, floor_depth_measure, ss_x, ss_y, show_hitboxes);
/* Render map walls and vertical entities
TODO ECS: Sort walls and wall entities together for proper ordering!*/
render_map_layer(g->map, camera, VERTICAL);
render_entities(g, camera, wall_depth_measure, show_hitboxes);
render_map_layer(g->map, camera, ss_x, ss_y, VERTICAL);
render_entities(g, camera, wall_depth_measure, ss_x, ss_y, show_hitboxes);
/* Render ceiling tiles (including out of bounds) and ceiling entities */
render_map_layer(g->map, camera, CEILING);
render_entities(g, camera, ceiling_depth_measure, 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);
extern font_t font_rogue;
font_t const *old_font = dfont(&font_rogue);