Skip to content

Commit c6d8117

Browse files
authored
Merge pull request #113 from iolivia/olivia/hecs
Update to hecs
2 parents 5bb3398 + 844d5ae commit c6d8117

File tree

159 files changed

+3928
-5448
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

159 files changed

+3928
-5448
lines changed

books/en_US/src/SUMMARY.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
# Summary
22

33
- [Base game](./c01-00-intro.md)
4-
- [Project setup](./c01-01-setup.md)
5-
- [Entity Component System](./c01-02-ecs.md)
6-
- [Components and entities](./c01-03-entities-components.md)
7-
- [Rendering system](./c01-04-rendering.md)
4+
- [Project setup](./c01-01-setup.md)
5+
- [Entity Component System](./c01-02-ecs.md)
6+
- [Components and entities](./c01-03-entities-components.md)
7+
- [Rendering system](./c01-04-rendering.md)
88
- [Gameplay](./c02-00-intro.md)
9-
- [Map loading](./c02-01-map-loading.md)
10-
- [Moving the player](./c02-02-move-player.md)
11-
- [Pushing boxes](./c02-03-push-box.md)
12-
- [Modules](./c02-04-modules.md)
13-
- [Gameplay](./c02-05-gameplay.md)
9+
- [Map loading](./c02-01-map-loading.md)
10+
- [Moving the player](./c02-02-move-player.md)
11+
- [Pushing boxes](./c02-03-push-box.md)
12+
- [Modules](./c02-04-modules.md)
13+
- [Gameplay](./c02-05-gameplay.md)
1414
- [Advanced gameplay](./c03-00-intro.md)
15-
- [Coloured boxes](./c03-01-colours.md)
16-
- [Animations](./c03-02-animations.md)
17-
- [Sounds and events](./c03-03-sounds-events.md)
18-
- [Batch rendering](./c03-04-batch-rendering.md)
19-
15+
- [Coloured boxes](./c03-01-colours.md)
16+
- [Animations](./c03-02-animations.md)
17+
- [Events](./c03-03-events.md)
18+
- [Sounds](./c03-04-sounds.md)
19+
- [Batch rendering](./c03-05-batch-rendering.md)

books/en_US/src/c01-02-ecs.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,29 @@
33
In this section we will discuss Sokoban in more detail and how we will architect our game.
44

55
## Sokoban
6+
67
Here is how a Sokoban game looks like, if you are not familiar with the gameplay already. We have walls and boxes, and the goal is for the player to move the boxes onto their spots by pushing them around.
78

89
![Sokoban play](./images/sokoban.gif)
910

1011
## ECS
12+
1113
ECS (Entity Component System) is an architectural pattern for writing games which follows the composition over inheritance principle. We will be using ECS heavily in this project, much like most Rust games, so let's spend a bit of time familiarizing ourselves with the key concepts:
14+
1215
* **Components** - data-only structs which hold different characteristics of entities: some examples of components: Position, Renderable, Movement, etc. The key part here is that this is pure data, no behaviour.
1316
* **Entities** - entities are made up of multiple components, for example a player might be made up by Position, Renderable & Movement, while the floor might just be Position & Renderable since it doesn't move. Entities are pretty much just dummy containers of one or more components with a unique identifier.
1417
* **Systems** - systems use entities and components and contain behaviour and logic based on that data. For example, you could have a rendering system which just iterates through all entities which contain renderable components and draws all of them. The key here is that the components themselves don't contain any behaviour, instead they use a system to interpret the data and act.
1518

1619
If that doesn't make sense yet don't worry, we will discuss some practical examples in the next section applied to our Sokoban game.
1720

18-
1921
## Sokoban architecture
22+
2023
Based on what we know now about how a Sokoban game should work, we will need a few different types of "things": walls, a player, floors, boxes and box spots. These will be our *entities*.
2124

2225
Now we have to identify what these entities will be made of, or what *components* we need. Well first of all we will need to keep track of where everything is on the map, so we need some sort of position component. Secondly, some (but not all) entities can move. The player can move around, but boxes can also move if they get pushed by the player. Finally, we need a way to render each entity, so we need some renderable component.
2326

2427
Here is how our first idea of entities and components looks like:
28+
2529
1. **Player entity**: Position, Renderable, Movable
2630
1. **Wall entity**: Position, Renderable
2731
1. **Floor entity**: Position, Renderable
@@ -30,13 +34,14 @@ Here is how our first idea of entities and components looks like:
3034

3135
At first thinking in ECS might be difficult, so don't worry if you don't understand everything yet or if this doesn't seem familiar with the way you've done things in other languages.
3236

33-
## Specs
34-
Finally, let's bring in an ECS crate. There are a ton of them out there, but we will use [specs](https://specs.amethyst.rs/docs/tutorials/) for this book.
37+
## Hecs
38+
39+
Finally, let's bring in an ECS crate. There are a ton of them out there, but we will use [hecs](https://crates.io/crates/hecs) for this book.
3540

3641
```
3742
{{#include ../../../code/rust-sokoban-c01-03/Cargo.toml:9:11}}
3843
```
3944

4045
Next up, we'll start implementing entities and components!
4146

42-
> **_CODELINK:_** You can see the full code in this example [here](https://github.com/iolivia/rust-sokoban/tree/master/code/rust-sokoban-c01-03).
47+
> ***CODELINK:*** You can see the full code in this example [here](https://github.com/iolivia/rust-sokoban/tree/master/code/rust-sokoban-c01-03).

books/en_US/src/c01-03-entities-components.md

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,29 @@
11
# Components and entities
2+
23
In this section we will create our components, we'll see how to create entities and register everything to keep specs happy.
34

45
## Defining components
6+
57
Let's start by defining components. We previously discussed Position, Renderable and Movement - we'll skip movement for now. We will also need some components to identify each entity - for example we will need a Wall component so we can identify an entity as a wall by the fact that it has a wall component.
68

79
This should hopefully be straight-forward, the position components stores the x, y and z coordinates which will tell us where something is on the map, and the renderable component will receive a string path pointing to an image which we can render. All other components are [marker components](https://specs.amethyst.rs/docs/tutorials/11_advanced_component.html?highlight=marker#marker-components), with no data (yet).
810

9-
1011
```rust
11-
{{#include ../../../code/rust-sokoban-c01-03/src/main.rs:13:42}}
12+
{{#include ../../../code/rust-sokoban-c01-03/src/main.rs:components}}
1213
```
1314

1415
Among the familiar Rust code we've got some new syntax, we're using a powerful Rust feature called `Procedural Macros` which is used in `#[storage(VecStorage)]`. These type of macros are essentially functions that at compile time consume some syntax and produce some new syntax.
1516

1617
> **_MORE:_** Read more about procedural macros [here](https://doc.rust-lang.org/book/ch19-06-macros.html).
1718
18-
## Registering components
19-
In order for specs to be happy we have to tell it ahead of time what components we will be using. Let's create a function to register components into specs.
20-
21-
```rust
22-
{{#include ../../../code/rust-sokoban-c01-03/src/main.rs:61:69}}
23-
```
24-
2519
## Creating entities
20+
2621
An entity is simply a numeric identifier tied to a set of components. So the way we'll create entities is by simply specifying which components they contain.
2722

2823
This is how entity creation looks now.
2924

3025
```rust
31-
{{#include ../../../code/rust-sokoban-c01-03/src/main.rs:71:124}}
26+
{{#include ../../../code/rust-sokoban-c01-03/src/main.rs:entities}}
3227
```
3328

3429
## Assets
@@ -57,10 +52,11 @@ Let's add the images to our project. We'll add a `resources` folder which will h
5752
```
5853

5954
## World creation
55+
6056
Finally, let's tie everything together. We'll need to create a specs::World object, we'll add that to our Game struct and we will initialize it first thing in our main. Here is the full code, running now should render the same blank window, but we've made tremendous progress in actually setting up our game components and entities! Next up, we'll get to rendering so we'll finally see something on screen!
6157

6258
```rust
63-
{{#include ../../../code/rust-sokoban-c01-03/src/main.rs}}
59+
{{#include ../../../code/rust-sokoban-c01-03/src/main.rs:main}}
6460
```
6561

6662
Note that running now will report some warnings in the console about unused import(s) and/or fields, don't worry about these just yet as we'll fix them in the coming chapters.

books/en_US/src/c01-04-rendering.md

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,19 @@
33
It's time for our first system, the rendering system. This system will be responsible for drawing all our entities on the screen.
44

55
## Rendering system setup
6-
First we'll define the `RenderingSystem` struct, it will need access to the ggez context in order to actually render.
76

8-
```rust
9-
{{#include ../../../code/rust-sokoban-c01-04/src/main.rs:47:49}}
10-
```
11-
12-
We've got some new syntax here; `'a` is called a lifetime annotation. It's needed because the compiler can't see how long the reference in `RenderingSystem` is valid, meaning that we have to specify the lifetime annotation.
13-
14-
> **_MORE:_** Read more about lifetimes [here](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html).
15-
16-
Now let's implement the System trait for our Rendering system. This doesn't do anything yet, we're just setting up the scaffolding. The definition of SystemData means that we will have access to the storage of position and renderable components, and the fact that it's read storage means we only get immutable access, which is exactly what we need.
7+
First we'll start with a blank implementation, something like this:
178

189
```rust
19-
{{#include ../../../code/rust-sokoban-c01-04/src/main.rs:51:57}}
20-
// implementation here
21-
{{#include ../../../code/rust-sokoban-c01-04/src/main.rs:83:84}}
10+
pub fn run_rendering(world: &World, context: &mut Context) {
11+
// TODO add implementation
12+
}
2213
```
2314

2415
Finally let's run the rendering system in our draw loop. This means that every time the game updates we will render the latest state of all our entities.
2516

2617
```rust
27-
{{#include ../../../code/rust-sokoban-c01-04/src/main.rs:97:111}}
18+
{{#include ../../../code/rust-sokoban-c01-04/src/main.rs:handler}}
2819
```
2920

3021
Running the game now should compile, but it will probably not do anything yet, since we haven't filled in any of the implementation of the rendering system and also we haven't created any entities.
@@ -38,21 +29,22 @@ Running the game now should compile, but it will probably not do anything yet, s
3829
```
3930

4031
Here is the implementation of the rendering system. It does a few things:
32+
4133
* clear the screen (ensuring we don't keep any of the state rendered on the previous frame)
4234
* get all entities with a renderable component and sort them by z (we do this in order to ensure we can render things on top of each other, for example the player should be above the floor, otherwise we wouldn't be able to see them)
4335
* iterate through sorted entities and render each of them as an image
4436
* finally, present to the screen
4537

4638
```rust
47-
{{#include ../../../code/rust-sokoban-c01-04/src/main.rs:56:83}}
39+
{{#include ../../../code/rust-sokoban-c01-04/src/main.rs:rendering_system}}
4840
```
4941

5042
## Add some test entities
5143

5244
Let's create some test entities to make sure things are working correctly.
5345

5446
```rust
55-
{{#include ../../../code/rust-sokoban-c01-04/src/main.rs:179:204}}
47+
{{#include ../../../code/rust-sokoban-c01-04/src/main.rs:init}}
5648
```
5749

5850
Finally, let's put everything together and run. You should see something like this! This is super exciting, now we have a proper rendering system and we can actually see something on the screen for the first time. Next up, we're going to work on the gameplay so it can actually feel like a game!
@@ -63,7 +55,6 @@ Final code below.
6355

6456
> **_NOTE:_** Note that this is a very basic implementation of rendering and as the number of entities grow the performance will not be good enough. A more advanced implementation of rendering which uses batch rendering can be found in [Chapter 3 - Batch Rendering](/c03-04-batch-rendering.html).
6557
66-
6758
```rust
6859
{{#include ../../../code/rust-sokoban-c01-04/src/main.rs}}
6960
```

books/en_US/src/c02-01-map-loading.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
Last chapter we left off at creating some entities to test our rendering system, but now it's time to render a proper map. In this section we will create a text based map configuration which we will load.
44

55
## Map config
6+
67
First step, let's try to load a level based on a 2d map that looks like this.
78

89
```
9-
{{#include ../../../code/rust-sokoban-c02-01/src/main.rs:181:189}}
10+
{{#include ../../../code/rust-sokoban-c02-01/src/main.rs:map}}
1011
1112
where:
1213
. is an empty spot
@@ -17,16 +18,12 @@ S is a box spot
1718
N is nothing: used for the outer edges of the map
1819
```
1920

20-
Let's make a string for this, eventually we can load from a file but for simplicity let's go with a constant in the code for now.
21-
22-
```rust
23-
{{#include ../../../code/rust-sokoban-c02-01/src/main.rs:179:193}}
24-
```
21+
Eventually we can load from a file but for simplicity let's go with a constant in the code for now.
2522

2623
And here is the implementation of load map.
2724

2825
```rust
29-
{{#include ../../../code/rust-sokoban-c02-01/src/main.rs:195:234}}
26+
{{#include ../../../code/rust-sokoban-c02-01/src/main.rs:init}}
3027
```
3128

3229
The most interesting Rust concept here is probably the `match`. We are using the basic feature of pattern matching here, we are simply matching on the values of each token found in the map config, but we could do a lot of more advanced conditions or types of patterns.

0 commit comments

Comments
 (0)