fp: Add hit particles
This commit is contained in:
parent
de7d8c1341
commit
8d01a3631f
BIN
Data/Textures/sprite_spec.txt
(Stored with Git LFS)
BIN
Data/Textures/sprite_spec.txt
(Stored with Git LFS)
Binary file not shown.
100
feely_pona.cpp
100
feely_pona.cpp
@ -3,6 +3,37 @@
|
|||||||
#include "feely_pona_unity.h"
|
#include "feely_pona_unity.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct FP_ParticleDescriptor
|
||||||
|
{
|
||||||
|
Dqn_String8 anim_name;
|
||||||
|
Dqn_V2 pos;
|
||||||
|
Dqn_V2 velocity;
|
||||||
|
Dqn_V2 velocity_variance;
|
||||||
|
Dqn_V4 colour_begin;
|
||||||
|
Dqn_V4 colour_end;
|
||||||
|
Dqn_usize duration_ms;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void FP_EmitParticle(FP_GamePlay *play, FP_ParticleDescriptor descriptor, Dqn_usize count)
|
||||||
|
{
|
||||||
|
DQN_FOR_UINDEX (index, count) {
|
||||||
|
uint32_t particle_index = play->particle_next_index++ & (DQN_ARRAY_UCOUNT(play->particles) - 1);
|
||||||
|
FP_Particle *particle = play->particles + particle_index;
|
||||||
|
if (particle->alive)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
particle->anim_name = descriptor.anim_name;
|
||||||
|
particle->alive = true;
|
||||||
|
particle->pos = descriptor.pos;
|
||||||
|
particle->velocity.x = descriptor.velocity.x + (descriptor.velocity_variance.x * (Dqn_PCG32_NextF32(&play->rng) - 0.5f));
|
||||||
|
particle->velocity.y = descriptor.velocity.y + (descriptor.velocity_variance.y * (Dqn_PCG32_NextF32(&play->rng) - 0.5f));
|
||||||
|
particle->colour_begin = descriptor.colour_begin;
|
||||||
|
particle->colour_end = descriptor.colour_end;
|
||||||
|
particle->start_ms = play->clock_ms;
|
||||||
|
particle->end_ms = play->clock_ms + descriptor.duration_ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_Assets *assets, Dqn_Arena *arena, Dqn_String8 sheet_name)
|
static TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_Assets *assets, Dqn_Arena *arena, Dqn_String8 sheet_name)
|
||||||
{
|
{
|
||||||
TELY_AssetSpriteSheet result = {};
|
TELY_AssetSpriteSheet result = {};
|
||||||
@ -2108,7 +2139,29 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
|||||||
if (!Dqn_Rect_Intersects(attacker_box, defender_box))
|
if (!Dqn_Rect_Intersects(attacker_box, defender_box))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// NOTE: Do HP =========================================================================
|
// NOTE: Emit hit particles ========================================================
|
||||||
|
FP_ParticleDescriptor particle_desc = {};
|
||||||
|
Dqn_usize particle_selector = Dqn_PCG32_Range(&game->play.rng, 0, 3);
|
||||||
|
if (particle_selector == 0) {
|
||||||
|
particle_desc.anim_name = g_anim_names.particle_hit_1;
|
||||||
|
} else if (particle_selector == 1) {
|
||||||
|
particle_desc.anim_name = g_anim_names.particle_hit_2;
|
||||||
|
} else {
|
||||||
|
particle_desc.anim_name = g_anim_names.particle_hit_3;
|
||||||
|
DQN_ASSERT(particle_selector == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
particle_desc.pos = Dqn_Rect_InterpolatedPoint(defender_box, Dqn_V2_InitNx2(0.5f, 0.0f));
|
||||||
|
particle_desc.velocity.y = -16.f;
|
||||||
|
particle_desc.velocity_variance.y = (particle_desc.velocity.y * .5f);
|
||||||
|
particle_desc.velocity_variance.x = DQN_ABS(particle_desc.velocity.y);
|
||||||
|
particle_desc.colour_begin = TELY_COLOUR_WHITE_V4;
|
||||||
|
particle_desc.colour_end = TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, 0.f);
|
||||||
|
particle_desc.duration_ms = 1000;
|
||||||
|
FP_EmitParticle(&game->play, particle_desc, Dqn_PCG32_Range(&game->play.rng, 1, 3));
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE: God mode override =========================================================
|
||||||
if (game->play.heart == defender->handle) {
|
if (game->play.heart == defender->handle) {
|
||||||
if (game->play.god_mode)
|
if (game->play.god_mode)
|
||||||
continue;
|
continue;
|
||||||
@ -2127,6 +2180,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
|||||||
if (god_mode_override)
|
if (god_mode_override)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// NOTE: Do hit logic ==============================================================
|
||||||
defender->hp = defender->hp >= attacker->base_attack ? defender->hp - attacker->base_attack : 0;
|
defender->hp = defender->hp >= attacker->base_attack ? defender->hp - attacker->base_attack : 0;
|
||||||
defender->hit_on_clock_ms = game->play.clock_ms;
|
defender->hit_on_clock_ms = game->play.clock_ms;
|
||||||
defender->trauma01 = 1.f - (defender->hp / DQN_CAST(Dqn_f32)defender->hp_cap);
|
defender->trauma01 = 1.f - (defender->hp / DQN_CAST(Dqn_f32)defender->hp_cap);
|
||||||
@ -2176,6 +2230,17 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
|||||||
|
|
||||||
game->play.global_camera_trauma01 = DQN_MAX(0.f, game->play.global_camera_trauma01 - 0.05f);
|
game->play.global_camera_trauma01 = DQN_MAX(0.f, game->play.global_camera_trauma01 - 0.05f);
|
||||||
|
|
||||||
|
// NOTE: Update all particles ==================================================================
|
||||||
|
for (FP_Particle &particle_ : game->play.particles) {
|
||||||
|
FP_Particle *particle = &particle_;
|
||||||
|
if (game->play.clock_ms >= particle->end_ms)
|
||||||
|
particle->alive = false;
|
||||||
|
if (!particle->alive)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
particle->pos += particle->velocity * DQN_CAST(Dqn_f32)input->delta_s;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Camera ================================================================================
|
// NOTE: Camera ================================================================================
|
||||||
|
|
||||||
FP_GamePlay *play = &game->play;
|
FP_GamePlay *play = &game->play;
|
||||||
@ -2773,6 +2838,39 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (FP_Particle &particle_ : game->play.particles) {
|
||||||
|
FP_Particle *particle = &particle_;
|
||||||
|
if (!particle->alive)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Dqn_usize elapsed_ms = game->play.clock_ms - particle->start_ms;
|
||||||
|
Dqn_usize duration_ms = particle->end_ms - particle->start_ms;
|
||||||
|
|
||||||
|
Dqn_f32 t = DQN_MIN(1.f, elapsed_ms / DQN_CAST(Dqn_f32)duration_ms);
|
||||||
|
Dqn_V4 colour = {};
|
||||||
|
colour.r = Dqn_Lerp_F32(particle->colour_begin.r, t, particle->colour_end.r);
|
||||||
|
colour.b = Dqn_Lerp_F32(particle->colour_begin.b, t, particle->colour_end.b);
|
||||||
|
colour.g = Dqn_Lerp_F32(particle->colour_begin.g, t, particle->colour_end.g);
|
||||||
|
colour.a = Dqn_Lerp_F32(particle->colour_begin.a, t, particle->colour_end.a);
|
||||||
|
|
||||||
|
if (particle->anim_name.size) {
|
||||||
|
TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, particle->anim_name);
|
||||||
|
Dqn_Rect tex_rect = game->atlas_sprite_sheet.rects.data[anim->index];
|
||||||
|
Dqn_Rect dest_rect = {};
|
||||||
|
dest_rect.size = tex_rect.size;
|
||||||
|
dest_rect.pos = particle->pos - (tex_rect.size * .5f);
|
||||||
|
TELY_Render_TextureColourV4(renderer,
|
||||||
|
game->atlas_sprite_sheet.tex_handle,
|
||||||
|
tex_rect,
|
||||||
|
dest_rect,
|
||||||
|
Dqn_V2_Zero /*rotate origin*/,
|
||||||
|
0.f /*rotation*/,
|
||||||
|
colour);
|
||||||
|
} else {
|
||||||
|
TELY_Render_CircleColourV4(renderer, particle->pos, 20.f, TELY_RenderShapeMode_Fill, colour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Render overlay UI =====================================================================
|
// NOTE: Render overlay UI =====================================================================
|
||||||
if (!game->play.debug_hide_hud && (game->play.state == FP_GameState_Pause || game->play.state == FP_GameState_Play)) {
|
if (!game->play.debug_hide_hud && (game->play.state == FP_GameState_Pause || game->play.state == FP_GameState_Play)) {
|
||||||
|
|
||||||
|
@ -88,9 +88,17 @@ struct FP_GlobalAnimations
|
|||||||
Dqn_String8 merchant_terry = DQN_STRING8("merchant_terry");
|
Dqn_String8 merchant_terry = DQN_STRING8("merchant_terry");
|
||||||
Dqn_String8 merchant_terry_menu = DQN_STRING8("merchant_terry_menu");
|
Dqn_String8 merchant_terry_menu = DQN_STRING8("merchant_terry_menu");
|
||||||
|
|
||||||
|
Dqn_String8 particle_church_halo = DQN_STRING8("particle_church_halo");
|
||||||
|
Dqn_String8 particle_church_cross = DQN_STRING8("particle_church_cross");
|
||||||
Dqn_String8 particle_drunk = DQN_STRING8("particle_drunk");
|
Dqn_String8 particle_drunk = DQN_STRING8("particle_drunk");
|
||||||
|
Dqn_String8 particle_drunk_bottle = DQN_STRING8("particle_drunk_bottle");
|
||||||
|
Dqn_String8 particle_drunk_martini = DQN_STRING8("particle_drunk_martini");
|
||||||
Dqn_String8 particle_heart = DQN_STRING8("particle_heart");
|
Dqn_String8 particle_heart = DQN_STRING8("particle_heart");
|
||||||
|
Dqn_String8 particle_hit_1 = DQN_STRING8("particle_hit_1");
|
||||||
|
Dqn_String8 particle_hit_2 = DQN_STRING8("particle_hit_2");
|
||||||
|
Dqn_String8 particle_hit_3 = DQN_STRING8("particle_hit_3");
|
||||||
Dqn_String8 particle_purchase = DQN_STRING8("particle_purchase");
|
Dqn_String8 particle_purchase = DQN_STRING8("particle_purchase");
|
||||||
|
|
||||||
Dqn_String8 portal = DQN_STRING8("portal");
|
Dqn_String8 portal = DQN_STRING8("portal");
|
||||||
Dqn_String8 portal_break = DQN_STRING8("portal_break");
|
Dqn_String8 portal_break = DQN_STRING8("portal_break");
|
||||||
Dqn_String8 portal_monk = DQN_STRING8("portal_monk");
|
Dqn_String8 portal_monk = DQN_STRING8("portal_monk");
|
||||||
|
@ -351,6 +351,18 @@ enum FP_GamePerryJoined
|
|||||||
FP_GamePerryJoins_PostEnter,
|
FP_GamePerryJoins_PostEnter,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FP_Particle
|
||||||
|
{
|
||||||
|
Dqn_String8 anim_name;
|
||||||
|
bool alive;
|
||||||
|
Dqn_V2 pos;
|
||||||
|
Dqn_V2 velocity;
|
||||||
|
Dqn_V4 colour_begin;
|
||||||
|
Dqn_V4 colour_end;
|
||||||
|
Dqn_usize start_ms;
|
||||||
|
Dqn_usize end_ms;
|
||||||
|
};
|
||||||
|
|
||||||
struct FP_GamePlay
|
struct FP_GamePlay
|
||||||
{
|
{
|
||||||
TELY_ChunkPool *chunk_pool;
|
TELY_ChunkPool *chunk_pool;
|
||||||
@ -410,6 +422,9 @@ struct FP_GamePlay
|
|||||||
Dqn_V2 perry_join_splash_screen_pos;
|
Dqn_V2 perry_join_splash_screen_pos;
|
||||||
uint64_t perry_join_splash_screen_end_ms;
|
uint64_t perry_join_splash_screen_end_ms;
|
||||||
Dqn_V2 perry_join_splash_pos_offset;
|
Dqn_V2 perry_join_splash_pos_offset;
|
||||||
|
|
||||||
|
FP_Particle particles[256];
|
||||||
|
uint32_t particle_next_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FP_Game
|
struct FP_Game
|
||||||
|
Loading…
Reference in New Issue
Block a user