فهرست منبع

Fixed some bugs with player movement and updated raycasting

Gary Munnelly 2 سال پیش
والد
کامیت
1c482e9dd6

+ 2 - 0
demo/src/player.rs

@@ -280,9 +280,11 @@ impl Player {
 
 	pub fn turn_left(&mut self) {
 		self.camera.rotate(-self.rotate_speed);
+		log!("{}", self.camera.angle());
 	}
 
 	pub fn turn_right(&mut self) {
 		self.camera.rotate(self.rotate_speed);
+		log!("{}", self.camera.angle());
 	}
 }

+ 3 - 3
demo/webapp/demo-level.js

@@ -1,10 +1,10 @@
 module.exports = {
-  camera: { x: 32, y: 32, angle: 0, horizon: 100 },
+  camera: { x: 128, y: 128, angle: 0, horizon: 100 },
   scene: {
   	width: 5,
   	height: 5,
-  	x_walls: [ 4, 0, 0, 0, 4, 4, 0, 0, 0, 4, 2, 0, 0, 0, 66, 4, 0, 0, 0, 4, 4, 0, 0, 0, 4 ],
-  	y_walls: [ 4, 4, 66, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 66, 4, 4 ],
+  	x_walls: [ 4, 4, 66, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 66, 4, 4 ],
+  	y_walls: [ 4, 0, 0, 0, 4, 4, 0, 0, 0, 4, 2, 0, 0, 0, 66, 4, 0, 0, 0, 4, 4, 0, 0, 0, 4 ],
   	ceiling: [ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 ],
   	floor  : [ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23 ]
   },

+ 0 - 14
engine/src/render/camera.rs

@@ -66,17 +66,3 @@ impl Camera {
 		Ok(Camera::new(x, y, a, h))
 	}
 }
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-
-	#[test]
-	fn test_initialize() {
-		let camera = Camera::new(10, 15, 20, 25);
-		assert_eq!(camera.x(), 10);
-		assert_eq!(camera.y(), 15);
-		assert_eq!(camera.angle(), 20);
-		assert_eq!(camera.horizon(), 25);
-	}
-}

+ 46 - 16
engine/src/render/raycast.rs

@@ -22,18 +22,18 @@ impl Intersection {
 }
 
 struct Ray<'a> {
-	step_x: i32, // distance to next vertical intersect
-	step_y: i32, // distance to next horizontal intersect
-	x: i32,      // x coordinate of current ray intersect
-	y: i32,      // y coordinate of current ray intersect
-	flipped: bool,
-	direction: i32,
-	scene: &'a Scene,
-	origin_x: i32,
-	origin_y: i32,
-
-	cast_ray: fn(&mut Self) -> Option<Intersection>,
-	check_undefined: fn(&Self) -> bool
+	step_x: i32,        // distance to next vertical intersect
+	step_y: i32,        // distance to next horizontal intersect
+	x: i32,             // x coordinate of current ray intersect
+	y: i32,             // y coordinate of current ray intersect
+	flipped: bool,      // should the texture of the encountered surface be rendered backwards
+	direction: i32,     // direction in which the ray is cast
+	scene: &'a Scene,   // the environment in which the ray is being cast
+	origin_x: i32,      // x point of origin of the ray in fixed point representation
+	origin_y: i32,      // y point of origin of the ray in fixed point representation
+
+	cast_ray: fn(&mut Self) -> Option<Intersection>, // either cast_horizontal or cast_vertical depending on ray type
+	check_undefined: fn(&Self) -> bool               // either horizontal_is_undefined or vertical_is_undefined depending on ray type
 }
 
 impl Ray<'_> {
@@ -116,7 +116,7 @@ impl Ray<'_> {
 			let grid_x = fp::div(self.x, consts::FP_TILE_SIZE).to_i32();
 			let grid_y = fp::div(self.y, consts::FP_TILE_SIZE).to_i32();
 			
-			match self.scene.x_wall(grid_x, grid_y) {
+			match self.scene.y_wall(grid_x, grid_y) {
 				Tile::Wall(wall) => {
 					let world_x  = self.x.to_i32();
 					let world_y  = self.y.to_i32();
@@ -142,9 +142,9 @@ impl Ray<'_> {
 		while !result.is_some() {
 			let grid_x = fp::div(self.x, consts::FP_TILE_SIZE).to_i32();
 			let grid_y = fp::div(self.y, consts::FP_TILE_SIZE).to_i32();
-			
+
 			match self.scene.x_wall(grid_x, grid_y) {
-				Tile::Wall(wall) => {
+				Tile::Wall(wall) => {					
 					let world_x  = self.x.to_i32();
 					let world_y  = self.y.to_i32();
 					let distance = fp::mul(fp::sub(self.x, self.origin_x), trig::icos(self.direction)).abs();
@@ -194,9 +194,39 @@ impl RayCaster {
 #[cfg(test)]
 mod test {
 	use super::*;
+	use std::fs;
+	use std::path::Path;
+	use std::path::PathBuf;
+
+	fn load_scene(fname: &PathBuf) -> Result<Scene, Box<dyn std::error::Error>> {
+		let contents = fs::read_to_string(fname)?;
+		let json: serde_json::Value = serde_json::from_str(contents.as_str())?;
+		let scene = Scene::from_json(&json)?;
+		Ok(scene)
+	}
+
+	#[test]
+	fn test_facing_directly_right() {
+		let fname = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests").join("resources").join("test-scene-1.json");
+		let scene = load_scene(&fname).expect("Failed to load scene for test");
+		let raycaster = RayCaster::new();
+
+		let intersections = raycaster.find_wall_intersections(128.to_fp(), 128.to_fp(), trig::ANGLE_0, &scene);
+
+		assert_eq!(1, intersections.len());
+	}
 
 	#[test]
-	fn name() {
+	fn test_against_wall() {
+		let fname = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests").join("resources").join("test-scene-1.json");
+		let scene = load_scene(&fname).expect("Failed to load scene for test");
 		let raycaster = RayCaster::new();
+
+		let intersections = raycaster.find_wall_intersections(28.to_fp(), 28.to_fp(), trig::ANGLE_270, &scene);
+
+		assert_eq!(1, intersections.len());
+
+		let intersection = intersections[0];
+		assert_eq!(28, intersection.dist.to_i32());
 	}
 }

+ 2 - 2
engine/src/render/renderer.rs

@@ -128,7 +128,7 @@ impl Renderer {
 		let y_max = parameters[0].y_max;
 
 		for y in y_min..=y_max {
-			let mut pixel = Colour::new(255, 0, 0, 255);
+			let mut pixel = Colour::new(0, 0, 0, 0);
 			
 			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
 			
@@ -187,7 +187,7 @@ impl Renderer {
 			
 			// for each intersection, get a reference to its texture and figure out how
 			// it should be drawn
-			let parameters = intersects.iter().map(|intersect| {
+			let parameters: Vec<RenderParameters> = intersects.iter().map(|intersect| {
 				let dist        = fp::div(intersect.dist, trig::fisheye_correction(sweep)).to_i32();
 				let wall_height = trig::wall_height(dist);
 				let mid_height  = wall_height >> 1;

+ 1 - 0
engine/src/trig.rs

@@ -46,6 +46,7 @@ pub fn wall_height(distance: i32) -> i32 {
 }
 
 pub fn wall_texture_index(height: i32) -> &'static [usize] {
+	let height      = height.clamp(shared::consts::render::WALL_HEIGHT_MIN, shared::consts::render::WALL_HEIGHT_MAX);
 	let true_i      = height - shared::consts::render::WALL_HEIGHT_MIN;
 	let head: usize = (true_i * shared::consts::display::PROJECTION_PLANE_HEIGHT) as usize;
 	let tail: usize = head + shared::consts::display::PROJECTION_PLANE_HEIGHT as usize;

+ 8 - 0
engine/tests/resources/test-scene-1.json

@@ -0,0 +1,8 @@
+{
+  "width": 5,
+  "height": 5,
+  "x_walls": [ 4, 0, 0, 0, 4, 4, 0, 0, 0, 4, 2, 0, 0, 0, 66, 4, 0, 0, 0, 4, 4, 0, 0, 0, 4 ],
+  "y_walls": [ 4, 4, 66, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 66, 4, 4 ],
+  "ceiling": [ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 ],
+  "floor": [ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23 ]
+}

+ 1 - 1
macros/src/lib.rs

@@ -120,7 +120,7 @@ fn declare_wall_height_table() -> TokenStream {
 }
 
 fn declare_wall_texture_index_table() -> TokenStream {
-    const RANGE: i32  = consts::WALL_HEIGHT_MAX - consts::WALL_HEIGHT_MIN;
+    const RANGE: i32  = (consts::WALL_HEIGHT_MAX - consts::WALL_HEIGHT_MIN) + 1;
     const SIZE: usize = (RANGE * consts::PROJECTION_PLANE_HEIGHT) as usize;
     
     let mut wall_texture_index: [usize; SIZE] = [ 0; SIZE ];