Definition:
-
ECS for shorten is a paradigm that breaks your program into core components:
-
For example: There is entity Player has two components HP and Level. If the player gets enough experience the player will level up. That is called level_up system for Player. Or when the enemy hit the Player, the HP will be decreased. That is also a system.
Bevy ECS:
#[derive(Component)]
struct Position {
x: i32,
y: i32,
}
fn print_position_system(query: Query<&Position>)
{
for position in &query {
println!("x = {}, y = {}", position.x, position.y);
}
}
struct Entity(u64);
Practice
Example 1: Hello World and add system to your app
- We will make an app to print “Hello, World!!“.
- First we create the system
hello_world
:
fn hello_world() {
println!("Hello, World!!");
}
- Then add the system to
App
:
fn main()
{
App::new()
.add_systems(Update, hello_world)
.run()
}
- Update: the Schedule contains the systems that run once for per render frame.
add_systems
: this adds the system to the Update schedule.
Example 2: First component
- Create a Component Marker called Person:
#[derive(Component)]
struct Person;
-
This is Rust’s Unit Struct. For mainly purpose of marker.
-
Next, give the Person a component Name:
#[derive(Component)]
struct Name(String);
- To add our Person to the World we use a system called Startup system.
- Startup: The Schedule that contains system that:
- Runs only once.
- Runs before all other systems right after the app starts.
fn add_people(mut commands: Commands) {
command.spawn((Person, Name("Nguyen Nhat Minh".to_string())));
command.spawn((Person, Name("Nguyen Hoang Trung".to_string())));
}
-
This systems will add the persons named “Nguyen Nhat Minh” and “Nguyen Hoang Trung” to our World.
-
Finally, add the system to the schedule Startup in our main function:
fn main()
{
App::new()
.add_systems(Startup, add_people)
.run();
}
- To display the data in the World we create a system to query it:
fn show(query: Query<&Name, With(Person)>) {
for name in &query {
println!("name = {}", name.0);
}
}
-
Then finally add to the Update schedule:
fn main()
{
App::new()
.add_systems(Startup, add_people)
.add_systems(Update, show)
.run();
}
- If we want to change the Name of a Person, use mut Query:
fn change_name(mut query: Query<&mut Name, With<Person>>) {
for mut name in &mut query {
if name.0 == "Minh" {
name.0 = "MINH".to_string();
}
}
}
- Then add to our main like following code:
fn main()
{
App::new()
.add_systems(Startup, add_people)
.add_systems(Update, (show, change_name, show).chain())
.run();
}
chain()
will order the actions. First show the name then change the name then show it again.
ECS vs OOP
- In OOP, you have classes with data and functionality. Its objects will have the same data type but different values.
- In ECS, the data is combination of components. That means an entity can have any kinds of that combination. The entity itself is already used to identify that data. Thanks to this, u can have an Entity with component Transform or Color.
- A set of component of an entity is called entity’s Archetype.
- Entities with the same Archetype will be stored in the same contiguous arrays.
- Add/Remove component types mean that you are changing the archetype.