Skip to content

Commit

Permalink
Fix penetration bug of raycasting
Browse files Browse the repository at this point in the history
  • Loading branch information
msakuta committed Apr 30, 2023
1 parent 3b025cb commit 25d216f
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 17 deletions.
34 changes: 34 additions & 0 deletions src/agent/interpolation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,40 @@ pub(crate) fn interpolate_i<P: Into<Vector2<i32>>>(
return false;
}

/// A version of interpolation that won't miss diagonal walls.
/// Suitable for raycasting in grid tiles.
pub(crate) fn interpolate_raycast<P: Into<Vector2<i32>>>(
start: P,
target: P,
mut f: impl FnMut(Vector2<i32>) -> bool,
) -> bool {
let start_p = start.into();
let target_p = target.into();
let dx = start_p.x - target_p.x;
let dy = start_p.y - target_p.y;
let interpolates = dx.abs().max(dy.abs());
if interpolates == 0 {
return f(start_p);
}
let horizontal = dy.abs() < dx.abs();
let mut last_pos = start_p;
for i in 0..=interpolates {
let point = lerp_i(start_p, target_p, i as f64 / interpolates as f64);
if horizontal {
if last_pos.y != point.y {
f(Vector2::new(point.x, last_pos.y));
}
} else if last_pos.x != point.x {
f(Vector2::new(last_pos.x, point.y));
}
if f(point) {
return true;
}
last_pos = point;
}
return false;
}

/// Collision checking with steering model. It can interpolate curvature.
pub(crate) fn interpolate_steer(
start: &AgentState,
Expand Down
16 changes: 16 additions & 0 deletions src/fog_of_war.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::cell::RefCell;

use crate::{
agent::interpolation::{interpolate_i, interpolate_raycast},
entity::Entity,
game::{Board, Game, Resource},
};
Expand Down Expand Up @@ -99,3 +100,18 @@ impl Game {
self.fog[team].entities = shadow_entities;
}
}

pub(crate) fn precompute_ray_graph(range: usize) -> (Vec<Vec<[i32; 2]>>, Vec<Vec<[i32; 2]>>) {
let mut graph = vec![vec![]; range * range];
let mut forward = vec![vec![]; range * range];
for y in 0..range as i32 {
for x in 0..range as i32 {
interpolate_raycast([0, 0], [x, y], |p| {
graph[p.x as usize + p.y as usize * range].push([x, y].into());
forward[x as usize + y as usize * range].push(p.into());
false
});
}
}
(graph, forward)
}
19 changes: 2 additions & 17 deletions src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ use std::{
};

use crate::{
agent::{interpolation::interpolate_i, Agent, AgentClass, AgentState, Bullet},
agent::{Agent, AgentClass, AgentState, Bullet},
collision::CollisionShape,
entity::{Entity, GameEvent, VISION_RANGE},
fog_of_war::{FogGraph, FogOfWar, FOG_MAX_AGE},
fog_of_war::{precompute_ray_graph, FogGraph, FogOfWar, FOG_MAX_AGE},
measure_time,
mesh::{create_mesh, Mesh, MeshResult},
perlin_noise::{gen_terms, perlin_noise_pixel, Xor128},
Expand Down Expand Up @@ -933,18 +933,3 @@ pub fn is_passable_at_i(board: &[bool], shape: (usize, usize), pos: impl Into<[i
board[pos[0] + shape.0 * pos[1]]
}
}

fn precompute_ray_graph(range: usize) -> (Vec<Vec<[i32; 2]>>, Vec<Vec<[i32; 2]>>) {
let mut graph = vec![vec![]; range * range];
let mut forward = vec![vec![]; range * range];
for y in 0..range as i32 {
for x in 0..range as i32 {
interpolate_i([0, 0], [x, y], |p| {
graph[p.x as usize + p.y as usize * range].push([x, y].into());
forward[x as usize + y as usize * range].push(p.into());
false
});
}
}
(graph, forward)
}

0 comments on commit 25d216f

Please sign in to comment.