1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-11-22 13:03:38 +00:00

add damage / exp popups

This commit is contained in:
Alula 2021-05-05 23:37:11 +02:00
parent 6aa10ed946
commit b779af2c1f
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
7 changed files with 144 additions and 2 deletions

View file

@ -3,4 +3,5 @@ pub mod draw_common;
pub mod flash;
pub mod hud;
pub mod inventory;
pub mod number_popup;
pub mod stage_select;

View file

@ -0,0 +1,100 @@
use crate::common::{fix9_scale, interpolate_fix9_scale, Rect};
use crate::entity::GameEntity;
use crate::frame::Frame;
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::shared_game_state::SharedGameState;
#[derive(Debug, Copy, Clone)]
pub struct NumberPopup {
pub value: i16,
pub x: i32,
pub y: i32,
pub prev_x: i32,
pub prev_y: i32,
counter: u16,
}
impl NumberPopup {
pub fn new() -> NumberPopup {
NumberPopup { value: 0, x: 0, y: 0, prev_x: 0, prev_y: 0, counter: 0 }
}
pub fn set_value(&mut self, value: i16) {
if self.counter > 32 {
self.counter = 32;
}
self.value = value;
}
pub fn add_value(&mut self, value: i16) {
self.set_value(self.value + value);
}
}
impl GameEntity<()> for NumberPopup {
fn tick(&mut self, _state: &mut SharedGameState, _custom: ()) -> GameResult<()> {
if self.value == 0 {
return Ok(());
}
self.counter += 1;
if self.counter == 80 {
self.counter = 0;
self.value = 0;
}
Ok(())
}
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult<()> {
if self.value == 0 {
return Ok(());
}
// tick 0 - 32 - move up by 0.5 pixels
// tick 33 - 72 - stay
// tick 73 - 80 - fade up
let y_offset = self.counter.min(32) as f32 * 0.5;
let clip = self.counter.max(72) - 72;
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "TextBox")?;
let (frame_x, frame_y) = frame.xy_interpolated(state.frame_time);
let x = interpolate_fix9_scale(self.prev_x, self.x, state.frame_time) - frame_x;
let y = interpolate_fix9_scale(self.prev_x, self.y, state.frame_time) - frame_y - y_offset;
let mut n = self.value.to_string();
if self.value > 0 {
n = "+".to_owned() + n.as_str();
};
let x = x - n.len() as f32 * 4.0;
for (offset, chr) in n.chars().enumerate() {
match chr {
'+' => {
batch.add_rect(x + offset as f32 * 8.0, y, &Rect::new_size(32, 48 + clip, 8, 8 - clip));
}
'-' => {
batch.add_rect(x + offset as f32 * 8.0, y, &Rect::new_size(40, 48 + clip, 8, 8 - clip));
}
'0'..='9' => {
let number_set = if self.value < 0 { 64 } else { 56 };
let idx = chr as u16 - '0' as u16;
batch.add_rect(
x + offset as f32 * 8.0,
y,
&Rect::new_size(idx * 8, number_set + clip, 8, 8 - clip),
);
}
_ => {}
}
}
batch.draw(ctx)?;
Ok(())
}
}

View file

@ -21,6 +21,7 @@ use crate::shared_game_state::SharedGameState;
use crate::stage::Stage;
use crate::str;
use crate::components::flash::Flash;
use crate::components::number_popup::NumberPopup;
pub mod ai;
pub mod boss;
@ -107,6 +108,7 @@ pub struct NPC {
pub display_bounds: Rect<u32>,
pub hit_bounds: Rect<u32>,
pub rng: Xoroshiro32PlusPlus,
pub popup: NumberPopup,
}
impl NPC {
@ -149,6 +151,7 @@ impl NPC {
anim_counter: 0,
anim_rect: Rect { left: 0, top: 0, right: 0, bottom: 0 },
rng: Xoroshiro32PlusPlus::new(0),
popup: NumberPopup::new(),
}
}
@ -380,6 +383,10 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl
},
}?;
self.popup.x = self.x;
self.popup.y = self.y;
self.popup.tick(state, ())?;
if self.shock > 0 {
self.shock -= 1;
}
@ -421,6 +428,8 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl
);
batch.draw(ctx)?;
self.popup.draw(state, ctx, frame)?;
Ok(())
}
}

View file

@ -11,6 +11,7 @@ use crate::npc::list::NPCList;
use crate::player::Player;
use crate::rng::{RNG, Xoroshiro32PlusPlus};
use crate::shared_game_state::SharedGameState;
use crate::components::number_popup::NumberPopup;
impl NPC {
/// Initializes the RNG. Called when the [NPC] is being added to an [NPCList].
@ -80,6 +81,7 @@ impl NPC {
anim_counter: 0,
anim_rect: Rect::new(0, 0, 0, 0),
rng: Xoroshiro32PlusPlus::new(0),
popup: NumberPopup::new(),
}
}

View file

@ -17,6 +17,7 @@ use crate::player::skin::{PlayerAnimationState, PlayerAppearanceState, PlayerSki
use crate::player::skin::basic::BasicPlayerSkin;
use crate::rng::RNG;
use crate::shared_game_state::SharedGameState;
use crate::components::number_popup::NumberPopup;
mod player_hit;
pub mod skin;
@ -72,6 +73,7 @@ pub struct Player {
pub air: u16,
pub skin: Box<dyn PlayerSkin>,
pub controller: Box<dyn PlayerController>,
pub popup: NumberPopup,
weapon_offset_y: i8,
camera_target_x: i32,
camera_target_y: i32,
@ -126,6 +128,7 @@ impl Player {
air: 0,
skin: Box::new(BasicPlayerSkin::new("MyChar".to_string())),
controller: Box::new(DummyPlayerController::new()),
popup: NumberPopup::new(),
damage_counter: 0,
damage_taken: 0,
anim_num: 0,
@ -685,6 +688,11 @@ impl Player {
}
self.damage = self.damage.saturating_add(hp as u16);
if self.popup.value > 0 {
self.popup.set_value(-(self.damage as i16));
} else {
self.popup.add_value(-(self.damage as i16));
}
if self.life == 0 {
state.sound_manager.play_sfx(17);
@ -729,6 +737,10 @@ impl GameEntity<&NPCList> for Player {
ControlMode::IronHead => self.tick_ironhead(state)?,
}
self.popup.x = self.x;
self.popup.y = self.y;
self.popup.tick(state, ())?;
self.cond.set_increase_acceleration(false);
self.tick_animation(state);

View file

@ -258,6 +258,13 @@ impl Player {
1 => {
state.sound_manager.play_sfx(14);
inventory.add_xp(npc.exp, self, state);
if self.popup.value > 0 {
self.popup.add_value(npc.exp as i16);
} else {
self.popup.set_value(npc.exp as i16);
}
npc.cond.set_alive(false);
}
// missile pickup

View file

@ -1161,7 +1161,7 @@ impl GameScene {
if npc.life == 0 {
if npc.npc_flags.show_damage() {
// todo show damage
npc.popup.add_value(-bullet.damage);
}
if self.player1.cond.alive() && npc.npc_flags.event_when_killed() {
@ -1190,7 +1190,7 @@ impl GameScene {
}
if npc.npc_flags.show_damage() {
// todo show damage
npc.popup.add_value(-bullet.damage);
}
}
} else if !bullet.weapon_flags.flag_x10()
@ -1704,18 +1704,26 @@ impl Scene for GameScene {
self.frame.prev_y = self.frame.y;
self.player1.prev_x = self.player1.x;
self.player1.prev_y = self.player1.y;
self.player1.popup.prev_x = self.player1.prev_x;
self.player1.popup.prev_y = self.player1.prev_y;
self.player2.prev_x = self.player2.x;
self.player2.prev_y = self.player2.y;
self.player2.popup.prev_x = self.player2.prev_x;
self.player2.popup.prev_y = self.player2.prev_y;
for npc in self.npc_list.iter_alive() {
npc.prev_x = npc.x;
npc.prev_y = npc.y;
npc.popup.prev_x = npc.prev_x;
npc.popup.prev_y = npc.prev_y;
}
for npc in self.boss.parts.iter_mut() {
if npc.cond.alive() {
npc.prev_x = npc.x;
npc.prev_y = npc.y;
npc.popup.prev_x = npc.prev_x;
npc.popup.prev_y = npc.prev_y;
}
}
@ -1762,6 +1770,9 @@ impl Scene for GameScene {
self.draw_tiles(state, ctx, TileLayer::Foreground)?;
self.draw_tiles(state, ctx, TileLayer::Snack)?;
self.draw_carets(state, ctx)?;
self.player1.popup.draw(state, ctx, &self.frame)?;
self.player2.popup.draw(state, ctx, &self.frame)?;
if state.settings.shader_effects
&& (self.stage.data.background_type == BackgroundType::Black
|| self.stage.data.background.name() == "bkBlack")