fp: Integrate new billboard

This commit is contained in:
doyle 2023-10-23 22:13:03 +11:00
parent f5de988246
commit 206773607c
9 changed files with 132 additions and 90 deletions

BIN
Data/Textures/atlas.png (Stored with Git LFS)

Binary file not shown.

BIN
Data/Textures/atlas.txt (Stored with Git LFS)

Binary file not shown.

BIN
Data/Textures/atlas/map_billboard_build.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/sprite_spec.txt (Stored with Git LFS)

Binary file not shown.

View File

@ -18,23 +18,23 @@ static FP_ParticleDescriptor FP_DefaultFloatUpParticleDescriptor(Dqn_String8 ani
return result; return result;
} }
static void FP_EmitParticle(FP_GamePlay *play, FP_ParticleDescriptor descriptor, Dqn_usize count) static void FP_EmitParticle(FP_Game *game, FP_ParticleDescriptor descriptor, Dqn_usize count)
{ {
DQN_FOR_UINDEX (index, count) { DQN_FOR_UINDEX (index, count) {
uint32_t particle_index = play->particle_next_index++ & (DQN_ARRAY_UCOUNT(play->particles) - 1); uint32_t particle_index = game->play.particle_next_index++ & (DQN_ARRAY_UCOUNT(game->play.particles) - 1);
FP_Particle *particle = play->particles + particle_index; FP_Particle *particle = game->play.particles + particle_index;
if (particle->alive) if (particle->alive)
continue; continue;
particle->anim_name = descriptor.anim_name; particle->anim_name = Dqn_String8_Copy(Dqn_Arena_Allocator(game->frame_arena), descriptor.anim_name);
particle->alive = true; particle->alive = true;
particle->pos = descriptor.pos; particle->pos = descriptor.pos;
particle->velocity.x = descriptor.velocity.x + (descriptor.velocity_variance.x * (Dqn_PCG32_NextF32(&play->rng) - 0.5f)); particle->velocity.x = descriptor.velocity.x + (descriptor.velocity_variance.x * (Dqn_PCG32_NextF32(&game->play.rng) - 0.5f));
particle->velocity.y = descriptor.velocity.y + (descriptor.velocity_variance.y * (Dqn_PCG32_NextF32(&play->rng) - 0.5f)); particle->velocity.y = descriptor.velocity.y + (descriptor.velocity_variance.y * (Dqn_PCG32_NextF32(&game->play.rng) - 0.5f));
particle->colour_begin = descriptor.colour_begin; particle->colour_begin = descriptor.colour_begin;
particle->colour_end = descriptor.colour_end; particle->colour_end = descriptor.colour_end;
particle->start_ms = play->clock_ms; particle->start_ms = game->play.clock_ms;
particle->end_ms = play->clock_ms + descriptor.duration_ms; particle->end_ms = game->play.clock_ms + descriptor.duration_ms;
} }
} }
@ -385,6 +385,7 @@ static void FP_PlayReset(FP_Game *game, TELY_Platform *platform)
FP_Entity_CreateBillboard(game, Dqn_V2_InitNx2(2047, -720), FP_EntityBillboardState_RangeAttack, "Range Attack Billboard"); FP_Entity_CreateBillboard(game, Dqn_V2_InitNx2(2047, -720), FP_EntityBillboardState_RangeAttack, "Range Attack Billboard");
FP_Entity_CreateBillboard(game, Dqn_V2_InitNx2(-936, -500), FP_EntityBillboardState_Monkey, "Monkey Billboard"); FP_Entity_CreateBillboard(game, Dqn_V2_InitNx2(-936, -500), FP_EntityBillboardState_Monkey, "Monkey Billboard");
FP_Entity_CreateBillboard(game, Dqn_V2_InitNx2(1898, 771), FP_EntityBillboardState_Strafe, "Strafe Billboard"); FP_Entity_CreateBillboard(game, Dqn_V2_InitNx2(1898, 771), FP_EntityBillboardState_Strafe, "Strafe Billboard");
FP_Entity_CreateBillboard(game, Dqn_V2_InitNx2(1068, 619), FP_EntityBillboardState_Build, "Build Billboard");
// NOTE: Camera ================================================================================ // NOTE: Camera ================================================================================
play->camera.world_pos = {}; play->camera.world_pos = {};
@ -2025,7 +2026,7 @@ static void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput
particle_desc.pos = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.5f, -0.1f)); particle_desc.pos = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.5f, -0.1f));
particle_desc.colour_begin.a = .8f; particle_desc.colour_begin.a = .8f;
entity->drunk_particles_end_ms = game->play.clock_ms + duration_ms; entity->drunk_particles_end_ms = game->play.clock_ms + duration_ms;
FP_EmitParticle(&game->play, particle_desc, 3); FP_EmitParticle(game, particle_desc, 3);
} }
} }
@ -2155,7 +2156,7 @@ static void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput
particle_desc.colour_begin = TELY_COLOUR_WHITE_V4; particle_desc.colour_begin = TELY_COLOUR_WHITE_V4;
particle_desc.colour_end = TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, 0.f); particle_desc.colour_end = TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, 0.f);
particle_desc.duration_ms = 1000; particle_desc.duration_ms = 1000;
FP_EmitParticle(&game->play, particle_desc, Dqn_PCG32_Range(&game->play.rng, 1, 3)); FP_EmitParticle(game, particle_desc, Dqn_PCG32_Range(&game->play.rng, 1, 3));
// NOTE: God mode override ========================================================= // NOTE: God mode override =========================================================
if (game->play.heart == defender->handle) { if (game->play.heart == defender->handle) {
@ -2346,6 +2347,56 @@ static Dqn_String8 FP_ScanCodeToLabel(Dqn_Arena *arena, TELY_PlatformInputScanCo
return result; return result;
} }
static void FP_DrawBillboardKeyBindHint(TELY_Renderer *renderer,
TELY_Assets *assets,
FP_Game *game,
Dqn_usize player_index,
FP_GameControlMode mode,
FP_GameKeyBind key_bind,
Dqn_V2 draw_p,
bool draw_player_prefix)
{
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_String8 player_prefix = {};
if (draw_player_prefix)
player_prefix = Dqn_String8_InitF(scratch.allocator, "P%zu ", player_index);
if (mode == FP_GameControlMode_Gamepad) {
Dqn_String8 tex_name = {};
if (key_bind.gamepad_key == TELY_PlatformInputGamepadKey_A)
tex_name = g_anim_names.merchant_button_a;
else if (key_bind.gamepad_key == TELY_PlatformInputGamepadKey_B)
tex_name = g_anim_names.merchant_button_b;
else if (key_bind.gamepad_key == TELY_PlatformInputGamepadKey_X)
tex_name = g_anim_names.merchant_button_x;
else if (key_bind.gamepad_key == TELY_PlatformInputGamepadKey_Y)
tex_name = g_anim_names.merchant_button_y;
if (tex_name.size) {
TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, tex_name);
Dqn_Rect button_rect = game->atlas_sprite_sheet.rects.data[anim->index];
Dqn_V2 text_size = TELY_Asset_MeasureText(TELY_Render_Font(renderer, assets), player_prefix);
TELY_Render_Text(renderer, draw_p, Dqn_V2_InitNx2(0, +1.f), player_prefix);
Dqn_Rect gamepad_btn_rect = {};
gamepad_btn_rect.size = button_rect.size;
gamepad_btn_rect.pos = Dqn_V2_InitNx2(draw_p.x + (text_size.x * 1.25f), draw_p.y - button_rect.size.y);
TELY_Render_TextureColourV4(renderer,
game->atlas_sprite_sheet.tex_handle,
button_rect,
gamepad_btn_rect,
Dqn_V2_Zero /*rotate origin*/,
0.f /*rotation*/,
TELY_COLOUR_WHITE_V4);
}
} else {
Dqn_String8 key_bind_label = FP_ScanCodeToLabel(scratch.arena, key_bind.scan_code);
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0, +1.f), "%.*s%.*s", DQN_STRING_FMT(player_prefix), DQN_STRING_FMT(key_bind_label));
}
}
static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, TELY_Audio *audio) static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, TELY_Audio *audio)
{ {
Dqn_Profiler_ZoneScopeWithIndex("FP_Render", FP_ProfileZone_FPRender); Dqn_Profiler_ZoneScopeWithIndex("FP_Render", FP_ProfileZone_FPRender);
@ -2764,90 +2815,74 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
} }
if (entity->type == FP_EntityType_Billboard) { if (entity->type == FP_EntityType_Billboard) {
TELY_Render_PushFont(renderer, game->talkco_font);
DQN_DEFER { TELY_Render_PopFont(renderer); };
DQN_FOR_UINDEX (player_index, game->play.players.size) { DQN_FOR_UINDEX (player_index, game->play.players.size) {
FP_GameEntityHandle player_handle = game->play.players.data[player_index]; FP_GameEntityHandle player_handle = game->play.players.data[player_index];
FP_GameEntity const *player = FP_Game_GetEntity(game, player_handle); FP_GameEntity const *player = FP_Game_GetEntity(game, player_handle);
FP_GameControls const *controls = &player->controls; FP_GameControls const *controls = &player->controls;
FP_EntityBillboardState state = DQN_CAST(FP_EntityBillboardState) entity->action.state; FP_EntityBillboardState state = DQN_CAST(FP_EntityBillboardState) entity->action.state;
FP_GameKeyBind const *key_bind = nullptr;
Dqn_V2 draw_p = {};
Dqn_V4 colour = TELY_COLOUR_BLACK_V4;
switch (state) { switch (state) {
case FP_EntityBillboardState_Attack: { case FP_EntityBillboardState_Attack: {
key_bind = &controls->attack; Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.6f, 0.2f));
draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.6f, 0.2f)); draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index;
colour = colour_accent_yellow; TELY_Render_PushColourV4(renderer, colour_accent_yellow);
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->attack, draw_p, true /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer);
} break; } break;
case FP_EntityBillboardState_Dash: { case FP_EntityBillboardState_Dash: {
key_bind = &controls->dash; Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.505f, -0.08f));
draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.505f, -0.08f)); draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index;
colour = TELY_Colour_V4InitRGBU32(0xFFE726); TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0xFFE726));
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->dash, draw_p, true /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer);
} break; } break;
case FP_EntityBillboardState_Monkey: { case FP_EntityBillboardState_Monkey: {
} break; } break;
case FP_EntityBillboardState_RangeAttack: { case FP_EntityBillboardState_RangeAttack: {
key_bind = &controls->range_attack; Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.20f, -0.13f));
draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.20f, -0.13f)); draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index;
colour = TELY_Colour_V4InitRGBU32(0x364659); TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0x364659));
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->range_attack, draw_p, true /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer);
} break; } break;
case FP_EntityBillboardState_Strafe: { case FP_EntityBillboardState_Strafe: {
key_bind = &controls->strafe; Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.36f, -0.15f));
draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.36f, -0.15f));
colour = TELY_Colour_V4InitRGBU32(0xFF68A8);
} break;
}
draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index; draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index;
TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0xFF68A8));
if (key_bind) { FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->strafe, draw_p, true /*draw_player_prefix*/);
TELY_Render_PushColourV4(renderer, colour);
TELY_Render_PushFont(renderer, game->talkco_font);
DQN_DEFER {
TELY_Render_PopFont(renderer);
TELY_Render_PopColourV4(renderer); TELY_Render_PopColourV4(renderer);
}; } break;
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); case FP_EntityBillboardState_Build: {
Dqn_String8 player_prefix = Dqn_String8_InitF(scratch.allocator, "P%zu", player_index); Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.065f, 0.2f));
if (controls->mode == FP_GameControlMode_Gamepad) { draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index;
Dqn_String8 tex_name = {}; TELY_Render_PushColourV4(renderer, colour_accent_yellow);
if (key_bind->gamepad_key == TELY_PlatformInputGamepadKey_A) FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->build_mode, draw_p, true /*draw_player_prefix*/);
tex_name = g_anim_names.merchant_button_a; TELY_Render_PopColourV4(renderer);
else if (key_bind->gamepad_key == TELY_PlatformInputGamepadKey_B)
tex_name = g_anim_names.merchant_button_b;
else if (key_bind->gamepad_key == TELY_PlatformInputGamepadKey_X)
tex_name = g_anim_names.merchant_button_x;
else if (key_bind->gamepad_key == TELY_PlatformInputGamepadKey_Y)
tex_name = g_anim_names.merchant_button_y;
if (tex_name.size) { draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.35f, 0.2f));
TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, tex_name); draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index;
Dqn_Rect button_rect = game->atlas_sprite_sheet.rects.data[anim->index]; TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0xFF68A8));
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->move_building_ui_cursor_left, draw_p, true /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer);
Dqn_V2 text_size = TELY_Asset_MeasureText(TELY_Render_Font(renderer, assets), player_prefix); draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.44f, 0.2f));
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0, +1.f), "P%zu", player_index); draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index;
TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0xFF68A8));
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->move_building_ui_cursor_right, draw_p, false /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer);
Dqn_Rect gamepad_btn_rect = {}; draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.665f, 0.2f));
gamepad_btn_rect.size = button_rect.size; draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index;
gamepad_btn_rect.pos = Dqn_V2_InitNx2(draw_p.x + (text_size.x * 1.25f), draw_p.y - button_rect.size.y); TELY_Render_PushColourV4(renderer, TELY_COLOUR_BLACK_V4);
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->attack, draw_p, true /*draw_player_prefix*/);
TELY_Render_TextureColourV4(renderer, TELY_Render_PopColourV4(renderer);
game->atlas_sprite_sheet.tex_handle, } break;
button_rect,
gamepad_btn_rect,
Dqn_V2_Zero /*rotate origin*/,
0.f /*rotation*/,
TELY_COLOUR_WHITE_V4);
}
} else {
Dqn_String8 key_bind_label = FP_ScanCodeToLabel(scratch.arena, key_bind->scan_code);
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0, +1.f), "%.*s %.*s", DQN_STRING_FMT(player_prefix), DQN_STRING_FMT(key_bind_label));
}
} }
} }
} }
@ -3188,7 +3223,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
(*mapping.inventory_count)++; (*mapping.inventory_count)++;
dollar_buy_particle.pos = dollar_text_label_pos; dollar_buy_particle.pos = dollar_text_label_pos;
FP_EmitParticle(&game->play, dollar_buy_particle, 1); FP_EmitParticle(game, dollar_buy_particle, 1);
} }
} else { } else {
game->play.player_trigger_purchase_building_timestamp = UINT64_MAX; game->play.player_trigger_purchase_building_timestamp = UINT64_MAX;
@ -3311,7 +3346,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
TELY_Audio_Play(audio, game->audio[FP_GameAudio_Ching], 1.f); TELY_Audio_Play(audio, game->audio[FP_GameAudio_Ching], 1.f);
dollar_buy_particle.pos = dollar_text_label_pos; dollar_buy_particle.pos = dollar_text_label_pos;
FP_EmitParticle(&game->play, dollar_buy_particle, 1); FP_EmitParticle(game, dollar_buy_particle, 1);
if (mapping.merchant == game->play.merchant_terry) { if (mapping.merchant == game->play.merchant_terry) {
player->base_attack += DQN_CAST(uint32_t)(FP_DEFAULT_DAMAGE * 1.2f); player->base_attack += DQN_CAST(uint32_t)(FP_DEFAULT_DAMAGE * 1.2f);

View File

@ -72,6 +72,7 @@ struct FP_GlobalAnimations
Dqn_String8 map_billboard_monkey = DQN_STRING8("map_billboard_monkey"); Dqn_String8 map_billboard_monkey = DQN_STRING8("map_billboard_monkey");
Dqn_String8 map_billboard_range_attack = DQN_STRING8("map_billboard_range_attack"); Dqn_String8 map_billboard_range_attack = DQN_STRING8("map_billboard_range_attack");
Dqn_String8 map_billboard_strafe = DQN_STRING8("map_billboard_strafe"); Dqn_String8 map_billboard_strafe = DQN_STRING8("map_billboard_strafe");
Dqn_String8 map_billboard_build = DQN_STRING8("map_billboard_build");
Dqn_String8 map_police = DQN_STRING8("map_police"); Dqn_String8 map_police = DQN_STRING8("map_police");
Dqn_String8 merchant_button_a = DQN_STRING8("merchant_button_a"); Dqn_String8 merchant_button_a = DQN_STRING8("merchant_button_a");

View File

@ -400,6 +400,7 @@ static FP_EntityRenderData FP_Entity_GetRenderData(FP_Game *game, FP_EntityType
case FP_EntityBillboardState_Monkey: result.anim_name = g_anim_names.map_billboard_monkey; break; case FP_EntityBillboardState_Monkey: result.anim_name = g_anim_names.map_billboard_monkey; break;
case FP_EntityBillboardState_RangeAttack: result.anim_name = g_anim_names.map_billboard_range_attack; break; case FP_EntityBillboardState_RangeAttack: result.anim_name = g_anim_names.map_billboard_range_attack; break;
case FP_EntityBillboardState_Strafe: result.anim_name = g_anim_names.map_billboard_strafe; break; case FP_EntityBillboardState_Strafe: result.anim_name = g_anim_names.map_billboard_strafe; break;
case FP_EntityBillboardState_Build: result.anim_name = g_anim_names.map_billboard_build; result.height.meters = 6.25f; break;
} }
} break; } break;

View File

@ -137,6 +137,7 @@ enum FP_EntityBillboardState
FP_EntityBillboardState_Monkey, FP_EntityBillboardState_Monkey,
FP_EntityBillboardState_RangeAttack, FP_EntityBillboardState_RangeAttack,
FP_EntityBillboardState_Strafe, FP_EntityBillboardState_Strafe,
FP_EntityBillboardState_Build,
}; };
struct FP_EntityRenderData struct FP_EntityRenderData

View File

@ -442,6 +442,7 @@ struct FP_Game
TELY_AssetSpriteSheet atlas_sprite_sheet; TELY_AssetSpriteSheet atlas_sprite_sheet;
TELY_RFui rfui; TELY_RFui rfui;
FP_GamePlay play; FP_GamePlay play;
Dqn_Arena *frame_arena;
}; };
struct FP_GameAStarNode struct FP_GameAStarNode