nate_engine/
lib.rs

1//!
2//! Nate's Game Engine
3//! 
4//! # Creating Worlds
5//! ```
6//! #[world(singular=[canvas])]
7//! pub struct World {
8//!     position: (isize, isize),
9//!     velocity: (isize, isize),
10//!     health: usize,
11//!     health_changes: isize,
12//!     canvas: [[bool; 10]; 10],
13//! }
14//! ```
15//! 
16//! Creates a world named World, where every entity has the possibility of having a
17//! position, velocity, health, and health_change, but the world has a singular canvas.
18//! This will also generate getters and setters for each component as well as a default
19//! initializer for the world.
20//! 
21//! # Declaring Systems
22//! ```
23//! #[system(world=World, read=[velocity], write=[position], _read=[game_state], _write=[canvas])]
24//! pub fn some_system() {
25//!     ...
26//! }
27//! ```
28//! 
29//! The above example creates a system named some_system that operates on a world of type World.
30//! This system will operate on each entity that has a velocity and position component, such that
31//! the entity's positions are mutable and their velocities are immutable.  The world game_state is
32//! also readable and the world canvas is writable.
33//! 
34//! # Examples
35//! 
36//! One example of using the engine is accessible [here](examples/toy_example.rs).
37//! An even simpler example is as follows:
38//! ```
39//! use nate_engine::{Engine, Renderer, system, world};
40//! 
41//! // Game State Enum
42//! #[derive(Clone, Copy, Debug, PartialEq, Eq)]
43//! pub enum GameState {
44//!     Paused,
45//!     Playing,
46//!     Stopped,
47//! }
48//! 
49//! // World where every entity can have a position, velocity, health, and health_change and
50//! // canvas and game_state are singular components (i.e. components on the world)
51//! #[world(singular=[canvas, game_state])]
52//! pub struct ExampleWorld {
53//!     position: (isize, isize),
54//!     velocity: (isize, isize),
55//!     health: usize,
56//!     health_changes: isize,
57//! 
58//!     canvas: [[bool; 10]; 10],
59//!     game_state: GameState,
60//! }
61//! 
62//! // If the game is playing, update the position of every entity with both and position and
63//! // velocity based on the velocity.
64//! #[system(world=ExampleWorld, read=[velocity], write=[position], _read=[game_state])]
65//! pub fn position_update_system() {
66//!     if game_state == GameState::Playing {
67//!         *position = (position.0 + velocity.0, position.1 + velocity.1);
68//!     }
69//! }
70//! 
71//! // If the game is playing, update the health of every entity with a health change
72//! #[system(world=ExampleWorld, read=[health_changes], write=[health], _read=[game_state])]
73//! pub fn health_update_system() {
74//!     if game_state == GameState::Playing {
75//!         *health = health.saturating_add_signed(*health_changes);
76//!     }
77//! }
78//! 
79//! // Write the positions of entities to the canvas
80//! #[system(world=ExampleWorld, read=[position], _write=[canvas = [[false; 10]; 10])]
81//! pub fn canvas_update_system() {
82//!     let x = position.0.clamp(0.0, 9.0) as usize;
83//!     let y = position.1.clamp(0.0, 9.0) as usize;
84//!     canvas[y][x] = true;
85//! }
86//! 
87//! // Renderer that will print to the console
88//! pub struct ExampleRenderer {}
89//! 
90//! // Make sure the renderer is compatible with the game engine
91//! impl Renderer<ExampleWorld> for ExampleRenderer {
92//!     type Error = String;
93//! 
94//!     fn render(&mut self, world: Arc<RwLock<ExampleWorld>>) -> Result<(), Self::Error> {
95//!         let world = world.read.unwrap();
96//!         let canvas = (*world.canvas.read().unwrap()).unwrap();
97//!         
98//!         
99//!         for y in 0..10 {
100//!             for x in 0..10 {
101//!                 if canvas[y][x] {
102//!                     print!("X");
103//!                 } else {
104//!                     print!("_");
105//!                 }
106//!             }
107//!             print!("\n");
108//!         }
109//! 
110//!         // Handle Ctrl-c or Events to exit the loop
111//!         Ok(())
112//!     }
113//! }
114//! 
115//! // The Frame Rate for the Rendering Engine
116//! const FRAME_RATE: u32 = 30;
117//! // The Number of CPU workers to Compute Systems (1 will be reserved for the rendering engine)
118//! const WORKERS: usize = 2;
119//! 
120//! fn main() {
121//!     let world = ExampleWorld::new();
122//! 
123//!     {
124//!         let mut world = world.write().unwrap();
125//!         // Create Entities in the World
126//!         let entity_ids = world.add_entities(100);
127//! 
128//!         // Add Components to Entities
129//!         world.set_positions(&entity_ids, ...);
130//!         ...
131//! 
132//!         // Initialize Singular Components
133//!         world.set_game_state(GameState::Playing);
134//!         world.set_canvas([[false; 10]; 10]);
135//!     }
136//! 
137//!     let mut engine = Engine::new(
138//!         FRAME_RATE,
139//!         WORKERS,
140//!         world,
141//!         vec![
142//!             // position update system will run every 100ms
143//!             (position_update_system, 100_000),
144//!             // health update system will run every 1s
145//!             (health_update_system, 1_000_000),
146//!             // canvas update system will run every 100ms
147//!             (canvas_update_system, 100_000),
148//!         ],
149//!         Box::new(ExampleRenderer{}),
150//!     );
151//! 
152//!     engine.run();
153//! }
154//! ```
155//! 
156
157#[allow(rustdoc::invalid_rust_codeblocks)]
158
159/// Re-export of Nate's Engine Core
160pub use nate_engine_core::{Engine, Renderer};
161/// Re-export of Nate's Engine Macros
162pub use nate_engine_macros::{world, system};