summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/camera.rs8
-rw-r--r--src/config.rs2
-rw-r--r--src/content/entities/entity_wizard.rs158
-rw-r--r--src/content/entities/mod.rs1
-rw-r--r--src/input.rs11
-rw-r--r--src/main.rs7
-rw-r--r--src/sim/entity/mod.rs41
-rw-r--r--src/sim/rb_manager/mod.rs4
8 files changed, 220 insertions, 12 deletions
diff --git a/src/camera.rs b/src/camera.rs
index 8d1fe78..3de7ba7 100644
--- a/src/camera.rs
+++ b/src/camera.rs
@@ -33,16 +33,16 @@ impl Camera {
pub fn handle_camera_input(&mut self, input_manager: &InputManager, delta_time: f32) {
// wasd movement
- let x: f32 = if input_manager.held(Input::Left) {
+ let x: f32 = if input_manager.held(Input::CameraLeft) {
-1.0
- } else if input_manager.held(Input::Right) {
+ } else if input_manager.held(Input::CameraRight) {
1.0
} else {
0.0
};
- let y: f32 = if input_manager.held(Input::Down) {
+ let y: f32 = if input_manager.held(Input::CameraDown) {
1.0
- } else if input_manager.held(Input::Up) {
+ } else if input_manager.held(Input::CameraUp) {
-1.0
} else {
0.0
diff --git a/src/config.rs b/src/config.rs
index 2b60c50..4bb11e1 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -20,3 +20,5 @@ pub const SETTLED_THRESOHLD: u8 = 7;
pub const MIN_ENTITY_CELLS: usize = 9;
pub const TILESET_SCALING: i32 = 8;
+
+pub const GRAVITY: f32 = 196.2;
diff --git a/src/content/entities/entity_wizard.rs b/src/content/entities/entity_wizard.rs
new file mode 100644
index 0000000..eea2a48
--- /dev/null
+++ b/src/content/entities/entity_wizard.rs
@@ -0,0 +1,158 @@
+use glam::Vec2;
+use rapier2d::{
+ control::{CharacterAutostep, CharacterLength, KinematicCharacterController},
+ pipeline::QueryFilter,
+};
+
+use crate::{
+ config::GRAVITY,
+ input::Input,
+ sim::{
+ entity::{EntityBehaviour, EntityDef, EntityUpdateCtx},
+ sim_manager::SimCtx,
+ },
+};
+
+struct WizardEntityBehaviour {
+ movement_input_x: f32,
+ jump: f32,
+
+ grounded: bool,
+ acc_vel: Vec2,
+ kinematic_controller: KinematicCharacterController,
+}
+
+const JUMP_VELOCITY: f32 = 100.0;
+const ACCEL: f32 = 1000.0;
+const AIR_ACCEL: f32 = 350.0;
+const MAX_SPEED: f32 = 75.0;
+
+impl EntityBehaviour for WizardEntityBehaviour {
+ fn update(&mut self, _: &mut EntityUpdateCtx, ctx: &mut SimCtx, _: f32) {
+ if ctx.input_manager.held(Input::Left) {
+ self.movement_input_x = -1.0;
+ } else if ctx.input_manager.held(Input::Right) {
+ self.movement_input_x = 1.0;
+ } else {
+ self.movement_input_x = 0.0;
+ }
+
+ if ctx.input_manager.pressed(Input::Up) {
+ self.jump = 0.06;
+ }
+ }
+
+ fn physics_update(
+ &mut self,
+ update_ctx: &mut EntityUpdateCtx,
+ ctx: &mut SimCtx,
+ delta_time: f32,
+ ) {
+ if self.grounded {
+ // TODO delta_time
+ if self.movement_input_x.abs() < 0.2 {
+ self.acc_vel.x = self.acc_vel.x * 0.7;
+ }
+ // if we're moving up, keep moving up
+ self.acc_vel.y = self.acc_vel.y.min(0.0);
+ if self.jump > 0.0 {
+ self.acc_vel.y -= JUMP_VELOCITY;
+ self.jump = 0.0;
+ }
+ } else {
+ self.acc_vel.x = self.acc_vel.x * 0.95;
+ self.acc_vel.y += GRAVITY * delta_time;
+
+ if self.jump > 0.0 {
+ self.jump -= delta_time;
+ }
+ }
+
+ if self.acc_vel.x.abs() < 1.0 {
+ self.acc_vel.x = 0.0;
+ }
+
+ let flip_adj = if self.acc_vel.x.signum() != self.movement_input_x.signum() {
+ 3.0
+ } else {
+ 1.0
+ };
+ self.acc_vel.x += self.movement_input_x
+ * if self.grounded { ACCEL } else { AIR_ACCEL }
+ * delta_time
+ * flip_adj;
+ self.acc_vel.x = self.acc_vel.x.clamp(-MAX_SPEED, MAX_SPEED);
+
+ let query_pipeline = ctx
+ .rb_manager
+ .physics_manager
+ .world
+ .query_pipeline_with_filter(
+ QueryFilter::default().exclude_rigid_body(update_ctx.entity_data.rb_h.unwrap()),
+ );
+
+ let rb = ctx
+ .rb_manager
+ .physics_manager
+ .world
+ .bodies
+ .get(update_ctx.entity_data.rb_h.unwrap())
+ .unwrap();
+
+ let collider = ctx
+ .rb_manager
+ .physics_manager
+ .world
+ .colliders
+ .get(update_ctx.entity_data.collider_h.unwrap())
+ .unwrap();
+
+ // move_shape works in translations, not velocities: feed it the distance we
+ // want to cover this step, and convert the allowed distance back to a velocity.
+ let movement = self.kinematic_controller.move_shape(
+ delta_time,
+ &query_pipeline,
+ collider.shape(),
+ rb.position(),
+ self.acc_vel * delta_time,
+ |_| {},
+ );
+
+ let rb = ctx
+ .rb_manager
+ .physics_manager
+ .world
+ .bodies
+ .get_mut(update_ctx.entity_data.rb_h.unwrap())
+ .unwrap();
+
+ rb.set_linvel(movement.translation / delta_time, true);
+
+ self.grounded = movement.grounded;
+ }
+}
+
+pub fn entity_wizard_def(position: Vec2) -> EntityDef {
+ let mut kinematic_controller = KinematicCharacterController::default();
+ kinematic_controller.up = -Vec2::Y;
+ kinematic_controller.autostep = Some(CharacterAutostep {
+ max_height: CharacterLength::Absolute(4.0),
+ min_width: CharacterLength::Absolute(8.0),
+ include_dynamic_bodies: false,
+ });
+ kinematic_controller.offset = CharacterLength::Absolute(0.1);
+ kinematic_controller.normal_nudge_factor = 1.0e-3;
+ kinematic_controller.max_slope_climb_angle = 45f32.to_radians();
+
+ EntityDef::kinematic_from_sprite(
+ position,
+ "assets/sprites/wizard",
+ Some(Box::new(WizardEntityBehaviour {
+ movement_input_x: 0.0,
+ jump: 0.0,
+ grounded: false,
+ acc_vel: Vec2::ZERO,
+ kinematic_controller,
+ })),
+ )
+}
diff --git a/src/content/entities/mod.rs b/src/content/entities/mod.rs
index 0ec45ce..11c1706 100644
--- a/src/content/entities/mod.rs
+++ b/src/content/entities/mod.rs
@@ -2,3 +2,4 @@ pub mod entity_bullet_emitter;
pub mod entity_cube;
pub mod entity_grenade;
pub mod entity_tnt;
+pub mod entity_wizard;
diff --git a/src/input.rs b/src/input.rs
index 30f3834..e795a61 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -14,6 +14,11 @@ pub enum Input {
Down,
Right,
+ CameraUp,
+ CameraLeft,
+ CameraDown,
+ CameraRight,
+
// sim management
Pause,
Step,
@@ -34,13 +39,17 @@ pub enum Input {
Action6,
}
-const INPUT_VAR_LEN: usize = 17;
+const INPUT_VAR_LEN: usize = 21;
const KEYMAP: [(KeyCode, Input); INPUT_VAR_LEN] = [
(KeyCode::KeyW, Input::Up),
(KeyCode::KeyA, Input::Left),
(KeyCode::KeyS, Input::Down),
(KeyCode::KeyD, Input::Right),
+ (KeyCode::ArrowUp, Input::CameraUp),
+ (KeyCode::ArrowLeft, Input::CameraLeft),
+ (KeyCode::ArrowDown, Input::CameraDown),
+ (KeyCode::ArrowRight, Input::CameraRight),
(KeyCode::Space, Input::Pause),
(KeyCode::KeyX, Input::Step),
(KeyCode::KeyC, Input::ClearGrid),
diff --git a/src/main.rs b/src/main.rs
index 019c8fa..4d62f8c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -24,6 +24,7 @@ use crate::{
entities::{
entity_bullet_emitter::entity_bullet_emitter_def, entity_cube::entity_cube_def,
entity_grenade::entity_grenade_def, entity_tnt::entity_tnt_def,
+ entity_wizard::entity_wizard_def,
},
materials::MaterialId,
world::mines::MinesBiome,
@@ -107,11 +108,7 @@ impl App {
}
if self.input_manager.pressed(Input::Action5) {
- sim.create_entity(EntityDef::from_sprite(
- self.input_manager.world_mouse_pos,
- "assets/sprites/wizard",
- None,
- ));
+ sim.create_entity(entity_wizard_def(self.input_manager.world_mouse_pos));
}
if self.input_manager.pressed(Input::Action3) {
diff --git a/src/sim/entity/mod.rs b/src/sim/entity/mod.rs
index 9425f9b..4a8eda4 100644
--- a/src/sim/entity/mod.rs
+++ b/src/sim/entity/mod.rs
@@ -2,6 +2,7 @@ use glam::{IVec2, Vec2};
use rapier2d::{
dynamics::{RigidBody, RigidBodyBuilder, RigidBodyHandle},
geometry::{Collider, ColliderHandle},
+ math::Pose2,
};
use crate::{
@@ -123,6 +124,46 @@ impl EntityDef {
EntityDef::from_cells(position, entity_cells, behaviour)
}
+
+ pub fn kinematic_from_cells(
+ position: Vec2,
+ cells: EntityCells,
+ behaviour: Option<Box<dyn EntityBehaviour>>,
+ ) -> Self {
+ let rb = RigidBodyBuilder::kinematic_velocity_based()
+ .translation(position)
+ .build();
+
+ let collider = RbManager::convex_hull_collider_from_marchable(&cells, Some(10))
+ .mass(mass_from_cells(&cells.cells))
+ .build();
+
+ EntityDef {
+ rb: Some(rb),
+ collider: Some(collider),
+ cells: Some(cells),
+ behaviour,
+ }
+ }
+
+ pub fn kinematic_from_sprite(
+ position: Vec2,
+ path: &str,
+ behaviour: Option<Box<dyn EntityBehaviour>>,
+ ) -> Self {
+ let sprite_cells = load_sprite_to_cells(path);
+ let mut entity_cells = EntityCells {
+ cells: sprite_cells.cells,
+ size: IVec2::new(sprite_cells.width as i32, sprite_cells.height as i32),
+ };
+
+ entity_cells
+ .cells
+ .iter_mut()
+ .for_each(|c| c.set_entity_integrated(true));
+
+ EntityDef::kinematic_from_cells(position, entity_cells, behaviour)
+ }
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
diff --git a/src/sim/rb_manager/mod.rs b/src/sim/rb_manager/mod.rs
index 2b476d5..1be024a 100644
--- a/src/sim/rb_manager/mod.rs
+++ b/src/sim/rb_manager/mod.rs
@@ -11,7 +11,7 @@ use rapier2d::{
};
use crate::{
- config::{CELLS_TO_METRES, CHUNK_SIZE, PHYSICS_DELTA_TIME},
+ config::{CELLS_TO_METRES, CHUNK_SIZE, GRAVITY, PHYSICS_DELTA_TIME},
sim::{
cell_manager::chunk::Chunk,
lib::marching_squares::{Marchable, marching_squares_vertex_trace},
@@ -29,7 +29,7 @@ pub struct PhysicsManager {
impl PhysicsManager {
pub fn new() -> Self {
let mut world = PhysicsWorld::new();
- let gravity = vec2(0.0, 9.81 * CELLS_TO_METRES);
+ let gravity = vec2(0.0, GRAVITY);
world.gravity = gravity;
world.integration_parameters = IntegrationParameters {
// 20 pixels <-> 1 meter