use glam::{IVec2, Vec2}; use rapier2d::dynamics::RigidBodyBuilder; use crate::{ content::{materials::MaterialId, vfx::VfxMaterialId}, input::Input, sim::{ cell::Cell, entity::{EntityBehaviour, EntityCells, EntityDef, EntityUpdateCtx}, lib::force::apply_bullet, sim_manager::SimCtx, }, vfx::VfxLine, }; struct BulletEmitterEntityBehaviour { shot_timer: f32, life: f32, target: Option, } impl EntityBehaviour for BulletEmitterEntityBehaviour { fn update(&mut self, update_ctx: &mut EntityUpdateCtx, ctx: &mut SimCtx, delta_time: f32) { if self.target.is_none() && ctx.input_manager.pressed(Input::Action4) { self.target = Some(ctx.input_manager.world_mouse_pos); } if let Some(target) = self.target { let pos = update_ctx.entity_data.transform(ctx).unwrap().0; let dir = (target - pos).normalize(); let from = pos + (dir * 4.0); self.shot_timer -= delta_time; if self.shot_timer <= 0.0 { apply_bullet(ctx, from, target, 70); // 0.1 seconds to travel 200 cells let lifetime = (target - from).length() / 1000.0; ctx.vfx_writer.write_vfx_line(VfxLine::new( from, target, 1.3, VfxMaterialId::Tracer, lifetime, )); self.shot_timer = 0.2; } self.life -= delta_time; if self.life <= 0.0 { update_ctx.deferred_destroy(update_ctx.entity_data.id); } } } } pub fn entity_bullet_emitter_def(position: Vec2, life: f32) -> EntityDef { let w = 6; let h = 3; let mut raw_cells = vec![Cell::void(); (w * h) as usize]; for x in 0..w { for y in 0..h { let cell_idx = x + y * w; raw_cells[cell_idx as usize] = Cell::from_material(MaterialId::Steel); raw_cells[cell_idx as usize].set_entity_integrated(true); } } let entity_cells = EntityCells { cells: raw_cells, size: IVec2::new(w, h), }; let rb = RigidBodyBuilder::dynamic() .translation(position) .gravity_scale(0.0) .build(); EntityDef::from_cells_and_rb( entity_cells, rb, Some(Box::new(BulletEmitterEntityBehaviour { shot_timer: 0.0, life, target: None, })), ) }