@@ -6,34 +6,34 @@ number: 2
6
6
---
7
7
8
8
In this tutorial, we will create our first ` System ` in ` engo ` . We will also be using basic input methods such as the
9
- ** mouse and keyboard** .
9
+ ** mouse and keyboard** .
10
10
11
11
> #### Recap
12
12
> Remember what we did in [ the last tutorial] ( /tutorials/01-hello-world ) ? <br >
13
- > We created a ` Scene ` which renders a huge * City* icon onto the screen.
13
+ > We created a ` Scene ` which renders a huge * City* icon onto the screen.
14
14
15
15
> #### Final Code
16
- > The final code ** for tutorial 2** is available
17
- > [ here at GitHub] ( https://github.com/EngoEngine/TrafficManager/tree/02-first-system ) .
16
+ > The final code ** for tutorial 2** is available
17
+ > [ here at GitHub] ( https://github.com/EngoEngine/TrafficManager/tree/02-first-system ) .
18
18
19
19
### Step 1: The Concept
20
20
Before creating any ` System ` , it is often good to ask yourself: what is ** the purpose** (or task) of this ` System ` ? As
21
21
we are building a traffic-managing game which has multiple cities, it would make sense to create a system which creates
22
- new cities.
22
+ new cities.
23
23
24
24
To keep it simple for the sake of this tutorial, we shall create a ` System ` which creates a new * City* at the location
25
- of the cursor, whenever someone presses ** F1** .
25
+ of the cursor, whenever someone presses ** F1** .
26
26
27
27
### Step 2: Defining and Adding our System
28
28
29
29
#### Defining the System
30
30
31
- Before adding any functions, let's start by creating a dummy ` System ` and adding it to our game.
31
+ Before adding any functions, let's start by creating a dummy ` System ` and adding it to our game.
32
32
33
33
A ` System ` is anything that implements all these functions:
34
34
{% highlight go %}
35
35
// System is an interface which implements an ECS-System. A System
36
- // should iterate over its Entities on ` Update ` , in any way
36
+ // should iterate over its Entities on ` Update ` , in any way
37
37
// suitable for the current implementation.
38
38
type System interface {
39
39
// Update is ran every frame, with ` dt ` being the time
@@ -59,36 +59,36 @@ func (*CityBuildingSystem) Update(dt float32) {}
59
59
60
60
{% endhighlight %}
61
61
62
- Our ` CityBuildingSystem ` builds * Cities* on top of the cursor. This requires use of the keyboard and mouse. At first,
62
+ Our ` CityBuildingSystem ` builds * Cities* on top of the cursor. This requires use of the keyboard and mouse. At first,
63
63
we don't need to worry about entities, so we'll ignore the ` Remove ` function for now. We haven't added any entities,
64
64
so we can safely ignore removing them.
65
65
66
66
Let's keep ** code quality** in mind, and create a * separate package* for our Systems, called ` systems ` . This means we create
67
- the directory ` $GOPATH/github.com/EngoEngine/TrafficManager/systems ` . Within this, we create a new file, with the
67
+ the directory ` $GOPATH/github.com/EngoEngine/TrafficManager/systems ` . Within this, we create a new file, with the
68
68
exact contents of the ` CityBuildingSystem ` described above. However, we do add ` package systems ` to the top of the file.
69
69
70
70
#### Adding the System
71
71
Now that we've created the ` System ` , let's add it to our game. The usual way to add ` System ` s to a game, is by doing
72
72
it within the ` Setup ` function of the ` Scene ` you're going to use. Since we don't want this to interfere with the
73
- big * City* icon we created in the previous tutorial, we are not only going to add the ` System ` , but also remove
74
- the ` Entity ` we created in the last tutorial.
73
+ big * City* icon we created in the previous tutorial, we are not only going to add the ` System ` , but also remove
74
+ the ` Entity ` we created in the last tutorial.
75
75
76
76
{% highlight go %}
77
- // Setup is called before the main loop starts. It allows you
77
+ // Setup is called before the main loop starts. It allows you
78
78
// to add entities and systems to your Scene.
79
79
func (* myScene) Setup(world * ecs.World) {
80
80
common.SetBackground(color.White)
81
81
world.AddSystem(&common.RenderSystem{})
82
-
82
+
83
83
world.AddSystem(&systems.CityBuildingSystem{})
84
84
}
85
85
{% endhighlight %}
86
86
87
87
> ##### How do we know it works?
88
88
> At the moment, we can't be sure it actually works, right?
89
89
> Each system can optionally implement ` New(*ecs.World) ` , which will be called whenever the System is added to the
90
- > scene.
91
- >
90
+ > scene.
91
+ >
92
92
> Let's create a ` New ` function for our ` CityBuildingSystem ` like this:
93
93
> {% highlight go %}
94
94
// New is the initialisation of the System
@@ -98,12 +98,12 @@ func (*CityBuildingSystem) New(*ecs.World) {
98
98
{% endhighlight %}
99
99
100
100
> When we now run our game, we can see the white background, no * City* icon (because we removed it), and the
101
- > console outputs * "CityBuildingSystem was added to the Scene"* .
101
+ > console outputs * "CityBuildingSystem was added to the Scene"* .
102
102
103
103
### Step 3: Figuring out when ** F1** is pressed
104
- We want to spawn a * City* whenever someone presses ** F1** , so it makes sense that we want to know * when* this happens.
104
+ We want to spawn a * City* whenever someone presses ** F1** , so it makes sense that we want to know * when* this happens.
105
105
106
- First, we need to tell the Engo to listen for the F1 key press. We'll do this by using the
106
+ First, we need to tell the Engo to listen for the F1 key press. We'll do this by using the
107
107
` engo.Input.RegisterButton(name string, keys Key...) ` function. Multiple keys can be be assigned to one identifier.
108
108
109
109
Add the following line to the ` Setup ` function for your ` Scene ` .
@@ -112,7 +112,7 @@ func (*myScene) Setup(world *ecs.World) {
112
112
engo.Input.RegisterButton("AddCity", engo.KeyF1)
113
113
common.SetBackground(color.White)
114
114
world.AddSystem(&common.RenderSystem{})
115
-
115
+
116
116
world.AddSystem(&systems.CityBuildingSystem{})
117
117
}
118
118
{% endhighlight %}
@@ -121,14 +121,14 @@ We will check "did the gamer press **F1**", on every frame. The `Update` functio
121
121
gets called every frame by the ` World ` . So our checking-code needs to be written there. Engo has a neat feature which
122
122
allows you to lookup the state of keys, such as:
123
123
124
- * ` Down() ` : when the button is pressed; will be true as long as the user holds the button,
125
- * ` JustPressed() ` : when the button was just pressed; will be true for one frame, and cannot become true again unless the
126
- button was released first,
124
+ * ` Down() ` : when the button is pressed; will be true as long as the user holds the button,
125
+ * ` JustPressed() ` : when the button was just pressed; will be true for one frame, and cannot become true again unless the
126
+ button was released first,
127
127
* ` JustReleased() ` : same as ` JustPressed() ` , but with releasing the button instead of pressing it,
128
128
129
129
We don't want to risk placing two cities on top of each other in a very short time period (it's very likely that the
130
130
key is pressed longer than one frame, because a frame usually lasts between 16.6ms and 6.94ms). Therefore, we shall use
131
- the ` JustPressed() ` function.
131
+ the ` JustPressed() ` function.
132
132
133
133
{% highlight go %}
134
134
// Update is ran every frame, with ` dt ` being the time
@@ -142,12 +142,12 @@ func (*CityBuildingSystem) Update(dt float32) {
142
142
143
143
> #### How do we know it works?
144
144
> Let's run the game, and press ** F1** and find out! It should print "The gamer pressed ** F1** " just once, when we
145
- > hold the F1-key. It should print it twice when we double-tap it. It shouldn't print it as long as we don't press F1.
145
+ > hold the F1-key. It should print it twice when we double-tap it. It shouldn't print it as long as we don't press F1.
146
146
147
147
### Spawning a * City*
148
- Now we know * when* to spawn a * City* , we can actually write the code to do so.
148
+ Now we know * when* to spawn a * City* , we can actually write the code to do so.
149
149
150
- Remember the code we used for the large * City* -icon we removed?
150
+ Remember the code we used for the large * City* -icon we removed?
151
151
{% highlight go %}
152
152
city := City{BasicEntity: ecs.NewBasic()}
153
153
@@ -177,13 +177,13 @@ for _, system := range world.Systems() {
177
177
178
178
There are a few things we want to change, before using this in our ` CityBuildingSystem ` :
179
179
180
- * The size: 303 by 641 is a bit too big. Let's change this to 30 by 64.
180
+ * The size: 303 by 641 is a bit too big. Let's change this to 30 by 64.
181
181
* The location: we want to spawn it at the location of the cursor
182
182
* The ` world ` is unknown in the ` Update ` function, so we have to work around that
183
183
184
184
#### The size
185
- As stated, we can easily change the size, by changing the numbers. However, changing the values at the
186
- ` SpaceComponent ` isn't enough. The texture is still way too big; we can change this by setting the scale to ` 0.1 `
185
+ As stated, we can easily change the size, by changing the numbers. However, changing the values at the
186
+ ` SpaceComponent ` isn't enough. The texture is still way too big; we can change this by setting the scale to ` 0.1 `
187
187
instead of ` 1 ` :
188
188
189
189
{% highlight go %}
@@ -206,8 +206,8 @@ city.RenderComponent = common.NewRenderComponent(
206
206
207
207
#### The location
208
208
In order to spawn them at the correct location, we need to know where the cursor is. Our first guess might be to use
209
- the ` common. Mouse` struct which is available. However, this one returns the actual ` (X, Y) ` location relative to the
210
- screen size, not the in-game grid system. We have a special ` MouseSystem ` available for just that.
209
+ the ` engo.Input. Mouse` struct which is available. However, this one returns the actual ` (X, Y) ` location relative to the
210
+ screen size, not the in-game grid system. We have a special ` MouseSystem ` available for just that.
211
211
212
212
##### The ` MouseSystem `
213
213
The first thing you want to do, is add the ` MouseSystem ` to your ` Scene ` :
@@ -220,7 +220,7 @@ func (*myGame) Setup(world *ecs.World) {
220
220
221
221
world.AddSystem(&common.RenderSystem{})
222
222
world.AddSystem(&common.MouseSystem{})
223
-
223
+
224
224
world.AddSystem(&systems.CityBuildingSystem{})
225
225
}
226
226
{% endhighlight %}
@@ -229,8 +229,8 @@ func (*myGame) Setup(world *ecs.World) {
229
229
upon, are already initialized when we're initializing the ` CityBuildingSystem ` .*
230
230
231
231
The ` MouseSystem ` is mainly written to keep track of mouse-events for entities; you can check whether your ` Entity `
232
- has been hovered, clicked, dragged, etc. In order to use it, we therefore need an ` Entity ` which uses the ` MouseSystem ` .
233
- This one needs to hold a ` MouseComponent ` , at which the results/data will be saved.
232
+ has been hovered, clicked, dragged, etc. In order to use it, we therefore need an ` Entity ` which uses the ` MouseSystem ` .
233
+ This one needs to hold a ` MouseComponent ` , at which the results/data will be saved.
234
234
235
235
We first will update our ` CityBuildingSystem ` to contain the new ` Entity ` :
236
236
@@ -252,10 +252,10 @@ this `CityBuildingSystem`:
252
252
// New is the initialisation of the System
253
253
func (cb * CityBuildingSystem) New(w * ecs.World) {
254
254
fmt.Println("CityBuildingSystem was added to the Scene")
255
-
255
+
256
256
cb.mouseTracker.BasicEntity = ecs.NewBasic()
257
257
cb.mouseTracker.MouseComponent = common.MouseComponent{Track: true}
258
-
258
+
259
259
for _, system := range w.Systems() {
260
260
switch sys := system.(type) {
261
261
case *common.MouseSystem:
@@ -269,12 +269,12 @@ Note that we added the `Track: true` variable to the `MouseComponent`. This allo
269
269
mouse, regardless of where it is. If we were to leave it at ` false ` (the default), it would only contain anything
270
270
useful if the mouse was hovering the ` Entity ` . We are also giving two parameters ` nil ` within the ` Add ` function
271
271
of the ` MouseSystem ` . That is because (as described in the documentation of that ` Add ` function), one can also provide
272
- a ` SpaceComponent ` and ` RenderComponent ` , if one wants to know specifics about that particular entity (like
272
+ a ` SpaceComponent ` and ` RenderComponent ` , if one wants to know specifics about that particular entity (like
273
273
hover-events). This is not our intention at the moment, we just want to know about the position of the cursor. Therefore
274
- we can safely pass ` nil ` for those two parameters.
274
+ we can safely pass ` nil ` for those two parameters.
275
275
276
276
##### Getting information from the MouseSystem
277
- The ` MouseSystem ` updates the ` mouseTracker.MouseComponent ` every frame. Everything we need to know, is in there.
277
+ The ` MouseSystem ` updates the ` mouseTracker.MouseComponent ` every frame. Everything we need to know, is in there.
278
278
279
279
{% highlight go %}
280
280
// Update is ran every frame, with ` dt ` being the time
@@ -312,7 +312,7 @@ func (cb *CityBuildingSystem) Update(dt float32) {
312
312
{% endhighlight %}
313
313
314
314
But we still don't have a ` world ` reference within our ` Update ` function. We are given one inside our ` New ` function,
315
- so let's save that reference.
315
+ so let's save that reference.
316
316
317
317
{% highlight go %}
318
318
type CityBuildingSystem struct {
@@ -330,7 +330,7 @@ func (cb *CityBuildingSystem) New(w *ecs.World) {
330
330
}
331
331
{% endhighlight %}
332
332
333
- Now, we can reference it by saying ` cb.world ` , within our ` Update ` function.
333
+ Now, we can reference it by saying ` cb.world ` , within our ` Update ` function.
334
334
335
335
Now, if we were to run this whole project, and place a few cities using the ** F1** -key, we would get something like
336
336
this:
0 commit comments