From f98e5d0318084d502b29c022119a7a8ba8b58ddf Mon Sep 17 00:00:00 2001 From: Martin Indra Date: Mon, 4 Jul 2022 18:51:13 +0200 Subject: [PATCH] Implement laser beam Relates to #24. --- crates/attacking/src/beam.rs | 186 ++++++++++++++++++++++++++++++++++ crates/attacking/src/laser.rs | 10 +- crates/attacking/src/lib.rs | 5 +- 3 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 crates/attacking/src/beam.rs diff --git a/crates/attacking/src/beam.rs b/crates/attacking/src/beam.rs new file mode 100644 index 00000000..ea176e51 --- /dev/null +++ b/crates/attacking/src/beam.rs @@ -0,0 +1,186 @@ +use std::time::Duration; + +use bevy::{ + prelude::*, + render::mesh::{Indices, PrimitiveTopology}, +}; +use de_core::state::GameState; +use iyes_loopless::prelude::*; +use parry3d::query::Ray; + +use crate::AttackingLabels; + +/// All but bottom vertex of a hexagon. The hexagon lies on plane perpendicular +/// to X axis. The vertices start with the bottom-right point. +/// +/// It looks like this: +/// +/// /\ +/// / \ +/// | | +/// | | +const HEXAGON_VERTICES: [[f32; 3]; 5] = [ + [0., -0.25, 0.433], + [0., 0.25, 0.433], + [0., 0.5, 0.], + [0., 0.25, -0.433], + [0., -0.25, -0.433], +]; + +/// Outwards normals of a hexagon whose base is given by [`HEXAGON_VERTICES`]. +/// The bottom two edges are / surfaces are not included. It starts with normal +/// of the right (largest Z coordinate) surface. +const HEXAGON_NORMALS: [[f32; 3]; 4] = [ + [0., 0., 1.], + [0., 0.866_025_4, 0.5], + [0., 0.866_025_4, -0.5], + [0., 0., -1.], +]; + +const BEAM_COLOR: Color = Color::rgba(0.2, 0., 1., 0.4); +const BEAM_DURATION: Duration = Duration::from_millis(500); + +pub(crate) struct BeamPlugin; + +impl Plugin for BeamPlugin { + fn build(&self, app: &mut App) { + app.add_event::() + .add_enter_system(GameState::Playing, setup) + .add_system_set_to_stage( + CoreStage::Update, + SystemSet::new() + .with_system( + spawn + .run_in_state(GameState::Playing) + .label(AttackingLabels::Beam), + ) + .with_system(despawn.run_in_state(GameState::Playing)), + ); + } +} + +pub(crate) struct SpawnBeamEvent(Ray); + +impl SpawnBeamEvent { + /// Send this event to spawn a new beam. The beam will automatically + /// disappear after a moment. + /// + /// # Arguments + /// + /// * `ray` - the beam originates at the ray origin. The beam ends at the + /// `ray.origin + ray.dir`. + pub(crate) fn new(ray: Ray) -> Self { + Self(ray) + } + + fn ray(&self) -> &Ray { + &self.0 + } +} + +struct BeamHandles { + material: Handle, + mesh: Handle, +} + +#[derive(Component)] +struct Beam { + timer: Timer, +} + +impl Beam { + fn new() -> Self { + Self { + timer: Timer::new(BEAM_DURATION, false), + } + } + + fn tick(&mut self, duration: Duration) -> bool { + self.timer.tick(duration); + self.timer.finished() + } +} + +fn spawn( + mut commands: Commands, + handles: Res, + mut events: EventReader, +) { + for event in events.iter() { + commands + .spawn_bundle(PbrBundle { + mesh: handles.mesh.clone(), + material: handles.material.clone(), + transform: Transform { + translation: event.ray().origin.into(), + rotation: Quat::from_rotation_arc(Vec3::X, event.ray().dir.normalize().into()), + scale: Vec3::new(event.ray().dir.norm(), 0.1, 0.1), + }, + ..Default::default() + }) + .insert(Beam::new()); + } +} + +fn despawn(mut commands: Commands, time: Res