Initial work on proper character movement
This commit is contained in:
+14
-11
@@ -1,16 +1,19 @@
|
||||
use bevy::{color::palettes::css::RED, prelude::*};
|
||||
|
||||
use crate::stage::StageLine;
|
||||
use crate::stage::{StagePoly, line::StageCollision};
|
||||
|
||||
pub fn debug_draw_scene(mut gizmos: Gizmos, stage_collision: Res<StageCollision>) {
|
||||
for poly in stage_collision.stage_polys.iter() {
|
||||
for segment in poly.segments.iter() {
|
||||
let from = segment.segment.point1();
|
||||
let to = segment.segment.point2();
|
||||
let from_3d = Vec3::new(from.x, from.y, 0.0);
|
||||
let end_3d = Vec3::new(to.x, to.y, 0.0);
|
||||
let normal_3d = Vec3::new(segment.normal.x, segment.normal.y, 0.0);
|
||||
gizmos.line(from_3d, end_3d, RED);
|
||||
let midpoint = (from_3d + end_3d) * 0.5;
|
||||
gizmos.arrow(midpoint, midpoint + normal_3d, RED);
|
||||
}
|
||||
|
||||
pub fn debug_draw_scene(mut gizmos: Gizmos, planes: Query<&StageLine>) {
|
||||
for plane in planes {
|
||||
let from = plane.segment.point1();
|
||||
let to = plane.segment.point2();
|
||||
let from_3d = Vec3::new(from.x, from.y, 0.0);
|
||||
let end_3d = Vec3::new(to.x, to.y, 0.0);
|
||||
let normal_3d = Vec3::new(plane.normal.x, plane.normal.y, 0.0);
|
||||
gizmos.line(from_3d, end_3d, RED);
|
||||
let midpoint = (from_3d + end_3d) * 0.5;
|
||||
gizmos.arrow(midpoint, midpoint + normal_3d, RED);
|
||||
}
|
||||
}
|
||||
|
||||
+124
-13
@@ -1,34 +1,145 @@
|
||||
//! Stage collision geometry.
|
||||
|
||||
use std::default;
|
||||
|
||||
use bevy::{math::InvalidDirectionError, prelude::*};
|
||||
|
||||
use crate::math::SegmentIntersection;
|
||||
use crate::math::segment::SegmentIntersection;
|
||||
|
||||
#[derive(Reflect, Clone, Copy, PartialEq)]
|
||||
pub enum StagePolyLineSegmentType {
|
||||
Floor, Wall, Ceiling
|
||||
}
|
||||
|
||||
|
||||
#[derive(Reflect, Clone)]
|
||||
pub struct StagePolyLineSegment {
|
||||
pub segment: Segment2d,
|
||||
pub normal: Vec2,
|
||||
pub segment_type: StagePolyLineSegmentType
|
||||
}
|
||||
|
||||
#[derive(Reflect, Clone, Default)]
|
||||
pub enum StagePolyType {
|
||||
#[default]
|
||||
Closed,
|
||||
Platform
|
||||
}
|
||||
|
||||
#[derive(Reflect, Hash, Debug, Clone, Copy, Default)]
|
||||
pub struct StageLineID {
|
||||
pub polygon: usize,
|
||||
pub segment: usize
|
||||
}
|
||||
|
||||
#[derive(Component, Reflect, Clone, Default)]
|
||||
#[reflect(Component)]
|
||||
pub struct StageLine {
|
||||
pub segment: Segment2d,
|
||||
pub normal: Vec2,
|
||||
pub struct StagePoly {
|
||||
poly_type: StagePolyType,
|
||||
pub segments: Vec<StagePolyLineSegment>
|
||||
}
|
||||
|
||||
pub struct StagePlaneIntersectResult {
|
||||
pub position: Vec2,
|
||||
pub segment_idx: usize,
|
||||
pub normal: Vec2
|
||||
}
|
||||
|
||||
impl StageLine {
|
||||
pub fn new(start: Vec2, end: Vec2) -> Result<Self, InvalidDirectionError> {
|
||||
let segment = Segment2d::new(start, end);
|
||||
let normal = segment.left_normal().as_vec2();
|
||||
Ok(Self { segment, normal })
|
||||
#[derive(Resource, Reflect, Clone, Default)]
|
||||
#[reflect(Resource)]
|
||||
pub struct StageCollision {
|
||||
pub stage_polys: Vec<StagePoly>
|
||||
}
|
||||
|
||||
impl StagePoly {
|
||||
pub fn intersect_ray(&self, ray_segment: Segment2d) -> Option<StagePlaneIntersectResult> {
|
||||
for (i, segment) in self.segments.iter().enumerate() {
|
||||
if let Some(intersection) = segment.segment.segment_intersection(&ray_segment) {
|
||||
println!("DIST3 {} {}", intersection, segment.segment.closest_point(intersection));
|
||||
return Some(StagePlaneIntersectResult {
|
||||
position: intersection,
|
||||
segment_idx: i,
|
||||
normal: segment.normal
|
||||
});
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn intersect_ray(&self, segment: Segment2d) -> Option<StagePlaneIntersectResult> {
|
||||
self.segment
|
||||
.segment_intersection(&segment)
|
||||
.map(|position| StagePlaneIntersectResult { position })
|
||||
pub fn get_segment(&self, segment_idx: usize) -> Option<&StagePolyLineSegment> {
|
||||
self.segments.get(segment_idx)
|
||||
}
|
||||
|
||||
pub fn get_next_segment(&self, segment_idx: usize) -> Option<&StagePolyLineSegment> {
|
||||
self.segments.get(segment_idx % segment_idx + 1)
|
||||
}
|
||||
|
||||
pub fn get_prev_segment(&self, segment_idx: usize) -> Option<&StagePolyLineSegment> {
|
||||
self.segments.get(segment_idx % segment_idx + 1)
|
||||
}
|
||||
|
||||
pub fn build(poly_type: StagePolyType, points: &[(Vec2, StagePolyLineSegmentType)]) -> Self {
|
||||
let windows = points.iter().zip(points.iter().cycle().skip(1));
|
||||
|
||||
let segments = windows.map(|segment_window| {
|
||||
let (first_point, segment_type) = segment_window.0;
|
||||
let (second_point, _) = segment_window.1;
|
||||
let segment = Segment2d::new(*first_point, *second_point);
|
||||
StagePolyLineSegment {
|
||||
segment_type: *segment_type,
|
||||
segment,
|
||||
normal: segment.left_normal().as_vec2()
|
||||
}
|
||||
}).collect();
|
||||
|
||||
Self {
|
||||
poly_type,
|
||||
segments
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StagePolyLineSegment {
|
||||
pub fn project(&self, vec: Vec2) -> Vec2 {
|
||||
vec - vec.project_onto_normalized(self.normal)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn ray_intersection_test() {
|
||||
let stage_poly = StagePoly::build(crate::stage::line::StagePolyType::Platform, &[
|
||||
(Vec2::new(-4.5, 0.0), StagePolyLineSegmentType::Floor),
|
||||
(Vec2::new(4.5, 0.0), StagePolyLineSegmentType::Floor),
|
||||
]);
|
||||
|
||||
let res = stage_poly.intersect_ray(Segment2d::new(Vec2::new(0.0, 1.0), Vec2::new(0.0, -1.0)));
|
||||
assert!(res.is_some());
|
||||
assert_eq!(res.unwrap().position, Vec2::ZERO);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ray_intersection_test_side() {
|
||||
let stage_poly = StagePoly::build(crate::stage::line::StagePolyType::Platform, &[
|
||||
(Vec2::new(-4.5, 0.0), StagePolyLineSegmentType::Floor),
|
||||
(Vec2::new(4.5, 0.0), StagePolyLineSegmentType::Floor),
|
||||
]);
|
||||
|
||||
let res = stage_poly.intersect_ray(Segment2d::new(Vec2::new(2.0, 1.0), Vec2::new(2.0, -1.0)));
|
||||
assert!(res.is_some());
|
||||
assert_eq!(res.unwrap().position, Vec2::new(2.0, 0.0));
|
||||
}
|
||||
#[test]
|
||||
fn ray_intersection_test_diagonal() {
|
||||
let stage_poly = StagePoly::build(crate::stage::line::StagePolyType::Platform, &[
|
||||
(Vec2::new(0.0, 0.0), StagePolyLineSegmentType::Floor),
|
||||
(Vec2::new(2.0, 2.0), StagePolyLineSegmentType::Floor),
|
||||
]);
|
||||
|
||||
let res = stage_poly.intersect_ray(Segment2d::new(Vec2::new(1.0, 2.0), Vec2::new(1.0, -2.0)));
|
||||
assert!(res.is_some());
|
||||
assert_eq!(res.unwrap().position, Vec2::new(1.0, 1.0));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ pub mod debug;
|
||||
pub mod line;
|
||||
pub mod scene;
|
||||
|
||||
pub use line::{StageLine, StagePlaneIntersectResult};
|
||||
pub use line::{StagePoly, StagePlaneIntersectResult};
|
||||
|
||||
/// Owns the stage geometry: which scene gets spawned and how it is drawn.
|
||||
#[derive(Default)]
|
||||
|
||||
+26
-14
@@ -1,37 +1,49 @@
|
||||
//! The scene content that gets spawned at startup.
|
||||
|
||||
use bevy::prelude::*;
|
||||
use std::f32::consts::PI;
|
||||
|
||||
use crate::stage::StageLine;
|
||||
use bevy::{camera_controller::free_camera::FreeCamera, prelude::*};
|
||||
|
||||
use crate::stage::{StagePoly, line::StagePolyLineSegmentType, line::StageCollision};
|
||||
|
||||
/// set up a simple 3D scene
|
||||
pub fn test_scene() -> impl SceneList {
|
||||
|
||||
let stage_poly = StagePoly::build(crate::stage::line::StagePolyType::Closed, &[
|
||||
(Vec2::new(-5.6, -0.35), StagePolyLineSegmentType::Floor),
|
||||
(Vec2::new(-3.92, 0.0), StagePolyLineSegmentType::Floor),
|
||||
(Vec2::new(0.0, 0.0), StagePolyLineSegmentType::Floor),
|
||||
(Vec2::new(3.92, 0.0), StagePolyLineSegmentType::Floor),
|
||||
(Vec2::new(5.6, -0.35), StagePolyLineSegmentType::Wall),
|
||||
(Vec2::new(5.6, -20.0), StagePolyLineSegmentType::Ceiling),
|
||||
(Vec2::new(-5.6, -20.0), StagePolyLineSegmentType::Wall)
|
||||
]);
|
||||
|
||||
bsn_list! [
|
||||
(
|
||||
#Cube
|
||||
Mesh3d(asset_value(Cuboid::new(5.0, 1.0, 1.0)))
|
||||
MeshMaterial3d::<StandardMaterial>(asset_value(Color::srgb_u8(124, 144, 255)))
|
||||
Transform::from_xyz(0.0, 0.5, 0.0)
|
||||
#StageCollision
|
||||
template_value(StageCollision {
|
||||
stage_polys: vec!(stage_poly)
|
||||
})
|
||||
),
|
||||
(
|
||||
#StagePlane
|
||||
template_value(StageLine::new(Vec2::new(-2.5, 1.0), Vec2::new(2.5, 1.0)).unwrap())
|
||||
),
|
||||
(
|
||||
PointLight {
|
||||
DirectionalLight {
|
||||
shadow_maps_enabled: true,
|
||||
}
|
||||
Transform::from_xyz(4.0, 8.0, 4.0)
|
||||
Transform {
|
||||
translation: Vec3::new(0.0, 2.0, 0.0),
|
||||
rotation: Quat::from_rotation_x(-PI / 4.),
|
||||
}
|
||||
),
|
||||
(
|
||||
Camera3d
|
||||
template_value(Transform::from_xyz(0.0, 1.5, 9.0))
|
||||
/*FreeCamera {
|
||||
FreeCamera {
|
||||
sensitivity: 0.2,
|
||||
friction: 25.0,
|
||||
walk_speed: 3.0,
|
||||
run_speed: 9.0,
|
||||
}*/
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user