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 hud;
|
||||
pub mod inventory;
|
||||
pub mod number_popup;
|
||||
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::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(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in a new issue