simple ecs systems!
This commit is contained in:
parent
d51e783a50
commit
7c381672d9
|
@ -621,6 +621,12 @@ dependencies = [
|
||||||
"instant",
|
"instant",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.25"
|
version = "1.0.25"
|
||||||
|
@ -1003,6 +1009,7 @@ dependencies = [
|
||||||
"hecs",
|
"hecs",
|
||||||
"image",
|
"image",
|
||||||
"instant",
|
"instant",
|
||||||
|
"petgraph",
|
||||||
"specs",
|
"specs",
|
||||||
"tobj",
|
"tobj",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
@ -1387,6 +1394,16 @@ version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
|
|
|
@ -23,4 +23,5 @@ instant = "0.1"
|
||||||
async-trait = "0.1.65"
|
async-trait = "0.1.65"
|
||||||
specs = { version = "0.18.0", features = [ "derive" ] }
|
specs = { version = "0.18.0", features = [ "derive" ] }
|
||||||
hecs = "0.10.3"
|
hecs = "0.10.3"
|
||||||
glam = { version = "0.24.0", features = ["bytemuck"] }
|
glam = { version = "0.24.0", features = ["bytemuck"] }
|
||||||
|
petgraph = "0.6.3"
|
||||||
|
|
|
@ -15,14 +15,20 @@ impl Default for TransformComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Transform> for TransformComponent {
|
||||||
|
fn from(transform: Transform) -> Self {
|
||||||
|
Self {
|
||||||
|
transform
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TransformComponent {
|
impl TransformComponent {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_transform(transform: Transform) -> Self {
|
pub fn from_transform(transform: Transform) -> Self {
|
||||||
Self {
|
Self::from(transform)
|
||||||
transform
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use hecs::World;
|
use hecs::World;
|
||||||
|
use petgraph::{prelude::StableDiGraph, stable_graph::NodeIndex, visit::Topo};
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
pub mod components;
|
pub mod components;
|
||||||
|
@ -52,6 +53,89 @@ impl SimpleSystem for SystemFnExecutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SystemGraphNode {
|
||||||
|
name: String,
|
||||||
|
dependent_on: Vec<String>,
|
||||||
|
system: Box<dyn SimpleSystem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SystemGraphEdge {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SystemGraphExecutor {
|
||||||
|
graph: StableDiGraph<SystemGraphNode, SystemGraphEdge>,
|
||||||
|
node_refs: HashMap<String, NodeIndex>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SystemGraphExecutor {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
graph: StableDiGraph::new(),
|
||||||
|
node_refs: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SystemGraphExecutor {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a SimpleSystem to the SystemGraph.
|
||||||
|
///
|
||||||
|
/// WARN: Ensure that no cycles are created, this will cause the systems graph to not be sortable by topological sort,
|
||||||
|
/// and will cause a panic later on in the engine.
|
||||||
|
///
|
||||||
|
/// TODO: Return false if a cycle was created, making it impossible to know when to dispatch them. This will mean that the System would not of had been added.
|
||||||
|
pub fn add_system(&mut self, name: String, system: Box<dyn SimpleSystem>, dependencies: &[String]) -> bool {
|
||||||
|
let added_index =
|
||||||
|
self.graph.add_node(SystemGraphNode {
|
||||||
|
name: name.clone(),
|
||||||
|
dependent_on: dependencies.clone().to_vec(),
|
||||||
|
system,
|
||||||
|
});
|
||||||
|
|
||||||
|
// store name ref to the graph node
|
||||||
|
self.node_refs.insert(name, added_index);
|
||||||
|
|
||||||
|
// find the dependencies in node_refs and add edges directed towards the new node
|
||||||
|
for depend in dependencies.into_iter() {
|
||||||
|
let idx = self.node_refs
|
||||||
|
.get(depend)
|
||||||
|
.expect("Dependency not found!");
|
||||||
|
|
||||||
|
self.graph.add_edge(idx.clone(), added_index, SystemGraphEdge { });
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn execute_mut(&mut self, world: &mut World) {
|
||||||
|
let mut topo = Topo::new(&self.graph);
|
||||||
|
|
||||||
|
while let Some(nx) = topo.next(&self.graph) {
|
||||||
|
let node = self.graph.node_weight_mut(nx).unwrap();
|
||||||
|
|
||||||
|
match node.system.execute_mut(world) {
|
||||||
|
Ok(()) => {},
|
||||||
|
Err(e) => {
|
||||||
|
warn!("System execution of {} resulted in an error! '{}'.", node.name, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleSystem for SystemGraphExecutor {
|
||||||
|
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
|
||||||
|
SystemGraphExecutor::execute_mut(self, world);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
52
src/game.rs
52
src/game.rs
|
@ -13,7 +13,7 @@ use tracing_subscriber::{
|
||||||
|
|
||||||
use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode}, event_loop::{EventLoop, ControlFlow}};
|
use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode}, event_loop::{EventLoop, ControlFlow}};
|
||||||
|
|
||||||
use crate::{render::{renderer::{Renderer, BasicRenderer}, render_job::RenderJob}, input_event::InputEvent, ecs::{components::{mesh::MeshComponent, transform::TransformComponent}, SystemFnExecutor, SimpleSystem}};
|
use crate::{render::{renderer::{Renderer, BasicRenderer}, render_job::RenderJob}, input_event::InputEvent, ecs::{components::{mesh::MeshComponent, transform::TransformComponent}, SystemFnExecutor, SimpleSystem, SystemGraphExecutor}};
|
||||||
|
|
||||||
struct TickCounter {
|
struct TickCounter {
|
||||||
counter: u32,
|
counter: u32,
|
||||||
|
@ -69,24 +69,43 @@ impl TickCounter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct JiggleEntitiesSystem {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleSystem for JiggleEntitiesSystem {
|
||||||
|
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
|
||||||
|
for (_eid, (transform, )) in world.query_mut::<(&mut TransformComponent,)>() {
|
||||||
|
transform.transform.translate_vec3(glam::Vec3::new(0.0, 0.001, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct GameLoop {
|
struct GameLoop {
|
||||||
window: Arc<Window>,
|
window: Arc<Window>,
|
||||||
renderer: Box<dyn Renderer>,
|
renderer: Box<dyn Renderer>,
|
||||||
|
|
||||||
world: Arc<Mutex<World>>,
|
world: Arc<Mutex<World>>,
|
||||||
system_fn_executor: SystemFnExecutor,
|
/// higher priority systems
|
||||||
|
engine_systems: Vec<Box<dyn SimpleSystem>>,
|
||||||
|
systems: Vec<Box<dyn SimpleSystem>>,
|
||||||
fps_counter: TickCounter,
|
fps_counter: TickCounter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameLoop {
|
impl GameLoop {
|
||||||
pub async fn new(window: Arc<Window>, world: Arc<Mutex<World>>) -> GameLoop {
|
pub async fn new(window: Arc<Window>, world: Arc<Mutex<World>>, user_systems: Vec<Box<dyn SimpleSystem>>) -> GameLoop {
|
||||||
|
/* let mut graph_exec = SystemGraphExecutor::new();
|
||||||
|
graph_exec.add_system("jiggle_entities".to_string(), Box::new(JiggleEntitiesSystem {}), &[]); */
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
window: Arc::clone(&window),
|
window: Arc::clone(&window),
|
||||||
renderer: Box::new(BasicRenderer::create_with_window(window).await),
|
renderer: Box::new(BasicRenderer::create_with_window(window).await),
|
||||||
|
|
||||||
world,
|
world,
|
||||||
system_fn_executor: SystemFnExecutor::new(),
|
engine_systems: vec![],
|
||||||
|
systems: user_systems,
|
||||||
fps_counter: TickCounter::new(),
|
fps_counter: TickCounter::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,7 +120,14 @@ impl GameLoop {
|
||||||
|
|
||||||
async fn update(&mut self) {
|
async fn update(&mut self) {
|
||||||
let mut world = self.world.lock().await;
|
let mut world = self.world.lock().await;
|
||||||
self.system_fn_executor.execute_mut(&mut world).unwrap(); // always returns Ok(())
|
|
||||||
|
for esystem in self.engine_systems.iter_mut() {
|
||||||
|
esystem.execute_mut(&mut world).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
for system in self.systems.iter_mut() {
|
||||||
|
system.execute_mut(&mut world).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn input_update(&mut self, event: &InputEvent) -> Option<ControlFlow> {
|
async fn input_update(&mut self, event: &InputEvent) -> Option<ControlFlow> {
|
||||||
|
@ -208,12 +234,14 @@ impl GameLoop {
|
||||||
|
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
world: Option<Arc<Mutex<World>>>,
|
world: Option<Arc<Mutex<World>>>,
|
||||||
|
systems: Option<Vec<Box<dyn SimpleSystem>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Game {
|
impl Default for Game {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
world: None,
|
world: None,
|
||||||
|
systems: Some(vec![]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,13 +275,25 @@ impl Game {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_system<S>(&mut self, system: S) -> &mut Self
|
||||||
|
where
|
||||||
|
S: SimpleSystem + 'static
|
||||||
|
{
|
||||||
|
let systems = self.systems.as_mut().unwrap();
|
||||||
|
systems.push(Box::new(system));
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn run(&mut self) {
|
pub async fn run(&mut self) {
|
||||||
let world = self.world.take().expect("ECS World was never given to Game!");
|
let world = self.world.take().expect("ECS World was never given to Game!");
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap());
|
let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap());
|
||||||
|
|
||||||
let mut g_loop = GameLoop::new(Arc::clone(&window), world).await;
|
let systems = self.systems.take().unwrap();
|
||||||
|
|
||||||
|
let mut g_loop = GameLoop::new(Arc::clone(&window), world, systems).await;
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
g_loop.run_sync(event, control_flow);
|
g_loop.run_sync(event, control_flow);
|
||||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -11,10 +11,11 @@ use ecs::components::transform::TransformComponent;
|
||||||
use game::Game;
|
use game::Game;
|
||||||
use hecs::World;
|
use hecs::World;
|
||||||
|
|
||||||
|
use crate::ecs::SystemFnExecutor;
|
||||||
use crate::render::material::Material;
|
use crate::render::material::Material;
|
||||||
use crate::render::texture::Texture;
|
use crate::render::texture::Texture;
|
||||||
use crate::ecs::components::camera::CameraComponent;
|
use crate::ecs::components::camera::CameraComponent;
|
||||||
use crate::math::Angle;
|
use crate::math::{Angle, Transform};
|
||||||
//use specs::*;
|
//use specs::*;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -77,7 +78,7 @@ async fn main() {
|
||||||
shader_id: 0,
|
shader_id: 0,
|
||||||
texture: diffuse_texture
|
texture: diffuse_texture
|
||||||
}),
|
}),
|
||||||
TransformComponent::new(),
|
TransformComponent::from(Transform::from_translation(0.005, 0.0, 0.0)),
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut camera = CameraComponent::new();
|
let mut camera = CameraComponent::new();
|
||||||
|
@ -86,8 +87,21 @@ async fn main() {
|
||||||
camera.transform.rotate_z(Angle::Degrees(-90.0));
|
camera.transform.rotate_z(Angle::Degrees(-90.0));
|
||||||
world.spawn((camera,));
|
world.spawn((camera,));
|
||||||
|
|
||||||
|
let jiggle_system = |world: &mut World| -> anyhow::Result<()> {
|
||||||
|
for (_eid, (transform, )) in world.query_mut::<(&mut TransformComponent,)>() {
|
||||||
|
let t = &mut transform.transform;
|
||||||
|
t.translate_vec3(glam::Vec3::new(t.x() * -1.0, 0.001, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut fn_exec = SystemFnExecutor::new();
|
||||||
|
fn_exec.add_system("jiggle", Box::new(jiggle_system));
|
||||||
|
|
||||||
Game::initialize().await
|
Game::initialize().await
|
||||||
.with_world(world)
|
.with_world(world)
|
||||||
|
.with_system(fn_exec)
|
||||||
.run().await;
|
.run().await;
|
||||||
|
|
||||||
/* world.register::<Point2d>();
|
/* world.register::<Point2d>();
|
||||||
|
|
|
@ -65,6 +65,16 @@ impl Transform {
|
||||||
Self::from_matrix(matrix)
|
Self::from_matrix(matrix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_translation_vec(translation: Vec3) -> Self {
|
||||||
|
let matrix = glam::Mat4::from_scale_rotation_translation(Vec3::new(1.0, 1.0, 1.0), Quat::IDENTITY, translation);
|
||||||
|
|
||||||
|
Self::from_matrix(matrix)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_translation(x: f32, y: f32, z: f32) -> Self {
|
||||||
|
Self::from_translation_vec(Vec3::new(x, y, z))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn translate_vec3(&mut self, vec: Vec3) -> &mut Self {
|
pub fn translate_vec3(&mut self, vec: Vec3) -> &mut Self {
|
||||||
let translation = glam::Mat4::from_translation(vec);
|
let translation = glam::Mat4::from_translation(vec);
|
||||||
self.matrix *= translation;
|
self.matrix *= translation;
|
||||||
|
@ -163,4 +173,16 @@ impl Transform {
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn x(&self) -> f32 {
|
||||||
|
self.get_translation().x
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn y(&self) -> f32 {
|
||||||
|
self.get_translation().y
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn z(&self) -> f32 {
|
||||||
|
self.get_translation().z
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue