mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
clean up path straightening + navmesh dev example improvement
This commit is contained in:
Binary file not shown.
+5
-41
@@ -1,12 +1,3 @@
|
|||||||
//! Example 01. Simple scene.
|
|
||||||
//!
|
|
||||||
//! Difficulty: Easy.
|
|
||||||
//!
|
|
||||||
//! This example shows how to create simple scene with animated model.
|
|
||||||
|
|
||||||
use fyrox::event_loop::EventLoop;
|
|
||||||
use fyrox::scene::camera::CameraBuilder;
|
|
||||||
use fyrox::scene::node::NodeTrait;
|
|
||||||
use fyrox::{
|
use fyrox::{
|
||||||
asset::manager::ResourceManager,
|
asset::manager::ResourceManager,
|
||||||
core::{
|
core::{
|
||||||
@@ -19,25 +10,21 @@ use fyrox::{
|
|||||||
dpi::LogicalPosition,
|
dpi::LogicalPosition,
|
||||||
engine::{executor::Executor, GraphicsContext, GraphicsContextParams},
|
engine::{executor::Executor, GraphicsContext, GraphicsContextParams},
|
||||||
event::{ElementState, Event, WindowEvent},
|
event::{ElementState, Event, WindowEvent},
|
||||||
gui::{
|
event_loop::EventLoop,
|
||||||
message::MessageDirection,
|
|
||||||
text::{TextBuilder, TextMessage},
|
|
||||||
widget::WidgetBuilder,
|
|
||||||
BuildContext, UiNode,
|
|
||||||
},
|
|
||||||
keyboard::KeyCode,
|
keyboard::KeyCode,
|
||||||
material::{Material, PropertyValue, SharedMaterial},
|
material::{Material, PropertyValue, SharedMaterial},
|
||||||
plugin::{Plugin, PluginConstructor, PluginContext},
|
plugin::{Plugin, PluginConstructor, PluginContext},
|
||||||
resource::model::{Model, ModelResourceExtension},
|
resource::model::{Model, ModelResourceExtension},
|
||||||
scene::{
|
scene::{
|
||||||
base::BaseBuilder,
|
base::BaseBuilder,
|
||||||
|
camera::CameraBuilder,
|
||||||
debug::Line,
|
debug::Line,
|
||||||
graph::physics::{Intersection, RayCastOptions},
|
graph::physics::{Intersection, RayCastOptions},
|
||||||
mesh::{
|
mesh::{
|
||||||
surface::{SurfaceBuilder, SurfaceData, SurfaceSharedData},
|
surface::{SurfaceBuilder, SurfaceData, SurfaceSharedData},
|
||||||
MeshBuilder,
|
MeshBuilder,
|
||||||
},
|
},
|
||||||
node::Node,
|
node::{Node, NodeTrait},
|
||||||
transform::TransformBuilder,
|
transform::TransformBuilder,
|
||||||
Scene,
|
Scene,
|
||||||
},
|
},
|
||||||
@@ -45,10 +32,6 @@ use fyrox::{
|
|||||||
};
|
};
|
||||||
use winit::keyboard::PhysicalKey;
|
use winit::keyboard::PhysicalKey;
|
||||||
|
|
||||||
fn create_ui(ctx: &mut BuildContext) -> Handle<UiNode> {
|
|
||||||
TextBuilder::new(WidgetBuilder::new()).build(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct GameScene {
|
struct GameScene {
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
agent: Handle<Node>,
|
agent: Handle<Node>,
|
||||||
@@ -77,7 +60,7 @@ async fn create_scene(resource_manager: ResourceManager) -> GameScene {
|
|||||||
));
|
));
|
||||||
|
|
||||||
resource_manager
|
resource_manager
|
||||||
.request::<Model, _>("examples/data/navmesh_scene2.rgs")
|
.request::<Model, _>("examples/data/navmesh_scene.rgs")
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.instantiate(&mut scene);
|
.instantiate(&mut scene);
|
||||||
@@ -143,7 +126,6 @@ struct Game {
|
|||||||
target_position: Vector3<f32>,
|
target_position: Vector3<f32>,
|
||||||
mouse_position: Vector2<f32>,
|
mouse_position: Vector2<f32>,
|
||||||
navmesh_agent: NavmeshAgent,
|
navmesh_agent: NavmeshAgent,
|
||||||
debug_text: Handle<UiNode>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Plugin for Game {
|
impl Plugin for Game {
|
||||||
@@ -180,15 +162,13 @@ impl Plugin for Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let navmesh_handle = scene.graph.find_by_name_from_root("Navmesh0").unwrap().0;
|
let navmesh_handle = scene.graph.find_by_name_from_root("Navmesh").unwrap().0;
|
||||||
let navmesh_node = scene.graph[navmesh_handle].as_navigational_mesh_mut();
|
let navmesh_node = scene.graph[navmesh_handle].as_navigational_mesh_mut();
|
||||||
navmesh_node.debug_draw(&mut scene.drawing_context);
|
navmesh_node.debug_draw(&mut scene.drawing_context);
|
||||||
let navmesh = navmesh_node.navmesh_mut();
|
let navmesh = navmesh_node.navmesh_mut();
|
||||||
|
|
||||||
let last = std::time::Instant::now();
|
|
||||||
self.navmesh_agent.set_target(self.target_position);
|
self.navmesh_agent.set_target(self.target_position);
|
||||||
let _ = self.navmesh_agent.update(context.dt, navmesh);
|
let _ = self.navmesh_agent.update(context.dt, navmesh);
|
||||||
let agent_time = std::time::Instant::now() - last;
|
|
||||||
|
|
||||||
scene.graph[self.agent]
|
scene.graph[self.agent]
|
||||||
.local_transform_mut()
|
.local_transform_mut()
|
||||||
@@ -201,19 +181,6 @@ impl Plugin for Game {
|
|||||||
color: Color::opaque(255, 0, 0),
|
color: Color::opaque(255, 0, 0),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let GraphicsContext::Initialized(ref graphics_context) = context.graphics_context {
|
|
||||||
let fps = graphics_context.renderer.get_statistics().frames_per_second;
|
|
||||||
let text = format!(
|
|
||||||
"Example 12 - Navigation Mesh\nFPS: {}\nAgent time: {:?}",
|
|
||||||
fps, agent_time
|
|
||||||
);
|
|
||||||
context.user_interface.send_message(TextMessage::text(
|
|
||||||
self.debug_text,
|
|
||||||
MessageDirection::ToWidget,
|
|
||||||
text,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_os_event(&mut self, event: &Event<()>, context: PluginContext) {
|
fn on_os_event(&mut self, event: &Event<()>, context: PluginContext) {
|
||||||
@@ -251,8 +218,6 @@ impl PluginConstructor for GameConstructor {
|
|||||||
_override_scene: Option<&str>,
|
_override_scene: Option<&str>,
|
||||||
context: PluginContext,
|
context: PluginContext,
|
||||||
) -> Box<dyn Plugin> {
|
) -> Box<dyn Plugin> {
|
||||||
let debug_text = create_ui(&mut context.user_interface.build_ctx());
|
|
||||||
|
|
||||||
// Create test scene.
|
// Create test scene.
|
||||||
let GameScene {
|
let GameScene {
|
||||||
scene,
|
scene,
|
||||||
@@ -280,7 +245,6 @@ impl PluginConstructor for GameConstructor {
|
|||||||
target_position: Default::default(),
|
target_position: Default::default(),
|
||||||
mouse_position: Default::default(),
|
mouse_position: Default::default(),
|
||||||
navmesh_agent,
|
navmesh_agent,
|
||||||
debug_text,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-52
@@ -121,7 +121,7 @@ struct Portal {
|
|||||||
left: usize,
|
left: usize,
|
||||||
right: usize,
|
right: usize,
|
||||||
}
|
}
|
||||||
fn signed_triangle_area_2d(a: Vector3<f32>, b: Vector3<f32>, c: Vector3<f32>) -> f32 {
|
fn triangle_area_2d(a: Vector3<f32>, b: Vector3<f32>, c: Vector3<f32>) -> f32 {
|
||||||
let abx = b[0] - a[0];
|
let abx = b[0] - a[0];
|
||||||
let abz = b[2] - a[2];
|
let abz = b[2] - a[2];
|
||||||
let acx = c[0] - a[0];
|
let acx = c[0] - a[0];
|
||||||
@@ -136,7 +136,7 @@ enum Winding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn winding(a: Vector3<f32>, b: Vector3<f32>, c: Vector3<f32>) -> Winding {
|
fn winding(a: Vector3<f32>, b: Vector3<f32>, c: Vector3<f32>) -> Winding {
|
||||||
if signed_triangle_area_2d(a, b, c) > 0.0 {
|
if triangle_area_2d(a, b, c) > 0.0 {
|
||||||
Winding::Clockwise
|
Winding::Clockwise
|
||||||
} else {
|
} else {
|
||||||
Winding::CounterClockwise
|
Winding::CounterClockwise
|
||||||
@@ -669,16 +669,14 @@ impl NavmeshAgent {
|
|||||||
self.path.push(src_position);
|
self.path.push(src_position);
|
||||||
|
|
||||||
if path_triangles.len() > 1 {
|
if path_triangles.len() > 1 {
|
||||||
let mut portal_apex = src_position;
|
let mut funnel_apex = src_position;
|
||||||
let mut portal_left = src_position;
|
let mut funnel_vertices = [funnel_apex; 2];
|
||||||
let mut portal_right = src_position;
|
let mut side_indices = [0; 2];
|
||||||
|
let side_signs = [1.0, -1.0];
|
||||||
let mut left_index = 0;
|
|
||||||
let mut right_index = 0;
|
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < path_triangles.len() {
|
while i < path_triangles.len() {
|
||||||
let (left, right) = if i + 1 < path_triangles.len() {
|
let portal_vertices = if i + 1 < path_triangles.len() {
|
||||||
let portal = navmesh
|
let portal = navmesh
|
||||||
.portal_between(path_triangles[i], path_triangles[i + 1])
|
.portal_between(path_triangles[i], path_triangles[i + 1])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -695,54 +693,44 @@ impl NavmeshAgent {
|
|||||||
right -= offset;
|
right -= offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
(left, right)
|
[left, right]
|
||||||
} else {
|
} else {
|
||||||
(dest_position, dest_position)
|
[dest_position, dest_position]
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update right vertex.
|
for current in 0..2 {
|
||||||
if signed_triangle_area_2d(portal_apex, portal_right, right) <= 0.0 {
|
let opposite = 1 - current;
|
||||||
if portal_apex == portal_right
|
let side_sign = side_signs[current];
|
||||||
|| signed_triangle_area_2d(portal_apex, portal_left, right) > 0.0
|
if side_sign
|
||||||
|
* triangle_area_2d(
|
||||||
|
funnel_apex,
|
||||||
|
funnel_vertices[current],
|
||||||
|
portal_vertices[current],
|
||||||
|
)
|
||||||
|
>= 0.0
|
||||||
{
|
{
|
||||||
// Tighten the funnel.
|
if funnel_apex == funnel_vertices[current]
|
||||||
portal_right = right;
|
|| side_sign
|
||||||
right_index = i;
|
* triangle_area_2d(
|
||||||
} else {
|
funnel_apex,
|
||||||
// Right over left, insert left to path and restart scan from portal left point.
|
funnel_vertices[opposite],
|
||||||
self.path.push(portal_left);
|
portal_vertices[current],
|
||||||
// Make current left the new apex.
|
)
|
||||||
portal_apex = portal_left;
|
< 0.0
|
||||||
// Reset portal
|
{
|
||||||
portal_left = portal_apex;
|
funnel_vertices[current] = portal_vertices[current];
|
||||||
portal_right = portal_apex;
|
side_indices[current] = i;
|
||||||
right_index = left_index;
|
} else {
|
||||||
// Restart scan
|
funnel_apex = funnel_vertices[opposite];
|
||||||
i = left_index + 1;
|
funnel_vertices = [funnel_apex; 2];
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update left vertex.
|
self.path.push(funnel_apex);
|
||||||
if signed_triangle_area_2d(portal_apex, portal_left, left) >= 0.0 {
|
|
||||||
if portal_apex == portal_left
|
i = side_indices[opposite];
|
||||||
|| signed_triangle_area_2d(portal_apex, portal_right, left) < 0.0
|
side_indices[current] = i;
|
||||||
{
|
|
||||||
// Tighten the funnel.
|
break;
|
||||||
portal_left = left;
|
}
|
||||||
left_index = i;
|
|
||||||
} else {
|
|
||||||
// Left over right, insert right to path and restart scan from portal right point.
|
|
||||||
self.path.push(portal_right);
|
|
||||||
// Make current right the new apex.
|
|
||||||
portal_apex = portal_right;
|
|
||||||
// Reset portal
|
|
||||||
portal_left = portal_apex;
|
|
||||||
portal_right = portal_apex;
|
|
||||||
left_index = right_index;
|
|
||||||
// Restart scan
|
|
||||||
i = right_index + 1;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user