???
This commit is contained in:
parent
5587a7dc35
commit
022fac5966
8 changed files with 150 additions and 13 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -791,6 +791,7 @@ version = "0.1.0"
|
||||||
name = "moonhare_game"
|
name = "moonhare_game"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"moonhare_ecs",
|
||||||
"moonhare_graphics",
|
"moonhare_graphics",
|
||||||
"moonhare_log",
|
"moonhare_log",
|
||||||
"moonhare_window",
|
"moonhare_window",
|
||||||
|
|
|
||||||
20
crates/moonhare_ecs/src/component.rs
Normal file
20
crates/moonhare_ecs/src/component.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use std::{collections::HashMap, marker::PhantomData};
|
||||||
|
|
||||||
|
use crate::generational_index::{self, GenerationalIndex};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Component<T: ComponentType> {
|
||||||
|
id: usize,
|
||||||
|
component_type: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ComponentType{}
|
||||||
|
|
||||||
|
impl<T: ComponentType> Component<T> {
|
||||||
|
pub fn new(id: usize, component_type: T) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
component_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
crates/moonhare_ecs/src/entity/mod.rs
Normal file
36
crates/moonhare_ecs/src/entity/mod.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
use crate::{entity, generational_index::{GenerationalIndex, GenerationalIndexAllocator}};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy, Hash)]
|
||||||
|
pub struct Entity(GenerationalIndex);
|
||||||
|
|
||||||
|
impl Entity {
|
||||||
|
pub fn index(&self) -> usize {
|
||||||
|
self.0.index()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generation(&self) -> u64 {
|
||||||
|
self.0.generation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct EntityAllocator(GenerationalIndexAllocator);
|
||||||
|
|
||||||
|
impl EntityAllocator {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
EntityAllocator(GenerationalIndexAllocator::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate(&mut self) -> Entity {
|
||||||
|
Entity(self.0.allocate())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deallocate(&mut self, entity: Entity) -> bool {
|
||||||
|
self.0.deallocate(entity.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_live(&self, entity: Entity) -> bool {
|
||||||
|
self.0.is_live(entity.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
|
||||||
pub struct GenerationalIndex {
|
pub struct GenerationalIndex {
|
||||||
index: usize,
|
index: usize,
|
||||||
generation: u64,
|
generation: u64,
|
||||||
|
|
@ -14,17 +14,22 @@ impl GenerationalIndex {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
struct AllocatorEntry {
|
struct AllocatorEntry {
|
||||||
is_live: bool,
|
is_live: bool,
|
||||||
generation: u64,
|
generation: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct GenerationalIndexAllocator {
|
pub struct GenerationalIndexAllocator {
|
||||||
entries: Vec<AllocatorEntry>,
|
entries: Vec<AllocatorEntry>,
|
||||||
free: Vec<usize>,
|
free: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenerationalIndexAllocator {
|
impl GenerationalIndexAllocator {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
pub fn allocate(&mut self) -> GenerationalIndex {
|
pub fn allocate(&mut self) -> GenerationalIndex {
|
||||||
match self.free.pop() {
|
match self.free.pop() {
|
||||||
Some(index) =>{
|
Some(index) =>{
|
||||||
|
|
@ -64,6 +69,10 @@ impl GenerationalIndexAllocator {
|
||||||
pub fn is_live(&self, index: GenerationalIndex) -> bool {
|
pub fn is_live(&self, index: GenerationalIndex) -> bool {
|
||||||
index.index() < self.entries.len() && self.entries[index.index()].generation == index.generation && self.entries[index.index()].is_live
|
index.index() < self.entries.len() && self.entries[index.index()].generation == index.generation && self.entries[index.index()].is_live
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn max_allocated_index(&self) -> usize {
|
||||||
|
self.entries.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ArrayEntry<T> {
|
struct ArrayEntry<T> {
|
||||||
|
|
@ -74,7 +83,15 @@ struct ArrayEntry<T> {
|
||||||
pub struct GenerationalIndexArray<T>(Vec<Option<ArrayEntry<T>>>);
|
pub struct GenerationalIndexArray<T>(Vec<Option<ArrayEntry<T>>>);
|
||||||
|
|
||||||
impl <T> GenerationalIndexArray<T> {
|
impl <T> GenerationalIndexArray<T> {
|
||||||
pub fn set(&mut self, index: GenerationalIndex, value: T) {
|
pub fn new() -> GenerationalIndexArray<T> {
|
||||||
|
GenerationalIndexArray(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.0.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, index: GenerationalIndex, value: T) {
|
||||||
while self.0.len() <= index.index() {
|
while self.0.len() <= index.index() {
|
||||||
self.0.push(None);
|
self.0.push(None);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,55 @@
|
||||||
|
use std::{collections::HashMap, path::{Component, Components}};
|
||||||
|
|
||||||
use anymap::AnyMap;
|
use anymap::AnyMap;
|
||||||
|
|
||||||
use crate::generational_index::{GenerationalIndex, GenerationalIndexAllocator, GenerationalIndexArray};
|
use crate::{entity::{Entity, EntityAllocator}, generational_index::{GenerationalIndex, GenerationalIndexAllocator, GenerationalIndexArray}};
|
||||||
|
|
||||||
pub mod generational_index;
|
pub mod generational_index;
|
||||||
|
pub mod world;
|
||||||
|
pub mod entity;
|
||||||
|
pub mod component;
|
||||||
|
|
||||||
pub type Entity = GenerationalIndex;
|
|
||||||
pub type EntityMap<T> = GenerationalIndexArray<T>;
|
|
||||||
|
|
||||||
// based on: https://kyren.github.io/2018/09/14/rustconf-talk.html
|
// based on: https://kyren.github.io/2018/09/14/rustconf-talk.html
|
||||||
|
|
||||||
|
/* Moonhare ECS Design
|
||||||
|
--------------------------------------
|
||||||
|
Game
|
||||||
|
🠟
|
||||||
|
Systems
|
||||||
|
(RenderSystem, PhysicsSystem, EnemyAISystem, EnemyCollisionSystem,...)
|
||||||
|
🠟
|
||||||
|
Entity
|
||||||
|
🠟
|
||||||
|
Components
|
||||||
|
--------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ECS {
|
pub struct ECS {
|
||||||
pub entity_allocator: GenerationalIndexAllocator,
|
entities: EntityAllocator,
|
||||||
pub entity_components: AnyMap,
|
components: AnyMap
|
||||||
pub resources: AnyMap
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ECS {
|
||||||
|
pub fn new() -> ECS {
|
||||||
|
ECS {
|
||||||
|
entities: EntityAllocator::new(),
|
||||||
|
components: AnyMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_entity(&mut self) -> Entity {
|
||||||
|
self.entities.allocate()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn entity_is_live(&self, entity: Entity) -> bool {
|
||||||
|
self.entities.is_live(entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_component() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
22
crates/moonhare_ecs/src/world.rs
Normal file
22
crates/moonhare_ecs/src/world.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
use std::fmt::Error;
|
||||||
|
|
||||||
|
use anymap::AnyMap;
|
||||||
|
|
||||||
|
use crate::{Entity, ECS};
|
||||||
|
|
||||||
|
/// stores Entitys, Components and resources
|
||||||
|
/// provides methods to search for specific Entitys
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct World {
|
||||||
|
ecs: ECS,
|
||||||
|
resources: AnyMap
|
||||||
|
}
|
||||||
|
|
||||||
|
impl World {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
ecs: ECS::new(),
|
||||||
|
resources: AnyMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ version.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
moonhare_ecs = { path = "../moonhare_ecs" }
|
||||||
moonhare_graphics = { path = "../moonhare_graphics" }
|
moonhare_graphics = { path = "../moonhare_graphics" }
|
||||||
moonhare_log = { path = "../moonhare_log" }
|
moonhare_log = { path = "../moonhare_log" }
|
||||||
moonhare_window = { path = "../moonhare_window" }
|
moonhare_window = { path = "../moonhare_window" }
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
|
||||||
|
use moonhare_ecs::world::World;
|
||||||
use moonhare_graphics::{color::Color, glium::{backend::Context, glutin::api::egl::context}};
|
use moonhare_graphics::{color::Color, glium::{backend::Context, glutin::api::egl::context}};
|
||||||
use moonhare_log::*;
|
use moonhare_log::*;
|
||||||
use moonhare_window::{platforms::glfw_window::GLFWWindow};
|
use moonhare_window::{platforms::glfw_window::GLFWWindow};
|
||||||
|
|
@ -10,19 +12,17 @@ pub mod basic;
|
||||||
/// Only one Game may exist per project
|
/// Only one Game may exist per project
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
|
pub world: World,
|
||||||
pub is_running: bool,
|
pub is_running: bool,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub context: moonhare_window::WindowRenderContext,
|
|
||||||
pub glfw_window: Option<moonhare_window::platforms::glfw_window::GLFWWindow>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Game {
|
impl Default for Game {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
world: World::new(),
|
||||||
is_running: true,
|
is_running: true,
|
||||||
name: default_game_name(),
|
name: default_game_name(),
|
||||||
context: moonhare_window::WindowRenderContext::OPENGLGLFW,
|
|
||||||
glfw_window: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue