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};