Add ParticleEmitter Component

This commit is contained in:
scott-c 2020-06-29 19:18:19 +08:00
parent 7aebff26e0
commit 42a10a6059
12 changed files with 161 additions and 72 deletions

View File

@ -2,7 +2,8 @@ use crate::{
comp::{
ability::Stage,
item::{armor::Protection, Item, ItemKind},
Body, CharacterState, EnergySource, Gravity, LightEmitter, Projectile, StateUpdate,
Body, CharacterState, EnergySource, Gravity, LightEmitter, ParticleEmitter, Projectile,
StateUpdate,
},
states::{triple_strike::*, *},
sys::character_behavior::JoinData,
@ -61,6 +62,7 @@ pub enum CharacterAbility {
projectile: Projectile,
projectile_body: Body,
projectile_light: Option<LightEmitter>,
projectile_particles: Option<ParticleEmitter>,
projectile_gravity: Option<Gravity>,
},
Boost {
@ -247,6 +249,7 @@ impl From<&CharacterAbility> for CharacterState {
projectile,
projectile_body,
projectile_light,
projectile_particles,
projectile_gravity,
energy_cost: _,
} => CharacterState::BasicRanged(basic_ranged::Data {
@ -258,6 +261,7 @@ impl From<&CharacterAbility> for CharacterState {
projectile: projectile.clone(),
projectile_body: *projectile_body,
projectile_light: *projectile_light,
projectile_particles: *projectile_particles,
projectile_gravity: *projectile_gravity,
}),
CharacterAbility::Boost { duration, only_up } => CharacterState::Boost(boost::Data {

View File

@ -2,7 +2,8 @@
// version in voxygen\src\meta.rs in order to reset save files to being empty
use crate::comp::{
body::object, projectile, Body, CharacterAbility, Gravity, LightEmitter, Projectile,
body::object, projectile, Body, CharacterAbility, Gravity, HealthChange, HealthSource,
LightEmitter, Projectile, ParticleEmitter,
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
@ -179,6 +180,7 @@ impl Tool {
},
projectile_body: Body::Object(object::Body::Arrow),
projectile_light: None,
projectile_particles: None,
projectile_gravity: Some(Gravity(0.2)),
},
ChargedRanged {
@ -193,6 +195,8 @@ impl Tool {
recover_duration: Duration::from_millis(500),
projectile_body: Body::Object(object::Body::Arrow),
projectile_light: None,
projectile_particles: None,
projectile_gravity: Some(Gravity(0.05)),
},
],
Dagger(_) => vec![
@ -261,40 +265,68 @@ impl Tool {
col: (0.85, 0.5, 0.11).into(),
..Default::default()
}),
projectile_gravity: None,
},
BasicRanged {
energy_cost: 400,
holdable: true,
prepare_duration: Duration::from_millis(800),
recover_duration: Duration::from_millis(50),
projectile: Projectile {
hit_solid: vec![
projectile::Effect::Explode {
power: 1.4 * self.base_power(),
},
projectile::Effect::Vanish,
],
hit_entity: vec![
projectile::Effect::Explode {
power: 1.4 * self.base_power(),
},
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(20),
owner: None,
},
projectile_body: Body::Object(object::Body::BoltFireBig),
projectile_light: Some(LightEmitter {
col: (1.0, 0.75, 0.11).into(),
..Default::default()
}),
projectile_gravity: None,
},
]
}
},
projectile::Effect::RewardEnergy(150),
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(20),
owner: None,
},
projectile_body: Body::Object(object::Body::BoltFire),
projectile_light: Some(LightEmitter {
col: (0.85, 0.5, 0.11).into(),
..Default::default()
}),
projectile_particles: Some(ParticleEmitter {
mode: 0,
}),
projectile_gravity: None,
},
BasicRanged {
energy_cost: 400,
holdable: true,
prepare_duration: Duration::from_millis(800),
recover_duration: Duration::from_millis(50),
projectile: Projectile {
hit_solid: vec![
projectile::Effect::Explode { power: 1.4 },
projectile::Effect::Vanish,
],
hit_entity: vec![
projectile::Effect::Explode { power: 1.4 },
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(20),
owner: None,
},
projectile_body: Body::Object(object::Body::BoltFireBig),
projectile_light: Some(LightEmitter {
col: (1.0, 0.75, 0.11).into(),
..Default::default()
}),
projectile_particles: Some(ParticleEmitter {
mode: 0,
}),
projectile_gravity: None,
},
],
Staff(StaffKind::Sceptre) => vec![
BasicMelee {
energy_cost: 0,
buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(300),
base_healthchange: -1,
range: 10.0,
max_angle: 45.0,
},
BasicMelee {
energy_cost: 350,
buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(1000),
base_healthchange: 15,
range: 10.0,
max_angle: 45.0,
},
],
Shield(_) => vec![
BasicMelee {
energy_cost: 0,
@ -313,35 +345,15 @@ impl Tool {
duration: Duration::from_millis(50),
only_up: false,
},
CharacterAbility::Boost {
duration: Duration::from_millis(50),
only_up: true,
},
BasicRanged {
energy_cost: 0,
holdable: false,
prepare_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(10),
projectile: Projectile {
hit_solid: vec![projectile::Effect::Stick],
hit_entity: vec![
projectile::Effect::Stick,
projectile::Effect::Possess,
],
time_left: Duration::from_secs(10),
owner: None,
},
projectile_body: Body::Object(object::Body::ArrowSnake),
projectile_light: Some(LightEmitter {
col: (0.0, 1.0, 0.33).into(),
..Default::default()
}),
projectile_gravity: None,
},
]
} else {
vec![]
}
projectile_body: Body::Object(object::Body::ArrowSnake),
projectile_light: Some(LightEmitter {
col: (0.0, 1.0, 0.33).into(),
..Default::default()
}),
projectile_particles: None,
projectile_gravity: None,
},
],
},
Empty => vec![BasicMelee {
energy_cost: 0,

View File

@ -53,4 +53,4 @@ pub use player::{Player, MAX_MOUNT_RANGE_SQR};
pub use projectile::Projectile;
pub use skills::{Skill, SkillGroup, SkillGroupType, SkillSet};
pub use stats::{Exp, HealthChange, HealthSource, Level, Stats};
pub use visual::{LightAnimation, LightEmitter};
pub use visual::{LightAnimation, LightEmitter, ParticleEmitter};

View File

@ -46,3 +46,37 @@ impl Default for LightAnimation {
impl Component for LightAnimation {
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ParticleEmitter {
/// Mode 1: sprinkler (inital_velocity, lifespan)
/// Mode 2: smoke (initial_position, boyancy_const, wind, lifespan)
pub mode: u8, // enum?
// pub vertices: Vec<i8>,
// pub texture: RasterFooBar,
// // mode 1 -- sprinkler.
// pub initial_position: [i8; 3],
// pub initial_velocity: [i8; 3],
// pub lifespan: u32, // in ticks?
// // mode 2 -- smoke
// pub initial_position: [i8; 3],
// pub boyancy_const: [i8; 3],
// pub wind_sway: [i8; 3],
}
impl Default for ParticleEmitter {
fn default() -> Self {
Self {
mode: 0,
}
}
}
impl Component for ParticleEmitter {
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
}

View File

@ -43,6 +43,7 @@ pub enum ServerEvent {
dir: Dir,
body: comp::Body,
light: Option<comp::LightEmitter>,
particles: Option<comp::ParticleEmitter>,
projectile: comp::Projectile,
gravity: Option<comp::Gravity>,
},

View File

@ -15,6 +15,7 @@ sum_type! {
Stats(comp::Stats),
Energy(comp::Energy),
LightEmitter(comp::LightEmitter),
ParticleEmitter(comp::ParticleEmitter),
Item(comp::Item),
Scale(comp::Scale),
Group(comp::Group),
@ -42,6 +43,7 @@ sum_type! {
Stats(PhantomData<comp::Stats>),
Energy(PhantomData<comp::Energy>),
LightEmitter(PhantomData<comp::LightEmitter>),
ParticleEmitter(PhantomData<comp::ParticleEmitter>),
Item(PhantomData<comp::Item>),
Scale(PhantomData<comp::Scale>),
Group(PhantomData<comp::Group>),
@ -69,6 +71,7 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPacket::Stats(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Energy(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::LightEmitter(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::ParticleEmitter(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Item(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Scale(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Group(comp) => sync::handle_insert(comp, entity, world),
@ -94,6 +97,7 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPacket::Stats(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Energy(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::LightEmitter(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::ParticleEmitter(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Item(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Scale(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Group(comp) => sync::handle_modify(comp, entity, world),
@ -121,6 +125,9 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPhantom::LightEmitter(_) => {
sync::handle_remove::<comp::LightEmitter>(entity, world)
},
EcsCompPhantom::ParticleEmitter(_) => {
sync::handle_remove::<comp::ParticleEmitter>(entity, world)
},
EcsCompPhantom::Item(_) => sync::handle_remove::<comp::Item>(entity, world),
EcsCompPhantom::Scale(_) => sync::handle_remove::<comp::Scale>(entity, world),
EcsCompPhantom::Group(_) => sync::handle_remove::<comp::Group>(entity, world),

View File

@ -113,6 +113,7 @@ impl State {
ecs.register::<comp::Energy>();
ecs.register::<comp::CanBuild>();
ecs.register::<comp::LightEmitter>();
ecs.register::<comp::ParticleEmitter>();
ecs.register::<comp::Item>();
ecs.register::<comp::Scale>();
ecs.register::<comp::Mounting>();

View File

@ -1,5 +1,5 @@
use crate::{
comp::{Body, CharacterState, Gravity, LightEmitter, Projectile, StateUpdate},
comp::{Body, CharacterState, Gravity, LightEmitter, ParticleEmitter, Projectile, StateUpdate},
event::ServerEvent,
states::utils::*,
sys::character_behavior::*,
@ -20,6 +20,7 @@ pub struct Data {
pub projectile: Projectile,
pub projectile_body: Body,
pub projectile_light: Option<LightEmitter>,
pub projectile_particles: Option<ParticleEmitter>,
pub projectile_gravity: Option<Gravity>,
/// Whether the attack fired already
pub exhausted: bool,
@ -48,6 +49,7 @@ impl CharacterBehavior for Data {
projectile: self.projectile.clone(),
projectile_body: self.projectile_body,
projectile_light: self.projectile_light,
projectile_particles: self.projectile_particles,
projectile_gravity: self.projectile_gravity,
exhausted: false,
});
@ -61,6 +63,7 @@ impl CharacterBehavior for Data {
body: self.projectile_body,
projectile,
light: self.projectile_light,
particles: self.projectile_particles,
gravity: self.projectile_gravity,
});
@ -72,6 +75,7 @@ impl CharacterBehavior for Data {
projectile: self.projectile.clone(),
projectile_body: self.projectile_body,
projectile_light: self.projectile_light,
projectile_particles: self.projectile_particles,
projectile_gravity: self.projectile_gravity,
exhausted: true,
});
@ -88,6 +92,7 @@ impl CharacterBehavior for Data {
projectile: self.projectile.clone(),
projectile_body: self.projectile_body,
projectile_light: self.projectile_light,
projectile_particles: self.projectile_particles,
projectile_gravity: self.projectile_gravity,
exhausted: true,
});

View File

@ -910,6 +910,7 @@ fn handle_light(
.create_entity_synced()
.with(pos)
.with(comp::ForceUpdate)
.with(comp::ParticleEmitter { mode: 0 })
.with(light_emitter);
if let Some(light_offset) = light_offset_opt {
builder.with(light_offset).build();

View File

@ -1,8 +1,8 @@
use crate::{sys, Server, StateExt};
use common::{
comp::{
self, group, Agent, Alignment, Body, Gravity, Item, ItemDrop, LightEmitter, Loadout, Pos,
Projectile, Scale, Stats, Vel, WaypointArea,
self, Agent, Alignment, Body, Gravity, Item, ItemDrop, LightEmitter, Loadout,
ParticleEmitter, Pos, Projectile, Scale, Stats, Vel, WaypointArea,
},
util::Dir,
};
@ -77,6 +77,7 @@ pub fn handle_shoot(
dir: Dir,
body: Body,
light: Option<LightEmitter>,
particles: Option<ParticleEmitter>,
projectile: Projectile,
gravity: Option<Gravity>,
) {
@ -96,6 +97,9 @@ pub fn handle_shoot(
if let Some(light) = light {
builder = builder.with(light)
}
if let Some(particles) = particles {
builder = builder.with(particles)
}
if let Some(gravity) = gravity {
builder = builder.with(gravity)
}
@ -113,6 +117,7 @@ pub fn handle_create_waypoint(server: &mut Server, pos: Vec3<f32>) {
flicker: 1.0,
animated: true,
})
.with(ParticleEmitter { mode: 0 })
.with(WaypointArea::default())
.build();
}

View File

@ -61,9 +61,10 @@ impl Server {
dir,
body,
light,
particles,
projectile,
gravity,
} => handle_shoot(self, entity, dir, body, light, projectile, gravity),
} => handle_shoot(self, entity, dir, body, light, particles, projectile, gravity),
ServerEvent::Damage { uid, change } => handle_damage(&self, uid, change),
ServerEvent::Destroy { entity, cause } => handle_destroy(self, entity, cause),
ServerEvent::InventoryManip(entity, manip) => handle_inventory(self, entity, manip),

View File

@ -1,8 +1,9 @@
use super::SysTimer;
use common::{
comp::{
Body, CanBuild, CharacterState, Collider, Energy, Gravity, Group, Item, LightEmitter,
Loadout, Mass, MountState, Mounting, Ori, Player, Pos, Scale, Stats, Sticky, Vel,
Alignment, Body, CanBuild, CharacterState, Collider, Energy, Gravity, Item, LightEmitter,
Loadout, Mass, MountState, Mounting, Ori, ParticleEmitter, Player, Pos, Scale, Stats,
Sticky, Vel,
},
msg::EcsCompPacket,
sync::{CompSyncPackage, EntityPackage, EntitySyncPackage, Uid, UpdateTracker, WorldSyncExt},
@ -44,6 +45,7 @@ pub struct TrackedComps<'a> {
pub energy: ReadStorage<'a, Energy>,
pub can_build: ReadStorage<'a, CanBuild>,
pub light_emitter: ReadStorage<'a, LightEmitter>,
pub particle_emitter: ReadStorage<'a, ParticleEmitter>,
pub item: ReadStorage<'a, Item>,
pub scale: ReadStorage<'a, Scale>,
pub mounting: ReadStorage<'a, Mounting>,
@ -92,6 +94,10 @@ impl<'a> TrackedComps<'a> {
.get(entity)
.copied()
.map(|c| comps.push(c.into()));
self.particle_emitter
.get(entity)
.copied()
.map(|c| comps.push(c.into()));
self.item.get(entity).cloned().map(|c| comps.push(c.into()));
self.scale
.get(entity)
@ -147,6 +153,7 @@ pub struct ReadTrackers<'a> {
pub energy: ReadExpect<'a, UpdateTracker<Energy>>,
pub can_build: ReadExpect<'a, UpdateTracker<CanBuild>>,
pub light_emitter: ReadExpect<'a, UpdateTracker<LightEmitter>>,
pub particle_emitter: ReadExpect<'a, UpdateTracker<ParticleEmitter>>,
pub item: ReadExpect<'a, UpdateTracker<Item>>,
pub scale: ReadExpect<'a, UpdateTracker<Scale>>,
pub mounting: ReadExpect<'a, UpdateTracker<Mounting>>,
@ -180,6 +187,12 @@ impl<'a> ReadTrackers<'a> {
&comps.light_emitter,
filter,
)
.with_component(
&comps.uid,
&*self.particle_emitter,
&comps.particle_emitter,
filter,
)
.with_component(&comps.uid, &*self.item, &comps.item, filter)
.with_component(&comps.uid, &*self.scale, &comps.scale, filter)
.with_component(&comps.uid, &*self.mounting, &comps.mounting, filter)
@ -210,6 +223,7 @@ pub struct WriteTrackers<'a> {
energy: WriteExpect<'a, UpdateTracker<Energy>>,
can_build: WriteExpect<'a, UpdateTracker<CanBuild>>,
light_emitter: WriteExpect<'a, UpdateTracker<LightEmitter>>,
particle_emitter: WriteExpect<'a, UpdateTracker<ParticleEmitter>>,
item: WriteExpect<'a, UpdateTracker<Item>>,
scale: WriteExpect<'a, UpdateTracker<Scale>>,
mounting: WriteExpect<'a, UpdateTracker<Mounting>>,
@ -232,6 +246,9 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
trackers.energy.record_changes(&comps.energy);
trackers.can_build.record_changes(&comps.can_build);
trackers.light_emitter.record_changes(&comps.light_emitter);
trackers
.particle_emitter
.record_changes(&comps.particle_emitter);
trackers.item.record_changes(&comps.item);
trackers.scale.record_changes(&comps.scale);
trackers.mounting.record_changes(&comps.mounting);
@ -287,6 +304,7 @@ pub fn register_trackers(world: &mut World) {
world.register_tracker::<Energy>();
world.register_tracker::<CanBuild>();
world.register_tracker::<LightEmitter>();
world.register_tracker::<ParticleEmitter>();
world.register_tracker::<Item>();
world.register_tracker::<Scale>();
world.register_tracker::<Mounting>();