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:
parent
6aa10ed946
commit
b779af2c1f
|
|
@ -3,4 +3,5 @@ pub mod draw_common;
|
||||||
pub mod flash;
|
pub mod flash;
|
||||||
pub mod hud;
|
pub mod hud;
|
||||||
pub mod inventory;
|
pub mod inventory;
|
||||||
|
pub mod number_popup;
|
||||||
pub mod stage_select;
|
pub mod stage_select;
|
||||||
|
|
|
||||||
100
src/components/number_popup.rs
Normal file
100
src/components/number_popup.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -21,6 +21,7 @@ use crate::shared_game_state::SharedGameState;
|
||||||
use crate::stage::Stage;
|
use crate::stage::Stage;
|
||||||
use crate::str;
|
use crate::str;
|
||||||
use crate::components::flash::Flash;
|
use crate::components::flash::Flash;
|
||||||
|
use crate::components::number_popup::NumberPopup;
|
||||||
|
|
||||||
pub mod ai;
|
pub mod ai;
|
||||||
pub mod boss;
|
pub mod boss;
|
||||||
|
|
@ -107,6 +108,7 @@ pub struct NPC {
|
||||||
pub display_bounds: Rect<u32>,
|
pub display_bounds: Rect<u32>,
|
||||||
pub hit_bounds: Rect<u32>,
|
pub hit_bounds: Rect<u32>,
|
||||||
pub rng: Xoroshiro32PlusPlus,
|
pub rng: Xoroshiro32PlusPlus,
|
||||||
|
pub popup: NumberPopup,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NPC {
|
impl NPC {
|
||||||
|
|
@ -149,6 +151,7 @@ impl NPC {
|
||||||
anim_counter: 0,
|
anim_counter: 0,
|
||||||
anim_rect: Rect { left: 0, top: 0, right: 0, bottom: 0 },
|
anim_rect: Rect { left: 0, top: 0, right: 0, bottom: 0 },
|
||||||
rng: Xoroshiro32PlusPlus::new(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 {
|
if self.shock > 0 {
|
||||||
self.shock -= 1;
|
self.shock -= 1;
|
||||||
}
|
}
|
||||||
|
|
@ -421,6 +428,8 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl
|
||||||
);
|
);
|
||||||
batch.draw(ctx)?;
|
batch.draw(ctx)?;
|
||||||
|
|
||||||
|
self.popup.draw(state, ctx, frame)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use crate::npc::list::NPCList;
|
||||||
use crate::player::Player;
|
use crate::player::Player;
|
||||||
use crate::rng::{RNG, Xoroshiro32PlusPlus};
|
use crate::rng::{RNG, Xoroshiro32PlusPlus};
|
||||||
use crate::shared_game_state::SharedGameState;
|
use crate::shared_game_state::SharedGameState;
|
||||||
|
use crate::components::number_popup::NumberPopup;
|
||||||
|
|
||||||
impl NPC {
|
impl NPC {
|
||||||
/// Initializes the RNG. Called when the [NPC] is being added to an [NPCList].
|
/// Initializes the RNG. Called when the [NPC] is being added to an [NPCList].
|
||||||
|
|
@ -80,6 +81,7 @@ impl NPC {
|
||||||
anim_counter: 0,
|
anim_counter: 0,
|
||||||
anim_rect: Rect::new(0, 0, 0, 0),
|
anim_rect: Rect::new(0, 0, 0, 0),
|
||||||
rng: Xoroshiro32PlusPlus::new(0),
|
rng: Xoroshiro32PlusPlus::new(0),
|
||||||
|
popup: NumberPopup::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ use crate::player::skin::{PlayerAnimationState, PlayerAppearanceState, PlayerSki
|
||||||
use crate::player::skin::basic::BasicPlayerSkin;
|
use crate::player::skin::basic::BasicPlayerSkin;
|
||||||
use crate::rng::RNG;
|
use crate::rng::RNG;
|
||||||
use crate::shared_game_state::SharedGameState;
|
use crate::shared_game_state::SharedGameState;
|
||||||
|
use crate::components::number_popup::NumberPopup;
|
||||||
|
|
||||||
mod player_hit;
|
mod player_hit;
|
||||||
pub mod skin;
|
pub mod skin;
|
||||||
|
|
@ -72,6 +73,7 @@ pub struct Player {
|
||||||
pub air: u16,
|
pub air: u16,
|
||||||
pub skin: Box<dyn PlayerSkin>,
|
pub skin: Box<dyn PlayerSkin>,
|
||||||
pub controller: Box<dyn PlayerController>,
|
pub controller: Box<dyn PlayerController>,
|
||||||
|
pub popup: NumberPopup,
|
||||||
weapon_offset_y: i8,
|
weapon_offset_y: i8,
|
||||||
camera_target_x: i32,
|
camera_target_x: i32,
|
||||||
camera_target_y: i32,
|
camera_target_y: i32,
|
||||||
|
|
@ -126,6 +128,7 @@ impl Player {
|
||||||
air: 0,
|
air: 0,
|
||||||
skin: Box::new(BasicPlayerSkin::new("MyChar".to_string())),
|
skin: Box::new(BasicPlayerSkin::new("MyChar".to_string())),
|
||||||
controller: Box::new(DummyPlayerController::new()),
|
controller: Box::new(DummyPlayerController::new()),
|
||||||
|
popup: NumberPopup::new(),
|
||||||
damage_counter: 0,
|
damage_counter: 0,
|
||||||
damage_taken: 0,
|
damage_taken: 0,
|
||||||
anim_num: 0,
|
anim_num: 0,
|
||||||
|
|
@ -685,6 +688,11 @@ impl Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.damage = self.damage.saturating_add(hp as u16);
|
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 {
|
if self.life == 0 {
|
||||||
state.sound_manager.play_sfx(17);
|
state.sound_manager.play_sfx(17);
|
||||||
|
|
@ -729,6 +737,10 @@ impl GameEntity<&NPCList> for Player {
|
||||||
ControlMode::IronHead => self.tick_ironhead(state)?,
|
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.cond.set_increase_acceleration(false);
|
||||||
self.tick_animation(state);
|
self.tick_animation(state);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -258,6 +258,13 @@ impl Player {
|
||||||
1 => {
|
1 => {
|
||||||
state.sound_manager.play_sfx(14);
|
state.sound_manager.play_sfx(14);
|
||||||
inventory.add_xp(npc.exp, self, state);
|
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);
|
npc.cond.set_alive(false);
|
||||||
}
|
}
|
||||||
// missile pickup
|
// missile pickup
|
||||||
|
|
|
||||||
|
|
@ -1161,7 +1161,7 @@ impl GameScene {
|
||||||
|
|
||||||
if npc.life == 0 {
|
if npc.life == 0 {
|
||||||
if npc.npc_flags.show_damage() {
|
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() {
|
if self.player1.cond.alive() && npc.npc_flags.event_when_killed() {
|
||||||
|
|
@ -1190,7 +1190,7 @@ impl GameScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
if npc.npc_flags.show_damage() {
|
if npc.npc_flags.show_damage() {
|
||||||
// todo show damage
|
npc.popup.add_value(-bullet.damage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if !bullet.weapon_flags.flag_x10()
|
} else if !bullet.weapon_flags.flag_x10()
|
||||||
|
|
@ -1704,18 +1704,26 @@ impl Scene for GameScene {
|
||||||
self.frame.prev_y = self.frame.y;
|
self.frame.prev_y = self.frame.y;
|
||||||
self.player1.prev_x = self.player1.x;
|
self.player1.prev_x = self.player1.x;
|
||||||
self.player1.prev_y = self.player1.y;
|
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_x = self.player2.x;
|
||||||
self.player2.prev_y = self.player2.y;
|
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() {
|
for npc in self.npc_list.iter_alive() {
|
||||||
npc.prev_x = npc.x;
|
npc.prev_x = npc.x;
|
||||||
npc.prev_y = npc.y;
|
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() {
|
for npc in self.boss.parts.iter_mut() {
|
||||||
if npc.cond.alive() {
|
if npc.cond.alive() {
|
||||||
npc.prev_x = npc.x;
|
npc.prev_x = npc.x;
|
||||||
npc.prev_y = npc.y;
|
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::Foreground)?;
|
||||||
self.draw_tiles(state, ctx, TileLayer::Snack)?;
|
self.draw_tiles(state, ctx, TileLayer::Snack)?;
|
||||||
self.draw_carets(state, ctx)?;
|
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
|
if state.settings.shader_effects
|
||||||
&& (self.stage.data.background_type == BackgroundType::Black
|
&& (self.stage.data.background_type == BackgroundType::Black
|
||||||
|| self.stage.data.background.name() == "bkBlack")
|
|| self.stage.data.background.name() == "bkBlack")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue