Skip to content

Commit cdb3dc3

Browse files
committed
Merge remote-tracking branch 'origin/main' into offline
* origin/main: (30 commits) fix: use absolute URLs for assets chore: update my newsletter link fix: typo & clarity in source control feat: add kenney assets to Game Dev Resources chore(source-control): improve clarity chore: further thank vlevo chore(ch12): improve clarity & proper itch.io formatting chore: add DR Zine to Outro Update README.md 06-time-attack.md Update README.md 03-spit-fire.md 02-player-movement.md 01-hello-dragon.md I keep shooting 'cause I keep missing introduction.md grammar README.md tweaks tweaks tweaks tweaks ...
2 parents ccd258f + 4e2c7a0 commit cdb3dc3

17 files changed

+117
-104
lines changed

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Building Games with DragonRuby
22

3-
An open source book that walks you through how to build games with [DragonRuby Game Toolkit](https://dragonruby.org/toolkit/game).
3+
An open-source book that walks you through how to build games with [DragonRuby Game Toolkit](https://dragonruby.org/toolkit/game).
44

55
[Play the game you'll be building, right in the browser.](https://dragonridersunite.itch.io/dragonruby-book)
66

@@ -16,8 +16,8 @@ When the code is pushed to the `main` branch on GitHub, an action runs that depl
1616

1717
## Key Versions
1818

19-
- DragonRuby Game Toolkit: v3.24, v4.0
20-
- mdbook: v0.4.22
19+
- DragonRuby Game Toolkit: v3.x, v4.x
20+
- mdBook: v0.4.22
2121

2222
## Running Samples
2323

@@ -33,4 +33,12 @@ Clone this book repository into a DragonRuby GTK engine directory and run the sa
3333

3434
## Publishing
3535

36+
How to make a release:
37+
38+
1. Merge the `main` branch into `offline`
39+
2. Generate a new PDF via printing in Firefox, turning off the header and footer
40+
3. Generate an HTML version of the book and zip it up
41+
4. Create zips and upload them on itch.io
42+
5. Create tags and releases for the offline branch and the main branch
43+
3644
The 3D cover file is generated with https://diybookcovers.com/

src/01-hello-dragon.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ We'll start by rendering an image and some simple text on the screen. But first,
1010

1111
You're ready to work on your game. Let's get to it!
1212

13-
**ProTip:** don't delete the zip file! You can unzip it again when the times comes to start working on your next game. It's helpful to keep it around.
13+
**ProTip:** don't delete the zip file! You can unzip it again when the time comes to start working on your next game. It's helpful to keep it around.
1414

1515
## What's in the Engine Zip
1616

@@ -51,7 +51,7 @@ This isn't a game... yet! But it is doing three key things:
5151

5252
And you haven't even written any code yet. Not a bad starting place.
5353

54-
DRGTK handles the boring stuff when it comes to making games—dealing with low-level APIs like graphics, sound, and the game window. We can instead focus on creating our game instead of, for example, figuring out how to save data in a way that's compartible with Linux, Mac, Windows, Android, iOS, and web.
54+
DRGTK handles the boring stuff when it comes to making games—dealing with low-level APIs like graphics, sound, and the game window. We can instead focus on creating our game instead of, for example, figuring out how to save data in a way that's compatible with Linux, Mac, Windows, Android, iOS, and the web.
5555

5656
## An Overview of the Main Game File
5757

@@ -171,7 +171,7 @@ Let's take a detour down Screen Coordinates Road. The `x` and `y` values are coo
171171

172172
DRGTK games are made up of a window that's 1280x720 pixels in size. That's 1280 pixels wide and 720 pixels tall. The rectangle of the game screen contains 921600 pixels, that's those two numbers multiplied. Each of those pixels has a coordinate on the plane. It makes it easy to refer to a specific pixel by using its `x` and `y` position.
173173

174-
DRGTK starts 0, 0 in the lower left. So 1280, 720 would be the upper right. **Note:** this varies from most game engines, libraries, and tools, but it's intentional to make it easier to think about gravity and follows the geometric 2D plane that is taught in mathematics.
174+
DRGTK starts 0, 0 in the lower left. So 1280, 720 would be the upper right. **Note:** This varies from most game engines, libraries, and tools, but it's intentional to make it easier to think about gravity and follows the geometric 2D plane that is taught in mathematics.
175175

176176
It's important to keep coordinates in mind, as we'll be using them a lot when making our game. A major aspect of games is moving things around on the screen, which we do by changing their coordinates.
177177

@@ -215,7 +215,7 @@ The new code refactors (changes the implementation of the code without changing
215215

216216
The `"Hello #{friend}!"` code does what's called string interpolation. It takes whatever `friend` is, hopefully a name as a string, and inserts it. It's pretty similar to this code: `"Hello " + friend + "!"`, but quite a bit friendlier to use. The `#{}` tells Ruby to run any Ruby code within those curly braces.
217217

218-
Methods in Ruby return a value. Return values can then be used by the caller for whatever purposes are needed. In the example above, the return value is the string we built. Ruby returns the vaue of the last line of the method definition automatically. But you can explicitly return early with `return`, which can be useful if you want to end the execution of a method early.
218+
Methods in Ruby return a value. Return values can then be used by the caller for whatever purposes are needed. In the example above, the return value is the string we built. Ruby returns the value of the last line of the method definition automatically. But you can explicitly return early with `return`, which can be useful if you want to end the execution of a method early.
219219

220220
Go ahead and change the `greet` method to:
221221

src/02-player-movement.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ There are a couple of new things here:
2929
- `args.state`
3030
- `||=`
3131

32-
Let's start with `args.state`. It's basically a blob that can be anything you want it to be, a bit like Kirby. Feed it `player_x` and it keeps track of it. Whatever you feed the `args.state`, it'll be accessible in future ticks. Keeping track of game state across ticks is important! It's part of the game loop. If we don't know where the player last was, how can we calculate where they should move to? We need to keep track of it in someplace. `args.state` is a fine place to start.
32+
Let's start with `args.state`. It's basically a blob that can be anything you want it to be, a bit like Kirby. Feed it `player_x` and it keeps track of it. Whatever you feed the `args.state`, it'll be accessible in future ticks. Keeping track of the game state across ticks is important! It's part of the game loop. If we don't know where the player last was, how can we calculate where they should move to? We need to keep track of it in someplace. `args.state` is a fine place to start.
3333

3434
You can define anything on `args.state`, so it's up to you to use useful names. You could make `args.state.bleh` and set it to your favorite color, `args.state.bleh = "blue"` or your age, `args.state.age = 30`. Much like Kirby, `args.state` doesn't care what you feed it. It's just hungry for your data.
3535

@@ -53,7 +53,7 @@ That calls the `puts` method and passes our variable `name` to it as a parameter
5353

5454
Remember how tick is running once every 60 seconds? We don't want to always set `args.state.player_x` to `120`. We just want to set it to that initially and then we'll update that value when we press keys on our keyboard or buttons on our gamepad. We haven't done that yet, but that's what's next.
5555

56-
Wow! That was a lot of explanation for two measly lines of code. But I'm telling ya', they're two really important lines of code when it comes to game programming.
56+
Wow! That was a lot of explanation for two measly lines of code. But I'm telling ya, they're two really important lines of code when it comes to game programming.
5757

5858
Then, finally, we change the `x` and `y` value for the dragon sprite to be the value stored in `args.state` so that we can actually make use of that value instead of our hard-coded position before.
5959

@@ -96,7 +96,7 @@ elsif args.inputs.right
9696
end
9797
```
9898

99-
This section checks for horizontal movement. If the left input is pressed, reduce the player's x position by 10 pixels. `-=` means, subtract the value on the right from the value on the left. It's the same as `args.state.player_x = args.state.player_x - 10`, but it's much more concise. We increase `player_x` to move right, decrease it to move left.
99+
This section checks for horizontal movement. If the left input is pressed, reduce the player's x position by 10 pixels. `-=` means, subtract the value on the right from the value on the left. It's the same as `args.state.player_x = args.state.player_x - 10`, but it's much more concise. We increase `player_x` to move right and decrease it to move left.
100100

101101
`if` and `elsif` are conditional checks. The code only runs if the value is true (more specifically, truthy, but let's not worry about that yet).
102102

@@ -107,7 +107,7 @@ elsif args.inputs.down
107107
args.state.player_y -= 10
108108
end
109109
```
110-
Then we check for vertical movement. We add to `player_y` to move up, decrease it to move down.
110+
Then we check for vertical movement. We add to `player_y` to move up and decrease it to move down.
111111

112112
What if we wanted our dragon to move faster though? We could change those four instances of `10` to be `12` and see how that feels, sure. But that's annoying to update it all over. Let's make use of a variable! We'll call it `speed`:
113113

@@ -147,27 +147,27 @@ Our dragon won't leave the screen. Woot woot! We've got some serious code here!
147147

148148
We moved the width and height of the player into variables so that they're easier to reference and reuse. Boom. We need those to do some math on the boundaries too. There's a general programming idea out there known as Don't Repeat Yourself (DRY). As soon as you have a piece of code, especially a number, that represents a value and is used multiple times, put it in a variable. This makes its intent clear as to what it represents and makes it easier to change. Win-win.
149149

150-
Here's the good stuff. We check the boundary for the x axis:
150+
Here's the good stuff. We check the boundary for the x-axis:
151151

152152
``` ruby
153153
{{#include code/chapter_02/app/main.rb:20:26}}
154154
```
155155

156156
We check the right side of the screen: if the current player's x position plus their width is greater than `args.grid.w`, then we set the x position to the width of the screen (`args.grid.w`) minus the width of the sprite. For example, if we move the sprite so it has the x position of 1284, 4 pixels past the right edge of the screen, we override that change and set it to 1280 minus the player's width.
157157

158-
It's so important that this happens after checking for input. You don't want to change `args.state.player_x` after this check, otherwise the boundary won't be enforced. Order matters with the code we write within `tick`.
158+
It's so important that this happens after checking for input. You don't want to change `args.state.player_x` after this check, otherwise, the boundary won't be enforced. Order matters with the code we write within `tick`.
159159

160160
`args.grid.w` is the width of the screen. It's always 1280, but we don't want to have that magic number in our code. So we use `args.grid.w`.
161161

162-
Next we check the left side of the screen: if the player's x is less than 0, then we set it to zero. That's a bit similar to the right side, just simpler.
162+
Next, we check the left side of the screen: if the player's x is less than 0, then we set it to zero. That's a bit similar to the right side, just simpler.
163163

164164
Then we do the same thing for the top and bottom of the screen by checking the y position.
165165

166166
## Extra Credit
167167

168-
- When you move the dragon horizontally and vertically at the same time, the dragon moves twice as fast. How could you make it so the dragon moves at a uniform speed still when that happens?
169-
- Ruby has a method which ensures that a numeric value is between some bounds, find it and replace our bounds checking code with it.
168+
- When you move the dragon horizontally and vertically at the same time, the dragon moves twice as fast. How could you make it so the dragon still moves at a uniform speed when that happens?
169+
- Ruby has a method which ensures that a numeric value is between some bounds, find it and replace our bounds-checking code with it.
170170

171171
## What's Next
172172

173-
In the next chapter we'll make our dragon spit fireballs when we press a key or button. Watch out!
173+
In the next chapter, we'll make our dragon spit fireballs when we press a key or button. Watch out!

src/03-spit-fire.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Then where we check for the action input, push a fireball into the `arg.state.fi
5858

5959
All we have to do is render our fireballs by pushing them into the `args.outputs.labels` collection. DragonRuby is smart enough to know that if we push an array into any `args.outputs` collection it'll flatten it and display them correctly. Thanks, DragonRuby!
6060

61-
We've been using arrays to represent the fields for different data in our game like labels and sprites, but arrays have other uses too. Arrays are a great way to keep track of information we need in a list. The array we've created in the code above tracks our fireballs.
61+
We've been using arrays to represent the fields for different data in our game like labels and sprites, but arrays have other uses too. Arrays are a great way to keep track of information that we need in a list. The array we've created in the code above tracks our fireballs.
6262

6363
Play your game and see what happens! Fireballs everywhere. Wait! You're not impressed by those fireballs? I'd be pretty frightened if the word "fireball" was flying at me.
6464

@@ -70,7 +70,7 @@ Wait, where are you going? Why are you muttering "I didn't sign up to read no st
7070

7171
Guess what? We're sticking with ole "fireball" for now! It's silly and fun and I haven't found a good fireball sprite to use. We'll get there, we'll get there. But let's first make the fireballs move across the screen.
7272

73-
When we moved our player dragon, we took the x and y position and added or subtracted values in each `#tick` based upon if any directional input was pressed. Our fireballs will move regardless of any button pressed once they're extruded from our dragon's mouth. Because our game is simple and the dragon only faces to the right, all of the fireballs will move to the right. How do we go about that on our X-Y axis? We just increase the `x` position of the fireball each tick. Let's do that and see what happens:
73+
When we moved our player dragon, we took the x and y position and added or subtracted values in each `#tick` based on if any directional input was pressed. Our fireballs will move regardless of any button pressed once they're extruded from our dragon's mouth. Because our game is simple and the dragon only faces to the right, all of the fireballs will move to the right. How do we go about that on our X-Y axis? We just increase the `x` position of the fireball each tick. Let's do that and see what happens:
7474

7575
``` ruby
7676
{{#include code/chapter_03/04_moving_fireballs/app/main.rb:38:48}}
@@ -136,7 +136,9 @@ With that refactor done, let's display a sprite for our fireball and call it a c
136136

137137
Download the fireball sprite below and put it in `mygame/sprites/fireball.png`:
138138

139-
![fireball sprite](./code/chapter_03/06_sprite/sprites/fireball.png)
139+
![fireball sprite](https://book.dragonriders.community/code/chapter_03/06_sprite/sprites/fireball.png)
140+
141+
[Download sprite](https://book.dragonriders.community/code/chapter_03/06_sprite/sprites/fireball.png)
140142

141143
I just made that! It's not half bad, right?
142144

src/06-time-attack.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
We've _almost_ got a game. But we need some way for the game to end. A lot of game loops end with the player's character dying, where they respawn or start over again. Other game loops end when the player reaches the end of a level.
44

5-
For our simple game, let's add a 30 second timer that counts down. The objective of our game will be to see how many targets the player can hit in that time window. Let's call our game **Target Practice**. Every dragon needs some practice before they head out into battle, right?
5+
For our simple game, let's add a 30-second timer that counts down. The objective of our game will be to see how many targets the player can hit in that time window. Let's call our game **Target Practice**. Every dragon needs some practice before they head out into battle, right?
66

77
Adding a timer to our game introduces a few new concepts we'll build out in this chapter:
88

@@ -42,7 +42,7 @@ Way at the bottom of `#tick`, let's display a label with the time remaining:
4242

4343
We use the same pattern of creating a `labels` array, pushing in the player's score and the time, in ticks, remaining. In order to display the time remaining as seconds, we divide it by 60 and round. We do the opposite of what we did when we set the total time in ticks.
4444

45-
The `alignment_enum` lets us specify that we want the text to be right-aligned instead of the default left alignment. This let's us nicely position our timer in the upper right corner of the game.
45+
The `alignment_enum` lets us specify that we want the text to be right-aligned instead of the default left alignment. This lets us nicely position our timer in the upper right corner of the game.
4646

4747
![gameplay with Time Left reading 10 seconds](./img/c06-timer.jpg)
4848

src/07-high-score.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# High-Score
22

3-
Saving and loading data is a key piece of functionality when it comes to making games. We may want to keep track of all sorts of important data across play sessions. For _Target Practice_, let's keep it simple and track the high-score each time a new one is set.
3+
Saving and loading data is a key piece of functionality when it comes to making games. We may want to keep track of all sorts of important data across play sessions. For _Target Practice_, let's keep it simple and track the high score each time a new one is set.
44

55
## Load & Save Data
66

7-
When the game is over, let's display whether or not a new high-score was achieved. If it is higher than the previous, we'll save that new high-score. Otherwise, we'll display the high-score and encourage the player to try to beat it.
7+
When the game is over, let's display whether or not a new high score was achieved. If it is higher than the previous one, we'll save that new high score. Otherwise, we'll display the high score and encourage the player to try to beat it.
88

99
This will require two parts:
1010

11-
1. Saving the score when a new high-score is achieved
12-
2. Loading the previous high-score to compare the player's score to
11+
1. Saving the score when a new high score is achieved
12+
2. Loading the previous high score to compare the player's score to
1313

1414
DragonRuby GTK gives us two handy methods to do so:
1515

@@ -26,26 +26,26 @@ We'll be working exclusively in `#game_over_tick`:
2626

2727
We read the value from the `HIGH_SCORE_FILE`, which is `high-score.txt`. If the file doesn't exist, it'll be `0` because we call `#to_i` on the file reading process.
2828

29-
Then, if we haven't saved the high-score yet and the player's score is greater than the high-score, we save it in the file and set a value in `args.state.saved_high_score` so that we don't save it every single time `#game_over_tick` gets called each frame of the game.
29+
Then, if we haven't saved the high score yet and the player's score is greater than the high score, we save it in the file and set a value in `args.state.saved_high_score` so that we don't save it every single time `#game_over_tick` gets called each frame of the game.
3030

3131
``` ruby
3232
{{#include code/chapter_07/01_load_and_save_data/app/main.rb:73:87}}
3333
```
3434

35-
When we're constructing our `labels` to render, we add a condition that checks if we've got a new high-score. If we do, then we let the player know. Otherwise we display the current high-score for them to chase after.
35+
When we're constructing our `labels` to render, we add a condition that checks if we've got a new high score. If we do, then we let the player know. Otherwise, we display the current high score for them to chase after.
3636

37-
![game over screen showing a score of 1 and a high-score of 4](./img/c07-low-score.jpg)
37+
![game over screen showing a score of 1 and a high score of 4](./img/c07-low-score.jpg)
3838

39-
![game over screen showing a new high-score of 30](./img/c07-high-score.jpg)
39+
![game over screen showing a new high score of 30](./img/c07-high-score.jpg)
4040

4141
## Summary
4242

4343
We load and save data relating to how our player has done. While saving one value is likely to be a bit too trivial for most games, the core concepts are pretty similar. You'll write your data to a file, read that file, and then do whatever you need to with it.
4444

4545
## Extra Credit
4646

47-
- How would you save the date and time the high-score was achieved at?
48-
- Displaying one high-score is neat. But what if it showed the last 5 scores in addition to the highest score?
47+
- How would you save the date and time the high score was achieved at?
48+
- Displaying one high score is neat. But what if it showed the last 5 scores in addition to the highest score?
4949

5050
## What's Next
5151

0 commit comments

Comments
 (0)