Add particle effects for Melee combat
This commit is contained in:
parent
c4bc637c79
commit
1dd5db42f7
@ -174,6 +174,11 @@ pub struct DefenseBonus {
|
|||||||
pub defense: i32,
|
pub defense: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct ParticleLifetime {
|
||||||
|
pub lifetime_ms: f32,
|
||||||
|
}
|
||||||
|
|
||||||
// Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an
|
// Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an
|
||||||
// Entity.
|
// Entity.
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ mod map;
|
|||||||
mod map_indexing_system;
|
mod map_indexing_system;
|
||||||
mod melee_combat_system;
|
mod melee_combat_system;
|
||||||
mod monster_ai_system;
|
mod monster_ai_system;
|
||||||
|
mod particle_system;
|
||||||
mod player;
|
mod player;
|
||||||
pub mod random_table;
|
pub mod random_table;
|
||||||
mod rect;
|
mod rect;
|
||||||
@ -101,6 +102,9 @@ impl State {
|
|||||||
let mut item_remove = ItemRemoveSystem {};
|
let mut item_remove = ItemRemoveSystem {};
|
||||||
item_remove.run_now(&self.ecs);
|
item_remove.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut particles = particle_system::ParticleSpawnSystem {};
|
||||||
|
particles.run_now(&self.ecs);
|
||||||
|
|
||||||
self.ecs.maintain();
|
self.ecs.maintain();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,6 +118,7 @@ impl GameState for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.cls();
|
ctx.cls();
|
||||||
|
particle_system::cull_dead_particles(&mut self.ecs, ctx);
|
||||||
|
|
||||||
match newrunstate {
|
match newrunstate {
|
||||||
RunState::MainMenu { .. } => {}
|
RunState::MainMenu { .. } => {}
|
||||||
@ -485,6 +490,7 @@ fn main() -> rltk::BError {
|
|||||||
MeleePowerBonus,
|
MeleePowerBonus,
|
||||||
DefenseBonus,
|
DefenseBonus,
|
||||||
WantsToRemoveItem,
|
WantsToRemoveItem,
|
||||||
|
ParticleLifetime,
|
||||||
);
|
);
|
||||||
|
|
||||||
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());
|
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());
|
||||||
@ -506,6 +512,7 @@ fn main() -> rltk::BError {
|
|||||||
menu_selection: gui::MainMenuSelection::NewGame,
|
menu_selection: gui::MainMenuSelection::NewGame,
|
||||||
});
|
});
|
||||||
gs.ecs.insert(GameLog::new("Welcome to Rusty Roguelike"));
|
gs.ecs.insert(GameLog::new("Welcome to Rusty Roguelike"));
|
||||||
|
gs.ecs.insert(particle_system::ParticleBuilder::new());
|
||||||
|
|
||||||
rltk::main_loop(context, gs)
|
rltk::main_loop(context, gs)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use crate::components::{
|
use crate::components::{
|
||||||
CombatStats, DefenseBonus, Equipped, MeleePowerBonus, Name, SufferDamage, WantsToMelee,
|
CombatStats, DefenseBonus, Equipped, MeleePowerBonus, Name, SufferDamage, WantsToMelee,
|
||||||
};
|
};
|
||||||
use crate::game_log::GameLog;
|
use crate::{game_log::GameLog, particle_system::ParticleBuilder, Position};
|
||||||
|
use rltk::RGB;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
pub struct MeleeCombatSystem {}
|
pub struct MeleeCombatSystem {}
|
||||||
@ -18,6 +19,8 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
|||||||
ReadStorage<'a, MeleePowerBonus>,
|
ReadStorage<'a, MeleePowerBonus>,
|
||||||
ReadStorage<'a, DefenseBonus>,
|
ReadStorage<'a, DefenseBonus>,
|
||||||
ReadStorage<'a, Equipped>,
|
ReadStorage<'a, Equipped>,
|
||||||
|
WriteExpect<'a, ParticleBuilder>,
|
||||||
|
ReadStorage<'a, Position>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
@ -31,6 +34,8 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
|||||||
melee_power_bonuses,
|
melee_power_bonuses,
|
||||||
defense_bonuses,
|
defense_bonuses,
|
||||||
equipped,
|
equipped,
|
||||||
|
mut particle_builder,
|
||||||
|
positions,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
for (entity, wants_melee, name, stats) in
|
for (entity, wants_melee, name, stats) in
|
||||||
@ -59,6 +64,17 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(pos) = positions.get(wants_melee.target) {
|
||||||
|
particle_builder.request(
|
||||||
|
pos.x,
|
||||||
|
pos.y,
|
||||||
|
RGB::named(rltk::ORANGE),
|
||||||
|
RGB::named(rltk::BLACK),
|
||||||
|
rltk::to_cp437('‼'),
|
||||||
|
200.0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let damage = i32::max(
|
let damage = i32::max(
|
||||||
0,
|
0,
|
||||||
(stats.power + offensive_bonus) - (target_stats.defense + defensive_bonus),
|
(stats.power + offensive_bonus) - (target_stats.defense + defensive_bonus),
|
||||||
|
118
src/particle_system.rs
Normal file
118
src/particle_system.rs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
use crate::components::{ParticleLifetime, Renderable};
|
||||||
|
use crate::Position;
|
||||||
|
use rltk::{Rltk, RGB};
|
||||||
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
pub fn cull_dead_particles(ecs: &mut World, ctx: &Rltk) {
|
||||||
|
let mut dead_particles: Vec<Entity> = Vec::new();
|
||||||
|
{
|
||||||
|
// Age out particles
|
||||||
|
let mut particles = ecs.write_storage::<ParticleLifetime>();
|
||||||
|
let entities = ecs.entities();
|
||||||
|
for (entity, mut particle) in (&entities, &mut particles).join() {
|
||||||
|
particle.lifetime_ms -= ctx.frame_time_ms;
|
||||||
|
|
||||||
|
if particle.lifetime_ms < 0.0 {
|
||||||
|
dead_particles.push(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for dead in dead_particles.iter() {
|
||||||
|
ecs.delete_entity(*dead)
|
||||||
|
.expect("Failed to delete dead particle entity");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ParticleRequest {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
fg: RGB,
|
||||||
|
bg: RGB,
|
||||||
|
glyph: rltk::FontCharType,
|
||||||
|
lifetime: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ParticleBuilder {
|
||||||
|
requests: Vec<ParticleRequest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParticleBuilder {
|
||||||
|
pub fn new() -> ParticleBuilder {
|
||||||
|
ParticleBuilder::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request(
|
||||||
|
&mut self,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
fg: RGB,
|
||||||
|
bg: RGB,
|
||||||
|
glyph: rltk::FontCharType,
|
||||||
|
lifetime: f32,
|
||||||
|
) {
|
||||||
|
self.requests.push(ParticleRequest {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
fg,
|
||||||
|
bg,
|
||||||
|
glyph,
|
||||||
|
lifetime,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ParticleSpawnSystem {}
|
||||||
|
|
||||||
|
impl<'a> System<'a> for ParticleSpawnSystem {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
type SystemData = (
|
||||||
|
Entities<'a>,
|
||||||
|
WriteStorage<'a, Position>,
|
||||||
|
WriteStorage<'a, Renderable>,
|
||||||
|
WriteStorage<'a, ParticleLifetime>,
|
||||||
|
WriteExpect<'a, ParticleBuilder>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
|
let (entities, mut positions, mut renderables, mut particles, mut particle_builder) = data;
|
||||||
|
|
||||||
|
for new_particle in particle_builder.requests.iter() {
|
||||||
|
let p = entities.create();
|
||||||
|
|
||||||
|
positions
|
||||||
|
.insert(
|
||||||
|
p,
|
||||||
|
Position {
|
||||||
|
x: new_particle.x,
|
||||||
|
y: new_particle.y,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("Failed to insert Position of new particle");
|
||||||
|
|
||||||
|
renderables
|
||||||
|
.insert(
|
||||||
|
p,
|
||||||
|
Renderable {
|
||||||
|
fg: new_particle.fg,
|
||||||
|
bg: new_particle.bg,
|
||||||
|
glyph: new_particle.glyph,
|
||||||
|
render_order: 0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("Failed to insert Renderable of new particle");
|
||||||
|
|
||||||
|
particles
|
||||||
|
.insert(
|
||||||
|
p,
|
||||||
|
ParticleLifetime {
|
||||||
|
lifetime_ms: new_particle.lifetime,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("Failed to insert Lifetime of new particle");
|
||||||
|
}
|
||||||
|
|
||||||
|
particle_builder.requests.clear();
|
||||||
|
}
|
||||||
|
}
|
@ -175,17 +175,8 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
|
|||||||
try_move_player(-1, 1, &mut gs.ecs)
|
try_move_player(-1, 1, &mut gs.ecs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick up item
|
// Skip Turn
|
||||||
VirtualKeyCode::G => get_item(&mut gs.ecs),
|
VirtualKeyCode::Numpad5 | VirtualKeyCode::Space => return skip_turn(&mut gs.ecs),
|
||||||
|
|
||||||
// Show inventory
|
|
||||||
VirtualKeyCode::I => return RunState::ShowInventory,
|
|
||||||
|
|
||||||
// Show item drop screen
|
|
||||||
VirtualKeyCode::D => return RunState::ShowDropItem,
|
|
||||||
|
|
||||||
// Save and Quit
|
|
||||||
VirtualKeyCode::Escape => return RunState::SaveGame,
|
|
||||||
|
|
||||||
// Level changes
|
// Level changes
|
||||||
VirtualKeyCode::Period => {
|
VirtualKeyCode::Period => {
|
||||||
@ -194,12 +185,15 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip Turn
|
// Item management
|
||||||
VirtualKeyCode::Numpad5 | VirtualKeyCode::Space => return skip_turn(&mut gs.ecs),
|
VirtualKeyCode::G => get_item(&mut gs.ecs),
|
||||||
|
VirtualKeyCode::I => return RunState::ShowInventory,
|
||||||
// Remove item
|
VirtualKeyCode::D => return RunState::ShowDropItem,
|
||||||
VirtualKeyCode::R => return RunState::ShowRemoveItem,
|
VirtualKeyCode::R => return RunState::ShowRemoveItem,
|
||||||
|
|
||||||
|
// Save and Quit
|
||||||
|
VirtualKeyCode::Escape => return RunState::SaveGame,
|
||||||
|
|
||||||
_ => return RunState::AwaitingInput,
|
_ => return RunState::AwaitingInput,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,8 @@ pub fn save_game(ecs: &mut World) {
|
|||||||
Equipped,
|
Equipped,
|
||||||
MeleePowerBonus,
|
MeleePowerBonus,
|
||||||
DefenseBonus,
|
DefenseBonus,
|
||||||
WantsToRemoveItem
|
WantsToRemoveItem,
|
||||||
|
ParticleLifetime
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +156,8 @@ pub fn load_game(ecs: &mut World) {
|
|||||||
Equipped,
|
Equipped,
|
||||||
MeleePowerBonus,
|
MeleePowerBonus,
|
||||||
DefenseBonus,
|
DefenseBonus,
|
||||||
WantsToRemoveItem
|
WantsToRemoveItem,
|
||||||
|
ParticleLifetime
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user