Create ParticleProjectile effect, and add to ranged attacks
This commit is contained in:
parent
9adee7a4dc
commit
89f6470ec0
@ -167,9 +167,18 @@ pub struct Wearable {
|
|||||||
pub slot: EquipmentSlot,
|
pub slot: EquipmentSlot,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct ParticleAnimation {
|
||||||
|
pub step_time: f32,
|
||||||
|
pub path: Vec<Point>,
|
||||||
|
pub current_step: usize,
|
||||||
|
pub timer: f32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Component, Serialize, Deserialize, Clone)]
|
#[derive(Component, Serialize, Deserialize, Clone)]
|
||||||
pub struct ParticleLifetime {
|
pub struct ParticleLifetime {
|
||||||
pub lifetime_ms: f32,
|
pub lifetime_ms: f32,
|
||||||
|
pub animation: Option<ParticleAnimation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Serialize, Deserialize, Clone)]
|
#[derive(Component, Serialize, Deserialize, Clone)]
|
||||||
|
@ -8,7 +8,7 @@ mod triggers;
|
|||||||
use std::collections::{HashSet, VecDeque};
|
use std::collections::{HashSet, VecDeque};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use ::rltk::{FontCharType, RGB};
|
use ::rltk::{FontCharType, Point, RGB};
|
||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
pub use targeting::*;
|
pub use targeting::*;
|
||||||
|
|
||||||
@ -31,6 +31,14 @@ pub enum EffectType {
|
|||||||
bg: RGB,
|
bg: RGB,
|
||||||
lifespan: f32,
|
lifespan: f32,
|
||||||
},
|
},
|
||||||
|
ParticleProjectile {
|
||||||
|
glyph: FontCharType,
|
||||||
|
fg: RGB,
|
||||||
|
bg: RGB,
|
||||||
|
lifespan: f32,
|
||||||
|
speed: f32,
|
||||||
|
path: Vec<Point>,
|
||||||
|
},
|
||||||
EntityDeath,
|
EntityDeath,
|
||||||
ItemUse {
|
ItemUse {
|
||||||
item: Entity,
|
item: Entity,
|
||||||
@ -155,6 +163,7 @@ fn affect_tile(ecs: &mut World, effect: &mut EffectSpawner, tile_idx: i32) {
|
|||||||
match &effect.effect_type {
|
match &effect.effect_type {
|
||||||
EffectType::Bloodstain => damage::bloodstain(ecs, tile_idx),
|
EffectType::Bloodstain => damage::bloodstain(ecs, tile_idx),
|
||||||
EffectType::Particle { .. } => particles::particle_to_tile(ecs, tile_idx, effect),
|
EffectType::Particle { .. } => particles::particle_to_tile(ecs, tile_idx, effect),
|
||||||
|
EffectType::ParticleProjectile { .. } => particles::projectile(ecs, tile_idx, effect),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use super::{EffectSpawner, EffectType};
|
use super::{EffectSpawner, EffectType};
|
||||||
|
use crate::components::{ParticleAnimation, ParticleLifetime, Position, Renderable};
|
||||||
use crate::map::Map;
|
use crate::map::Map;
|
||||||
use crate::particle_system::ParticleBuilder;
|
use crate::particle_system::ParticleBuilder;
|
||||||
|
|
||||||
@ -24,3 +25,42 @@ pub fn particle_to_tile(ecs: &mut World, tile_idx: i32, effect: &EffectSpawner)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn projectile(ecs: &mut World, tile_idx: i32, effect: &EffectSpawner) {
|
||||||
|
if let EffectType::ParticleProjectile {
|
||||||
|
glyph,
|
||||||
|
fg,
|
||||||
|
bg,
|
||||||
|
lifespan: _,
|
||||||
|
speed,
|
||||||
|
path,
|
||||||
|
} = &effect.effect_type
|
||||||
|
{
|
||||||
|
let x: i32;
|
||||||
|
let y: i32;
|
||||||
|
{
|
||||||
|
let map = ecs.fetch::<Map>();
|
||||||
|
x = tile_idx % map.width;
|
||||||
|
y = tile_idx / map.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
ecs.create_entity()
|
||||||
|
.with(Position { x, y })
|
||||||
|
.with(Renderable {
|
||||||
|
fg: *fg,
|
||||||
|
bg: *bg,
|
||||||
|
glyph: *glyph,
|
||||||
|
render_order: 0,
|
||||||
|
})
|
||||||
|
.with(ParticleLifetime {
|
||||||
|
lifetime_ms: path.len() as f32 * speed,
|
||||||
|
animation: Some(ParticleAnimation {
|
||||||
|
step_time: *speed,
|
||||||
|
path: path.to_vec(),
|
||||||
|
current_step: 0,
|
||||||
|
timer: 0.0,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
20
src/gui.rs
20
src/gui.rs
@ -219,21 +219,31 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
|||||||
y += 1;
|
y += 1;
|
||||||
|
|
||||||
if let Some(weapon) = weapon.get(entity) {
|
if let Some(weapon) = weapon.get(entity) {
|
||||||
let mut weapon_info = if weapon.damage_bonus < 0 {
|
let mut weapon_info = match weapon.damage_bonus.cmp(&0) {
|
||||||
|
Ordering::Less => {
|
||||||
format!(
|
format!(
|
||||||
"┤ {} ({}d{}{})",
|
"┤ {} ({}d{}{})",
|
||||||
&name, weapon.damage_n_dice, weapon.damage_die_type, weapon.damage_bonus
|
&name,
|
||||||
|
weapon.damage_n_dice,
|
||||||
|
weapon.damage_die_type,
|
||||||
|
weapon.damage_bonus
|
||||||
)
|
)
|
||||||
} else if weapon.damage_bonus == 0 {
|
}
|
||||||
|
Ordering::Equal => {
|
||||||
format!(
|
format!(
|
||||||
"┤ {} ({}d{})",
|
"┤ {} ({}d{})",
|
||||||
&name, weapon.damage_n_dice, weapon.damage_die_type
|
&name, weapon.damage_n_dice, weapon.damage_die_type
|
||||||
)
|
)
|
||||||
} else {
|
}
|
||||||
|
Ordering::Greater => {
|
||||||
format!(
|
format!(
|
||||||
"┤ {} ({}d{}+{})",
|
"┤ {} ({}d{}+{})",
|
||||||
&name, weapon.damage_n_dice, weapon.damage_die_type, weapon.damage_bonus
|
&name,
|
||||||
|
weapon.damage_n_dice,
|
||||||
|
weapon.damage_die_type,
|
||||||
|
weapon.damage_bonus
|
||||||
)
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(range) = weapon.range {
|
if let Some(range) = weapon.range {
|
||||||
|
@ -1,16 +1,29 @@
|
|||||||
use ::rltk::{Rltk, RGB};
|
use ::rltk::{Rltk, RGB};
|
||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{ParticleLifetime, Renderable};
|
use crate::components::{ParticleLifetime, Position, Renderable};
|
||||||
use crate::Position;
|
|
||||||
|
|
||||||
pub fn cull_dead_particles(ecs: &mut World, ctx: &Rltk) {
|
pub fn update_particles(ecs: &mut World, ctx: &Rltk) {
|
||||||
let mut dead_particles: Vec<Entity> = Vec::new();
|
let mut dead_particles: Vec<Entity> = Vec::new();
|
||||||
{
|
{
|
||||||
// Age out particles
|
// Age out particles
|
||||||
let mut particles = ecs.write_storage::<ParticleLifetime>();
|
let mut particles = ecs.write_storage::<ParticleLifetime>();
|
||||||
let entities = ecs.entities();
|
let entities = ecs.entities();
|
||||||
for (entity, mut particle) in (&entities, &mut particles).join() {
|
for (entity, mut particle) in (&entities, &mut particles).join() {
|
||||||
|
if let Some(animation) = &mut particle.animation {
|
||||||
|
animation.timer += ctx.frame_time_ms;
|
||||||
|
if animation.timer > animation.step_time
|
||||||
|
&& animation.current_step < animation.path.len() - 2
|
||||||
|
{
|
||||||
|
animation.current_step += 1;
|
||||||
|
|
||||||
|
if let Some(pos) = ecs.write_storage::<Position>().get_mut(entity) {
|
||||||
|
pos.x = animation.path[animation.current_step].x;
|
||||||
|
pos.y = animation.path[animation.current_step].y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
particle.lifetime_ms -= ctx.frame_time_ms;
|
particle.lifetime_ms -= ctx.frame_time_ms;
|
||||||
|
|
||||||
if particle.lifetime_ms < 0.0 {
|
if particle.lifetime_ms < 0.0 {
|
||||||
@ -20,8 +33,7 @@ pub fn cull_dead_particles(ecs: &mut World, ctx: &Rltk) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for dead in dead_particles.iter() {
|
for dead in dead_particles.iter() {
|
||||||
ecs.delete_entity(*dead)
|
ecs.delete_entity(*dead).expect("Particle will not die.");
|
||||||
.expect("Failed to delete dead particle entity");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +121,7 @@ impl<'a> System<'a> for ParticleSpawnSystem {
|
|||||||
p,
|
p,
|
||||||
ParticleLifetime {
|
ParticleLifetime {
|
||||||
lifetime_ms: new_particle.lifetime,
|
lifetime_ms: new_particle.lifetime,
|
||||||
|
animation: None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.expect("Failed to insert Lifetime of new particle");
|
.expect("Failed to insert Lifetime of new particle");
|
||||||
|
@ -404,14 +404,18 @@ fn cycle_target(ecs: &mut World) {
|
|||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
for (i, target) in possible_targets.iter().enumerate() {
|
for (i, target) in possible_targets.iter().enumerate() {
|
||||||
if target.1 == current_target {
|
if target.1 == current_target {
|
||||||
index = 1;
|
index = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if index > possible_targets.len() - 2 {
|
if index > possible_targets.len() - 2 {
|
||||||
targets.insert(possible_targets[0].1, Target {});
|
targets
|
||||||
|
.insert(possible_targets[0].1, Target {})
|
||||||
|
.expect("Failed to insert Target tag");
|
||||||
} else {
|
} else {
|
||||||
targets.insert(possible_targets[index + 1].1, Target {});
|
targets
|
||||||
|
.insert(possible_targets[index + 1].1, Target {})
|
||||||
|
.expect("Failed to insert Target tag");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,26 +69,26 @@ impl<'a> System<'a> for RangedCombatSystem {
|
|||||||
let target_name = names.get(wants_shoot.target).unwrap();
|
let target_name = names.get(wants_shoot.target).unwrap();
|
||||||
|
|
||||||
// Fire projectile effect
|
// Fire projectile effect
|
||||||
// let apos = positions.get(entity).unwrap();
|
let apos = positions.get(entity).unwrap();
|
||||||
// let dpos = positions.get(wants_shoot.target).unwrap();
|
let dpos = positions.get(wants_shoot.target).unwrap();
|
||||||
// add_effect(
|
add_effect(
|
||||||
// None,
|
None,
|
||||||
// EffectType::ParticleProjectile {
|
EffectType::ParticleProjectile {
|
||||||
// glyph: to_cp437('*'),
|
glyph: to_cp437('*'),
|
||||||
// fg: colors::CYAN,
|
fg: colors::CYAN,
|
||||||
// bg: colors::BLACK,
|
bg: colors::BLACK,
|
||||||
// lifespan: 300.0,
|
lifespan: 300.0,
|
||||||
// speed: 50.0,
|
speed: 50.0,
|
||||||
// path: ::rltk::line2d(
|
path: ::rltk::line2d(
|
||||||
// LineAlg::Bresenham,
|
LineAlg::Bresenham,
|
||||||
// Point::from(*apos),
|
Point::from(*apos),
|
||||||
// Point::from(*dpos),
|
Point::from(*dpos),
|
||||||
// ),
|
),
|
||||||
// },
|
},
|
||||||
// Targets::Tile {
|
Targets::Tile {
|
||||||
// tile_idx: map.xy_idx(apos.x, apos.y) as i32,
|
tile_idx: map.xy_idx(apos.x, apos.y) as i32,
|
||||||
// },
|
},
|
||||||
// );
|
);
|
||||||
|
|
||||||
// Define the basic unarmed attack -- overridden by wielding check below if a weapon is equipped
|
// Define the basic unarmed attack -- overridden by wielding check below if a weapon is equipped
|
||||||
let mut weapon_info = Weapon {
|
let mut weapon_info = Weapon {
|
||||||
|
@ -176,7 +176,7 @@ impl GameState for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.cls();
|
ctx.cls();
|
||||||
particle_system::cull_dead_particles(&mut self.ecs, ctx);
|
particle_system::update_particles(&mut self.ecs, ctx);
|
||||||
|
|
||||||
match newrunstate {
|
match newrunstate {
|
||||||
RunState::MainMenu { .. } => {}
|
RunState::MainMenu { .. } => {}
|
||||||
|
Loading…
Reference in New Issue
Block a user