chore: import upstream snapshot with attribution
This commit is contained in:
+251
@@ -0,0 +1,251 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//! Example - 2D
|
||||
//!
|
||||
//! Difficulty: Easy.
|
||||
//!
|
||||
//! This example shows simple 2D scene with light sources.
|
||||
|
||||
use fyrox_impl::{
|
||||
asset::manager::ResourceManager,
|
||||
core::{
|
||||
algebra::{UnitQuaternion, Vector3},
|
||||
pool::Handle,
|
||||
sstorage::ImmutableString,
|
||||
},
|
||||
engine::{executor::Executor, GraphicsContextParams},
|
||||
event::{ElementState, Event, WindowEvent},
|
||||
event_loop::EventLoop,
|
||||
material::{Material, MaterialResource, PropertyValue},
|
||||
plugin::{Plugin, PluginConstructor, PluginContext},
|
||||
resource::texture::Texture,
|
||||
scene::{
|
||||
base::BaseBuilder,
|
||||
camera::{CameraBuilder, OrthographicProjection, Projection},
|
||||
dim2::rectangle::RectangleBuilder,
|
||||
light::{point::PointLightBuilder, spot::SpotLightBuilder, BaseLightBuilder},
|
||||
node::Node,
|
||||
transform::TransformBuilder,
|
||||
Scene,
|
||||
},
|
||||
};
|
||||
use winit::keyboard::{KeyCode, PhysicalKey};
|
||||
|
||||
struct SceneLoader {
|
||||
scene: Scene,
|
||||
camera: Handle<Node>,
|
||||
spot_light: Handle<Node>,
|
||||
}
|
||||
|
||||
impl SceneLoader {
|
||||
fn load_with(resource_manager: ResourceManager) -> Self {
|
||||
let mut scene = Scene::new();
|
||||
|
||||
// Create camera first.
|
||||
let camera = CameraBuilder::new(BaseBuilder::new())
|
||||
.with_projection(Projection::Orthographic(OrthographicProjection {
|
||||
z_near: -0.1,
|
||||
z_far: 16.0,
|
||||
vertical_size: 2.0,
|
||||
}))
|
||||
.build(&mut scene.graph);
|
||||
|
||||
let mut material = Material::standard_2d();
|
||||
material
|
||||
.set_property(
|
||||
&ImmutableString::new("diffuseTexture"),
|
||||
PropertyValue::Sampler {
|
||||
value: Some(resource_manager.request::<Texture>("examples/Crate.png")),
|
||||
fallback: Default::default(),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let material = MaterialResource::new_ok(Default::default(), material);
|
||||
|
||||
// Add some sprites.
|
||||
for y in 0..10 {
|
||||
for x in 0..10 {
|
||||
let sprite_size = 0.35;
|
||||
let spacing = 0.1;
|
||||
RectangleBuilder::new(
|
||||
BaseBuilder::new().with_local_transform(
|
||||
TransformBuilder::new()
|
||||
.with_local_position(Vector3::new(
|
||||
0.1 + x as f32 * (sprite_size + spacing),
|
||||
0.1 + y as f32 * (sprite_size + spacing),
|
||||
0.0, // Keep Z at zero.
|
||||
))
|
||||
.with_local_scale(Vector3::new(sprite_size, sprite_size, f32::EPSILON))
|
||||
.build(),
|
||||
),
|
||||
)
|
||||
.with_material(material.clone())
|
||||
.build(&mut scene.graph);
|
||||
}
|
||||
}
|
||||
|
||||
// Add some lights.
|
||||
PointLightBuilder::new(
|
||||
BaseLightBuilder::new(
|
||||
BaseBuilder::new().with_local_transform(
|
||||
TransformBuilder::new()
|
||||
.with_local_position(Vector3::new(2.5, 2.5, 0.0))
|
||||
.build(),
|
||||
),
|
||||
)
|
||||
.with_scatter_enabled(false),
|
||||
)
|
||||
.with_radius(1.0)
|
||||
.build(&mut scene.graph);
|
||||
|
||||
let spot_light = SpotLightBuilder::new(
|
||||
BaseLightBuilder::new(
|
||||
BaseBuilder::new().with_local_transform(
|
||||
TransformBuilder::new()
|
||||
.with_local_position(Vector3::new(3.0, 1.0, 0.0))
|
||||
.build(),
|
||||
),
|
||||
)
|
||||
.with_scatter_enabled(false),
|
||||
)
|
||||
.with_distance(2.0)
|
||||
.build(&mut scene.graph);
|
||||
|
||||
Self {
|
||||
scene,
|
||||
camera,
|
||||
spot_light,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct InputController {
|
||||
move_forward: bool,
|
||||
move_backward: bool,
|
||||
move_left: bool,
|
||||
move_right: bool,
|
||||
}
|
||||
|
||||
struct Game {
|
||||
input_controller: InputController,
|
||||
scene: Handle<Scene>,
|
||||
camera: Handle<Node>,
|
||||
spot_light: Handle<Node>,
|
||||
}
|
||||
|
||||
impl Plugin for Game {
|
||||
fn update(&mut self, context: &mut PluginContext) {
|
||||
let mut offset = Vector3::default();
|
||||
if self.input_controller.move_forward {
|
||||
offset.y += 1.0
|
||||
}
|
||||
if self.input_controller.move_backward {
|
||||
offset.y -= 1.0
|
||||
}
|
||||
if self.input_controller.move_left {
|
||||
offset.x += 1.0
|
||||
}
|
||||
if self.input_controller.move_right {
|
||||
offset.x -= 1.0
|
||||
}
|
||||
|
||||
let graph = &mut context.scenes[self.scene].graph;
|
||||
|
||||
if let Some(offset) = offset.try_normalize(f32::EPSILON) {
|
||||
graph[self.camera]
|
||||
.local_transform_mut()
|
||||
.offset(offset.scale(0.1));
|
||||
}
|
||||
|
||||
let local_transform = graph[self.spot_light].local_transform_mut();
|
||||
let new_rotation = **local_transform.rotation()
|
||||
* UnitQuaternion::from_euler_angles(0.0, 0.0, 1.0f32.to_radians());
|
||||
local_transform.set_rotation(new_rotation);
|
||||
}
|
||||
|
||||
fn on_os_event(&mut self, event: &Event<()>, _context: PluginContext) {
|
||||
if let Event::WindowEvent {
|
||||
event: WindowEvent::KeyboardInput { event: input, .. },
|
||||
..
|
||||
} = event
|
||||
{
|
||||
if let PhysicalKey::Code(code) = input.physical_key {
|
||||
match code {
|
||||
KeyCode::KeyW => {
|
||||
self.input_controller.move_forward = input.state == ElementState::Pressed
|
||||
}
|
||||
KeyCode::KeyS => {
|
||||
self.input_controller.move_backward = input.state == ElementState::Pressed
|
||||
}
|
||||
KeyCode::KeyA => {
|
||||
self.input_controller.move_left = input.state == ElementState::Pressed
|
||||
}
|
||||
KeyCode::KeyD => {
|
||||
self.input_controller.move_right = input.state == ElementState::Pressed
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct GameConstructor;
|
||||
|
||||
impl PluginConstructor for GameConstructor {
|
||||
fn create_instance(
|
||||
&self,
|
||||
_override_scene: Option<&str>,
|
||||
context: PluginContext,
|
||||
) -> Box<dyn Plugin> {
|
||||
// Create test scene.
|
||||
let loader = SceneLoader::load_with(context.resource_manager.clone());
|
||||
|
||||
Box::new(Game {
|
||||
// Create input controller - it will hold information about needed actions.
|
||||
input_controller: InputController {
|
||||
move_forward: false,
|
||||
move_backward: false,
|
||||
move_left: false,
|
||||
move_right: false,
|
||||
},
|
||||
// Add scene to engine - engine will take ownership over scene and will return
|
||||
// you a handle to scene which can be used later on to borrow it and do some
|
||||
// actions you need.
|
||||
scene: context.scenes.add(loader.scene),
|
||||
camera: loader.camera,
|
||||
spot_light: loader.spot_light,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut executor = Executor::from_params(
|
||||
EventLoop::new().unwrap(),
|
||||
GraphicsContextParams {
|
||||
window_attributes: Default::default(),
|
||||
vsync: true,
|
||||
msaa_sample_count: None,
|
||||
},
|
||||
);
|
||||
executor.add_plugin_constructor(GameConstructor);
|
||||
executor.run()
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,288 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use fyrox_graph::SceneGraph;
|
||||
use fyrox_impl::{
|
||||
asset::manager::ResourceManager,
|
||||
core::{
|
||||
algebra::{Matrix4, Point3, UnitQuaternion, Vector2, Vector3},
|
||||
arrayvec::ArrayVec,
|
||||
color::Color,
|
||||
pool::Handle,
|
||||
sstorage::ImmutableString,
|
||||
},
|
||||
dpi::LogicalPosition,
|
||||
engine::{executor::Executor, GraphicsContext, GraphicsContextParams},
|
||||
event::{ElementState, Event, WindowEvent},
|
||||
event_loop::EventLoop,
|
||||
keyboard::KeyCode,
|
||||
material::{Material, MaterialResource, PropertyValue},
|
||||
plugin::{Plugin, PluginConstructor, PluginContext},
|
||||
resource::model::{Model, ModelResourceExtension},
|
||||
scene::{
|
||||
base::BaseBuilder,
|
||||
camera::CameraBuilder,
|
||||
debug::Line,
|
||||
graph::physics::{Intersection, RayCastOptions},
|
||||
mesh::{
|
||||
surface::{SurfaceBuilder, SurfaceData, SurfaceSharedData},
|
||||
MeshBuilder,
|
||||
},
|
||||
node::{Node, NodeTrait},
|
||||
transform::TransformBuilder,
|
||||
Scene,
|
||||
},
|
||||
utils::navmesh::NavmeshAgent,
|
||||
};
|
||||
use winit::keyboard::PhysicalKey;
|
||||
|
||||
struct GameScene {
|
||||
scene: Scene,
|
||||
agent: Handle<Node>,
|
||||
cursor: Handle<Node>,
|
||||
camera: Handle<Node>,
|
||||
}
|
||||
|
||||
async fn create_scene(resource_manager: ResourceManager) -> GameScene {
|
||||
let mut scene = Scene::new();
|
||||
|
||||
// Camera is our eyes in the world - you won't see anything without it.
|
||||
let camera = CameraBuilder::new(
|
||||
BaseBuilder::new().with_local_transform(
|
||||
TransformBuilder::new()
|
||||
.with_local_position(Vector3::new(0.0, 5.0, 0.0))
|
||||
.build(),
|
||||
),
|
||||
)
|
||||
.build(&mut scene.graph);
|
||||
|
||||
scene.graph[camera]
|
||||
.local_transform_mut()
|
||||
.set_rotation(UnitQuaternion::from_axis_angle(
|
||||
&Vector3::x_axis(),
|
||||
90.0f32.to_radians(),
|
||||
));
|
||||
|
||||
resource_manager
|
||||
.request::<Model>("examples/data/navmesh_scene.rgs")
|
||||
.await
|
||||
.unwrap()
|
||||
.instantiate(&mut scene);
|
||||
|
||||
let mut cursor_material = Material::standard();
|
||||
cursor_material
|
||||
.set_property(
|
||||
&ImmutableString::new("diffuseColor"),
|
||||
PropertyValue::Color(Color::opaque(255, 0, 0)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cursor = MeshBuilder::new(BaseBuilder::new())
|
||||
.with_surfaces(vec![SurfaceBuilder::new(SurfaceSharedData::new(
|
||||
SurfaceData::make_sphere(10, 10, 0.1, &Matrix4::identity()),
|
||||
))
|
||||
.with_material(MaterialResource::new_ok(
|
||||
Default::default(),
|
||||
cursor_material,
|
||||
))
|
||||
.build()])
|
||||
.build(&mut scene.graph);
|
||||
|
||||
let mut agent_material = Material::standard();
|
||||
agent_material
|
||||
.set_property(
|
||||
&ImmutableString::new("diffuseColor"),
|
||||
PropertyValue::Color(Color::opaque(0, 200, 0)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let agent = MeshBuilder::new(
|
||||
BaseBuilder::new().with_local_transform(
|
||||
TransformBuilder::new()
|
||||
.with_local_scale(Vector3::new(1.0, 2.0, 1.0))
|
||||
.build(),
|
||||
),
|
||||
)
|
||||
.with_surfaces(vec![SurfaceBuilder::new(SurfaceSharedData::new(
|
||||
SurfaceData::make_sphere(10, 10, 0.2, &Matrix4::identity()),
|
||||
))
|
||||
.with_material(MaterialResource::new_ok(Default::default(), agent_material))
|
||||
.build()])
|
||||
.build(&mut scene.graph);
|
||||
|
||||
GameScene {
|
||||
scene,
|
||||
cursor,
|
||||
agent,
|
||||
camera,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct InputController {
|
||||
rotate_left: bool,
|
||||
rotate_right: bool,
|
||||
}
|
||||
|
||||
struct Game {
|
||||
input_controller: InputController,
|
||||
scene_handle: Handle<Scene>,
|
||||
agent: Handle<Node>,
|
||||
cursor: Handle<Node>,
|
||||
camera: Handle<Node>,
|
||||
target_position: Vector3<f32>,
|
||||
mouse_position: Vector2<f32>,
|
||||
navmesh_agent: NavmeshAgent,
|
||||
}
|
||||
|
||||
impl Plugin for Game {
|
||||
fn update(&mut self, context: &mut PluginContext) {
|
||||
// Use stored scene handle to borrow a mutable reference of scene in
|
||||
// engine.
|
||||
let scene = &mut context.scenes[self.scene_handle];
|
||||
|
||||
scene.drawing_context.clear_lines();
|
||||
|
||||
if let GraphicsContext::Initialized(ref graphics_context) = context.graphics_context {
|
||||
let ray = scene.graph[self.camera].as_camera().make_ray(
|
||||
self.mouse_position,
|
||||
graphics_context.renderer.get_frame_bounds(),
|
||||
);
|
||||
|
||||
let mut buffer = ArrayVec::<Intersection, 64>::new();
|
||||
scene.graph.physics.cast_ray(
|
||||
RayCastOptions {
|
||||
ray_origin: Point3::from(ray.origin),
|
||||
ray_direction: ray.dir,
|
||||
max_len: 9999.0,
|
||||
groups: Default::default(),
|
||||
sort_results: true,
|
||||
},
|
||||
&mut buffer,
|
||||
);
|
||||
|
||||
if let Some(first) = buffer.first() {
|
||||
self.target_position = first.position.coords;
|
||||
scene.graph[self.cursor]
|
||||
.local_transform_mut()
|
||||
.set_position(self.target_position);
|
||||
}
|
||||
}
|
||||
|
||||
let navmesh_handle = scene.graph.find_by_name_from_root("Navmesh").unwrap().0;
|
||||
let navmesh_node = scene.graph[navmesh_handle].as_navigational_mesh_mut();
|
||||
navmesh_node.debug_draw(&mut scene.drawing_context);
|
||||
let navmesh = navmesh_node.navmesh_ref();
|
||||
|
||||
self.navmesh_agent.set_target(self.target_position);
|
||||
let _ = self.navmesh_agent.update(context.dt, &navmesh);
|
||||
drop(navmesh);
|
||||
|
||||
scene.graph[self.agent]
|
||||
.local_transform_mut()
|
||||
.set_position(self.navmesh_agent.position());
|
||||
|
||||
for pts in self.navmesh_agent.path().windows(2) {
|
||||
scene.drawing_context.add_line(Line {
|
||||
begin: pts[0],
|
||||
end: pts[1],
|
||||
color: Color::opaque(255, 0, 0),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn on_os_event(&mut self, event: &Event<()>, context: PluginContext) {
|
||||
if let Event::WindowEvent { event, .. } = event {
|
||||
match event {
|
||||
WindowEvent::KeyboardInput { event: input, .. } => match input.physical_key {
|
||||
PhysicalKey::Code(KeyCode::KeyA) => {
|
||||
self.input_controller.rotate_left = input.state == ElementState::Pressed
|
||||
}
|
||||
PhysicalKey::Code(KeyCode::KeyD) => {
|
||||
self.input_controller.rotate_right = input.state == ElementState::Pressed
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
if let GraphicsContext::Initialized(ref graphics_context) =
|
||||
context.graphics_context
|
||||
{
|
||||
let p: LogicalPosition<f32> =
|
||||
position.to_logical(graphics_context.window.scale_factor());
|
||||
self.mouse_position = Vector2::new(p.x, p.y);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct GameConstructor;
|
||||
|
||||
impl PluginConstructor for GameConstructor {
|
||||
fn create_instance(
|
||||
&self,
|
||||
_override_scene: Option<&str>,
|
||||
context: PluginContext,
|
||||
) -> Box<dyn Plugin> {
|
||||
// Create test scene.
|
||||
let GameScene {
|
||||
scene,
|
||||
agent,
|
||||
cursor,
|
||||
camera,
|
||||
} = fyrox::core::futures::executor::block_on(create_scene(
|
||||
context.resource_manager.clone(),
|
||||
));
|
||||
|
||||
// Add scene to engine - engine will take ownership over scene and will return
|
||||
// you a handle to scene which can be used later on to borrow it and do some
|
||||
// actions you need.
|
||||
let scene_handle = context.scenes.add(scene);
|
||||
|
||||
let mut navmesh_agent = NavmeshAgent::new();
|
||||
navmesh_agent.set_speed(0.75);
|
||||
|
||||
Box::new(Game {
|
||||
input_controller: Default::default(),
|
||||
scene_handle,
|
||||
agent,
|
||||
cursor,
|
||||
camera,
|
||||
target_position: Default::default(),
|
||||
mouse_position: Default::default(),
|
||||
navmesh_agent,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut executor = Executor::from_params(
|
||||
EventLoop::new().unwrap(),
|
||||
GraphicsContextParams {
|
||||
window_attributes: Default::default(),
|
||||
vsync: true,
|
||||
msaa_sample_count: None,
|
||||
},
|
||||
);
|
||||
executor.add_plugin_constructor(GameConstructor);
|
||||
executor.run()
|
||||
}
|
||||
Reference in New Issue
Block a user