simple ecs systems!
This commit is contained in:
parent
d51e783a50
commit
7c381672d9
|
@ -621,6 +621,12 @@ dependencies = [
|
|||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.25"
|
||||
|
@ -1003,6 +1009,7 @@ dependencies = [
|
|||
"hecs",
|
||||
"image",
|
||||
"instant",
|
||||
"petgraph",
|
||||
"specs",
|
||||
"tobj",
|
||||
"tracing",
|
||||
|
@ -1387,6 +1394,16 @@ version = "2.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
|
|
|
@ -24,3 +24,4 @@ async-trait = "0.1.65"
|
|||
specs = { version = "0.18.0", features = [ "derive" ] }
|
||||
hecs = "0.10.3"
|
||||
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 {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn from_transform(transform: Transform) -> Self {
|
||||
Self {
|
||||
transform
|
||||
}
|
||||
Self::from(transform)
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
|||
|
||||
use async_trait::async_trait;
|
||||
use hecs::World;
|
||||
use petgraph::{prelude::StableDiGraph, stable_graph::NodeIndex, visit::Topo};
|
||||
use tracing::warn;
|
||||
|
||||
pub mod components;
|
||||
|
@ -55,3 +56,86 @@ 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(())
|
||||
}
|
||||
}
|
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 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 {
|
||||
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 {
|
||||
window: Arc<Window>,
|
||||
renderer: Box<dyn Renderer>,
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
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 {
|
||||
window: Arc::clone(&window),
|
||||
renderer: Box::new(BasicRenderer::create_with_window(window).await),
|
||||
|
||||
world,
|
||||
system_fn_executor: SystemFnExecutor::new(),
|
||||
engine_systems: vec![],
|
||||
systems: user_systems,
|
||||
fps_counter: TickCounter::new(),
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +120,14 @@ impl GameLoop {
|
|||
|
||||
async fn update(&mut self) {
|
||||
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> {
|
||||
|
@ -208,12 +234,14 @@ impl GameLoop {
|
|||
|
||||
pub struct Game {
|
||||
world: Option<Arc<Mutex<World>>>,
|
||||
systems: Option<Vec<Box<dyn SimpleSystem>>>
|
||||
}
|
||||
|
||||
impl Default for Game {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
world: None,
|
||||
systems: Some(vec![]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -247,13 +275,25 @@ impl Game {
|
|||
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) {
|
||||
let world = self.world.take().expect("ECS World was never given to Game!");
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
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| {
|
||||
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 hecs::World;
|
||||
|
||||
use crate::ecs::SystemFnExecutor;
|
||||
use crate::render::material::Material;
|
||||
use crate::render::texture::Texture;
|
||||
use crate::ecs::components::camera::CameraComponent;
|
||||
use crate::math::Angle;
|
||||
use crate::math::{Angle, Transform};
|
||||
//use specs::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -77,7 +78,7 @@ async fn main() {
|
|||
shader_id: 0,
|
||||
texture: diffuse_texture
|
||||
}),
|
||||
TransformComponent::new(),
|
||||
TransformComponent::from(Transform::from_translation(0.005, 0.0, 0.0)),
|
||||
));
|
||||
|
||||
let mut camera = CameraComponent::new();
|
||||
|
@ -86,8 +87,21 @@ async fn main() {
|
|||
camera.transform.rotate_z(Angle::Degrees(-90.0));
|
||||
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
|
||||
.with_world(world)
|
||||
.with_system(fn_exec)
|
||||
.run().await;
|
||||
|
||||
/* world.register::<Point2d>();
|
||||
|
|
|
@ -65,6 +65,16 @@ impl Transform {
|
|||
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 {
|
||||
let translation = glam::Mat4::from_translation(vec);
|
||||
self.matrix *= translation;
|
||||
|
@ -163,4 +173,16 @@ impl Transform {
|
|||
|
||||
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