pub struct FlowField { /* private fields */ }Expand description
Flow field for AI movement
Implementations§
Source§impl FlowField
impl FlowField
pub fn new(width: usize, height: usize) -> Self
Sourcepub fn get_direction(&self, x: usize, y: usize) -> (i32, i32)
pub fn get_direction(&self, x: usize, y: usize) -> (i32, i32)
Examples found in repository?
examples/advanced_pathfinding.rs (line 91)
88fn print_flow_field(flow: &terrain_forge::spatial::FlowField) {
89 for y in 0..flow.height() {
90 for x in 0..flow.width() {
91 let (dx, dy) = flow.get_direction(x, y);
92 let arrow = match (dx, dy) {
93 (0, 0) => "●", // Goal
94 (-1, -1) => "↖", // Northwest
95 (0, -1) => "↑", // North
96 (1, -1) => "↗", // Northeast
97 (-1, 0) => "←", // West
98 (1, 0) => "→", // East
99 (-1, 1) => "↙", // Southwest
100 (0, 1) => "↓", // South
101 (1, 1) => "↘", // Southeast
102 _ => "?", // Unknown
103 };
104 print!("{} ", arrow);
105 }
106 println!();
107 }
108}More examples
examples/spatial_workflow.rs (line 86)
14fn main() {
15 println!("=== Complete Spatial Analysis Workflow ===\n");
16
17 // Step 1: Generate base dungeon
18 println!("1. Generating Base Dungeon:");
19 let mut grid = Grid::new(40, 30);
20 let algo = algorithms::get("bsp").unwrap();
21 algo.generate(&mut grid, 42424);
22
23 let original_floors = grid.count(|t| t.is_floor());
24 println!(
25 " Generated {}x{} dungeon with {} floor tiles",
26 grid.width(),
27 grid.height(),
28 original_floors
29 );
30
31 // Step 2: Clean up with morphological operations
32 println!("\n2. Cleaning Up Small Features:");
33 let cleanup_element = StructuringElement::rectangle(3, 3);
34 let cleaned = morphological_transform(&grid, MorphologyOp::Opening, &cleanup_element);
35
36 let cleaned_floors = cleaned.count(|t| t.is_floor());
37 println!(
38 " Removed {} small features ({} floors remaining)",
39 original_floors - cleaned_floors,
40 cleaned_floors
41 );
42
43 // Step 3: Analyze distances from walls
44 println!("\n3. Analyzing Distance from Walls:");
45 let distance_map = distance_field(&cleaned, DistanceMetric::Euclidean);
46
47 let mut max_distance = 0.0;
48 let mut center_points = Vec::new();
49
50 for y in 0..distance_map.height() {
51 for x in 0..distance_map.width() {
52 let dist = distance_map.get(x, y);
53 if dist != f32::INFINITY {
54 if dist > max_distance {
55 max_distance = dist;
56 center_points.clear();
57 center_points.push((x, y));
58 } else if (dist - max_distance).abs() < 0.1 {
59 center_points.push((x, y));
60 }
61 }
62 }
63 }
64
65 println!(" Maximum distance from walls: {:.1}", max_distance);
66 println!(" Found {} center points", center_points.len());
67
68 // Step 4: Create strategic pathfinding network
69 println!("\n4. Creating Strategic Pathfinding Network:");
70
71 // Use the most central points as strategic locations
72 let strategic_points: Vec<_> = center_points.into_iter().take(3).collect();
73 println!(" Strategic points: {:?}", strategic_points);
74
75 let constraints = PathfindingConstraints::default();
76 let strategic_dijkstra = dijkstra_map(&cleaned, &strategic_points, &constraints);
77
78 // Step 5: Generate AI movement flow field
79 println!("\n5. Generating AI Movement Flow Field:");
80 let flow_field = flow_field_from_dijkstra(&strategic_dijkstra);
81
82 // Analyze flow field coverage
83 let mut flow_coverage = 0;
84 for y in 0..flow_field.height() {
85 for x in 0..flow_field.width() {
86 let (dx, dy) = flow_field.get_direction(x, y);
87 if dx != 0 || dy != 0 {
88 flow_coverage += 1;
89 }
90 }
91 }
92
93 println!(" Flow field covers {} cells", flow_coverage);
94
95 // Step 6: Identify chokepoints using morphological analysis
96 println!("\n6. Identifying Chokepoints:");
97 let thin_element = StructuringElement::rectangle(2, 2);
98 let thinned = morphological_transform(&cleaned, MorphologyOp::Erosion, &thin_element);
99
100 let mut chokepoints = Vec::new();
101 for y in 1..cleaned.height() - 1 {
102 for x in 1..cleaned.width() - 1 {
103 if let (Some(original), Some(thinned_cell)) = (
104 cleaned.get(x as i32, y as i32),
105 thinned.get(x as i32, y as i32),
106 ) {
107 if original.is_floor() && !thinned_cell.is_floor() {
108 // This was a floor that got eroded - potential chokepoint
109 let neighbors = count_floor_neighbors(&cleaned, x, y);
110 if (2..=4).contains(&neighbors) {
111 chokepoints.push((x, y));
112 }
113 }
114 }
115 }
116 }
117
118 println!(" Found {} potential chokepoints", chokepoints.len());
119
120 // Step 7: Performance summary
121 println!("\n7. Performance Summary:");
122
123 let start = std::time::Instant::now();
124 let _ = morphological_transform(&grid, MorphologyOp::Opening, &cleanup_element);
125 println!(" Morphological cleanup: {:?}", start.elapsed());
126
127 let start = std::time::Instant::now();
128 let _ = distance_field(&cleaned, DistanceMetric::Euclidean);
129 println!(" Distance field calculation: {:?}", start.elapsed());
130
131 let start = std::time::Instant::now();
132 let _ = dijkstra_map(&cleaned, &strategic_points, &constraints);
133 println!(" Dijkstra map generation: {:?}", start.elapsed());
134
135 let start = std::time::Instant::now();
136 let _ = flow_field_from_dijkstra(&strategic_dijkstra);
137 println!(" Flow field generation: {:?}", start.elapsed());
138
139 // Step 8: Spatial analysis results
140 println!("\n8. Spatial Analysis Results:");
141 println!(" Original dungeon: {} floors", original_floors);
142 println!(" After cleanup: {} floors", cleaned_floors);
143 println!(" Strategic locations: {}", strategic_points.len());
144 println!(" Chokepoints identified: {}", chokepoints.len());
145 println!(
146 " Flow field coverage: {:.1}%",
147 100.0 * flow_coverage as f32 / cleaned_floors as f32
148 );
149
150 println!("\n✅ Spatial analysis workflow complete!");
151 println!(" The dungeon is now ready for:");
152 println!(" - AI pathfinding using flow fields");
153 println!(" - Strategic placement at center points");
154 println!(" - Tactical analysis of chokepoints");
155 println!(" - Distance-based gameplay mechanics");
156}pub fn set_direction(&mut self, x: usize, y: usize, dir: (i32, i32))
Sourcepub fn width(&self) -> usize
pub fn width(&self) -> usize
Examples found in repository?
examples/advanced_pathfinding.rs (line 90)
88fn print_flow_field(flow: &terrain_forge::spatial::FlowField) {
89 for y in 0..flow.height() {
90 for x in 0..flow.width() {
91 let (dx, dy) = flow.get_direction(x, y);
92 let arrow = match (dx, dy) {
93 (0, 0) => "●", // Goal
94 (-1, -1) => "↖", // Northwest
95 (0, -1) => "↑", // North
96 (1, -1) => "↗", // Northeast
97 (-1, 0) => "←", // West
98 (1, 0) => "→", // East
99 (-1, 1) => "↙", // Southwest
100 (0, 1) => "↓", // South
101 (1, 1) => "↘", // Southeast
102 _ => "?", // Unknown
103 };
104 print!("{} ", arrow);
105 }
106 println!();
107 }
108}More examples
examples/spatial_workflow.rs (line 85)
14fn main() {
15 println!("=== Complete Spatial Analysis Workflow ===\n");
16
17 // Step 1: Generate base dungeon
18 println!("1. Generating Base Dungeon:");
19 let mut grid = Grid::new(40, 30);
20 let algo = algorithms::get("bsp").unwrap();
21 algo.generate(&mut grid, 42424);
22
23 let original_floors = grid.count(|t| t.is_floor());
24 println!(
25 " Generated {}x{} dungeon with {} floor tiles",
26 grid.width(),
27 grid.height(),
28 original_floors
29 );
30
31 // Step 2: Clean up with morphological operations
32 println!("\n2. Cleaning Up Small Features:");
33 let cleanup_element = StructuringElement::rectangle(3, 3);
34 let cleaned = morphological_transform(&grid, MorphologyOp::Opening, &cleanup_element);
35
36 let cleaned_floors = cleaned.count(|t| t.is_floor());
37 println!(
38 " Removed {} small features ({} floors remaining)",
39 original_floors - cleaned_floors,
40 cleaned_floors
41 );
42
43 // Step 3: Analyze distances from walls
44 println!("\n3. Analyzing Distance from Walls:");
45 let distance_map = distance_field(&cleaned, DistanceMetric::Euclidean);
46
47 let mut max_distance = 0.0;
48 let mut center_points = Vec::new();
49
50 for y in 0..distance_map.height() {
51 for x in 0..distance_map.width() {
52 let dist = distance_map.get(x, y);
53 if dist != f32::INFINITY {
54 if dist > max_distance {
55 max_distance = dist;
56 center_points.clear();
57 center_points.push((x, y));
58 } else if (dist - max_distance).abs() < 0.1 {
59 center_points.push((x, y));
60 }
61 }
62 }
63 }
64
65 println!(" Maximum distance from walls: {:.1}", max_distance);
66 println!(" Found {} center points", center_points.len());
67
68 // Step 4: Create strategic pathfinding network
69 println!("\n4. Creating Strategic Pathfinding Network:");
70
71 // Use the most central points as strategic locations
72 let strategic_points: Vec<_> = center_points.into_iter().take(3).collect();
73 println!(" Strategic points: {:?}", strategic_points);
74
75 let constraints = PathfindingConstraints::default();
76 let strategic_dijkstra = dijkstra_map(&cleaned, &strategic_points, &constraints);
77
78 // Step 5: Generate AI movement flow field
79 println!("\n5. Generating AI Movement Flow Field:");
80 let flow_field = flow_field_from_dijkstra(&strategic_dijkstra);
81
82 // Analyze flow field coverage
83 let mut flow_coverage = 0;
84 for y in 0..flow_field.height() {
85 for x in 0..flow_field.width() {
86 let (dx, dy) = flow_field.get_direction(x, y);
87 if dx != 0 || dy != 0 {
88 flow_coverage += 1;
89 }
90 }
91 }
92
93 println!(" Flow field covers {} cells", flow_coverage);
94
95 // Step 6: Identify chokepoints using morphological analysis
96 println!("\n6. Identifying Chokepoints:");
97 let thin_element = StructuringElement::rectangle(2, 2);
98 let thinned = morphological_transform(&cleaned, MorphologyOp::Erosion, &thin_element);
99
100 let mut chokepoints = Vec::new();
101 for y in 1..cleaned.height() - 1 {
102 for x in 1..cleaned.width() - 1 {
103 if let (Some(original), Some(thinned_cell)) = (
104 cleaned.get(x as i32, y as i32),
105 thinned.get(x as i32, y as i32),
106 ) {
107 if original.is_floor() && !thinned_cell.is_floor() {
108 // This was a floor that got eroded - potential chokepoint
109 let neighbors = count_floor_neighbors(&cleaned, x, y);
110 if (2..=4).contains(&neighbors) {
111 chokepoints.push((x, y));
112 }
113 }
114 }
115 }
116 }
117
118 println!(" Found {} potential chokepoints", chokepoints.len());
119
120 // Step 7: Performance summary
121 println!("\n7. Performance Summary:");
122
123 let start = std::time::Instant::now();
124 let _ = morphological_transform(&grid, MorphologyOp::Opening, &cleanup_element);
125 println!(" Morphological cleanup: {:?}", start.elapsed());
126
127 let start = std::time::Instant::now();
128 let _ = distance_field(&cleaned, DistanceMetric::Euclidean);
129 println!(" Distance field calculation: {:?}", start.elapsed());
130
131 let start = std::time::Instant::now();
132 let _ = dijkstra_map(&cleaned, &strategic_points, &constraints);
133 println!(" Dijkstra map generation: {:?}", start.elapsed());
134
135 let start = std::time::Instant::now();
136 let _ = flow_field_from_dijkstra(&strategic_dijkstra);
137 println!(" Flow field generation: {:?}", start.elapsed());
138
139 // Step 8: Spatial analysis results
140 println!("\n8. Spatial Analysis Results:");
141 println!(" Original dungeon: {} floors", original_floors);
142 println!(" After cleanup: {} floors", cleaned_floors);
143 println!(" Strategic locations: {}", strategic_points.len());
144 println!(" Chokepoints identified: {}", chokepoints.len());
145 println!(
146 " Flow field coverage: {:.1}%",
147 100.0 * flow_coverage as f32 / cleaned_floors as f32
148 );
149
150 println!("\n✅ Spatial analysis workflow complete!");
151 println!(" The dungeon is now ready for:");
152 println!(" - AI pathfinding using flow fields");
153 println!(" - Strategic placement at center points");
154 println!(" - Tactical analysis of chokepoints");
155 println!(" - Distance-based gameplay mechanics");
156}Sourcepub fn height(&self) -> usize
pub fn height(&self) -> usize
Examples found in repository?
examples/advanced_pathfinding.rs (line 89)
88fn print_flow_field(flow: &terrain_forge::spatial::FlowField) {
89 for y in 0..flow.height() {
90 for x in 0..flow.width() {
91 let (dx, dy) = flow.get_direction(x, y);
92 let arrow = match (dx, dy) {
93 (0, 0) => "●", // Goal
94 (-1, -1) => "↖", // Northwest
95 (0, -1) => "↑", // North
96 (1, -1) => "↗", // Northeast
97 (-1, 0) => "←", // West
98 (1, 0) => "→", // East
99 (-1, 1) => "↙", // Southwest
100 (0, 1) => "↓", // South
101 (1, 1) => "↘", // Southeast
102 _ => "?", // Unknown
103 };
104 print!("{} ", arrow);
105 }
106 println!();
107 }
108}More examples
examples/spatial_workflow.rs (line 84)
14fn main() {
15 println!("=== Complete Spatial Analysis Workflow ===\n");
16
17 // Step 1: Generate base dungeon
18 println!("1. Generating Base Dungeon:");
19 let mut grid = Grid::new(40, 30);
20 let algo = algorithms::get("bsp").unwrap();
21 algo.generate(&mut grid, 42424);
22
23 let original_floors = grid.count(|t| t.is_floor());
24 println!(
25 " Generated {}x{} dungeon with {} floor tiles",
26 grid.width(),
27 grid.height(),
28 original_floors
29 );
30
31 // Step 2: Clean up with morphological operations
32 println!("\n2. Cleaning Up Small Features:");
33 let cleanup_element = StructuringElement::rectangle(3, 3);
34 let cleaned = morphological_transform(&grid, MorphologyOp::Opening, &cleanup_element);
35
36 let cleaned_floors = cleaned.count(|t| t.is_floor());
37 println!(
38 " Removed {} small features ({} floors remaining)",
39 original_floors - cleaned_floors,
40 cleaned_floors
41 );
42
43 // Step 3: Analyze distances from walls
44 println!("\n3. Analyzing Distance from Walls:");
45 let distance_map = distance_field(&cleaned, DistanceMetric::Euclidean);
46
47 let mut max_distance = 0.0;
48 let mut center_points = Vec::new();
49
50 for y in 0..distance_map.height() {
51 for x in 0..distance_map.width() {
52 let dist = distance_map.get(x, y);
53 if dist != f32::INFINITY {
54 if dist > max_distance {
55 max_distance = dist;
56 center_points.clear();
57 center_points.push((x, y));
58 } else if (dist - max_distance).abs() < 0.1 {
59 center_points.push((x, y));
60 }
61 }
62 }
63 }
64
65 println!(" Maximum distance from walls: {:.1}", max_distance);
66 println!(" Found {} center points", center_points.len());
67
68 // Step 4: Create strategic pathfinding network
69 println!("\n4. Creating Strategic Pathfinding Network:");
70
71 // Use the most central points as strategic locations
72 let strategic_points: Vec<_> = center_points.into_iter().take(3).collect();
73 println!(" Strategic points: {:?}", strategic_points);
74
75 let constraints = PathfindingConstraints::default();
76 let strategic_dijkstra = dijkstra_map(&cleaned, &strategic_points, &constraints);
77
78 // Step 5: Generate AI movement flow field
79 println!("\n5. Generating AI Movement Flow Field:");
80 let flow_field = flow_field_from_dijkstra(&strategic_dijkstra);
81
82 // Analyze flow field coverage
83 let mut flow_coverage = 0;
84 for y in 0..flow_field.height() {
85 for x in 0..flow_field.width() {
86 let (dx, dy) = flow_field.get_direction(x, y);
87 if dx != 0 || dy != 0 {
88 flow_coverage += 1;
89 }
90 }
91 }
92
93 println!(" Flow field covers {} cells", flow_coverage);
94
95 // Step 6: Identify chokepoints using morphological analysis
96 println!("\n6. Identifying Chokepoints:");
97 let thin_element = StructuringElement::rectangle(2, 2);
98 let thinned = morphological_transform(&cleaned, MorphologyOp::Erosion, &thin_element);
99
100 let mut chokepoints = Vec::new();
101 for y in 1..cleaned.height() - 1 {
102 for x in 1..cleaned.width() - 1 {
103 if let (Some(original), Some(thinned_cell)) = (
104 cleaned.get(x as i32, y as i32),
105 thinned.get(x as i32, y as i32),
106 ) {
107 if original.is_floor() && !thinned_cell.is_floor() {
108 // This was a floor that got eroded - potential chokepoint
109 let neighbors = count_floor_neighbors(&cleaned, x, y);
110 if (2..=4).contains(&neighbors) {
111 chokepoints.push((x, y));
112 }
113 }
114 }
115 }
116 }
117
118 println!(" Found {} potential chokepoints", chokepoints.len());
119
120 // Step 7: Performance summary
121 println!("\n7. Performance Summary:");
122
123 let start = std::time::Instant::now();
124 let _ = morphological_transform(&grid, MorphologyOp::Opening, &cleanup_element);
125 println!(" Morphological cleanup: {:?}", start.elapsed());
126
127 let start = std::time::Instant::now();
128 let _ = distance_field(&cleaned, DistanceMetric::Euclidean);
129 println!(" Distance field calculation: {:?}", start.elapsed());
130
131 let start = std::time::Instant::now();
132 let _ = dijkstra_map(&cleaned, &strategic_points, &constraints);
133 println!(" Dijkstra map generation: {:?}", start.elapsed());
134
135 let start = std::time::Instant::now();
136 let _ = flow_field_from_dijkstra(&strategic_dijkstra);
137 println!(" Flow field generation: {:?}", start.elapsed());
138
139 // Step 8: Spatial analysis results
140 println!("\n8. Spatial Analysis Results:");
141 println!(" Original dungeon: {} floors", original_floors);
142 println!(" After cleanup: {} floors", cleaned_floors);
143 println!(" Strategic locations: {}", strategic_points.len());
144 println!(" Chokepoints identified: {}", chokepoints.len());
145 println!(
146 " Flow field coverage: {:.1}%",
147 100.0 * flow_coverage as f32 / cleaned_floors as f32
148 );
149
150 println!("\n✅ Spatial analysis workflow complete!");
151 println!(" The dungeon is now ready for:");
152 println!(" - AI pathfinding using flow fields");
153 println!(" - Strategic placement at center points");
154 println!(" - Tactical analysis of chokepoints");
155 println!(" - Distance-based gameplay mechanics");
156}Trait Implementations§
Auto Trait Implementations§
impl Freeze for FlowField
impl RefUnwindSafe for FlowField
impl Send for FlowField
impl Sync for FlowField
impl Unpin for FlowField
impl UnwindSafe for FlowField
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more