mirror of
https://github.com/DragonRidersUnite/book
synced 2025-02-05 20:45:52 +01:00
fix(ch02): revisions & clarity pass
This commit is contained in:
parent
62a17a63a8
commit
2121a4ea27
2 changed files with 28 additions and 24 deletions
|
@ -1,6 +1,6 @@
|
|||
# Player Movement
|
||||
|
||||
In the last chapter, we got a dragon sprite showing up on the screen and some text. Let's build upon that by making it so we can control the dragon with our keyboard and a gamepad. Because guess what? That dragon is now the main character of this game we're building. 🐉 Buckle up, it's dragon riding time.
|
||||
In the last chapter, we got a dragon sprite showing up on the screen and some text. Let's build upon that by making it so we can control the dragon with our keyboard and a gamepad. Because guess what? That dragon is now the main character of this game we're building. 🐉 Buckle up, it's dragon flying time.
|
||||
|
||||
Simplify `mygame/app/main.rb` to be just this for now:
|
||||
|
||||
|
@ -12,7 +12,7 @@ end
|
|||
|
||||
That displays our player dragon and nothing else. Excellent. Let's get this dragon moving!
|
||||
|
||||
In order to handle moving the player, we need to keep track of the position across the game loops. This lets us know where the player was last `tick`, check if they should move, and then update the position accordingly.
|
||||
In order to handle moving the player, we need to keep track of the position across the game loops. This lets us know where the player was last `tick`, check if they should move, and then update their position accordingly.
|
||||
|
||||
Update your `mygame/app/main.rb` to be this:
|
||||
|
||||
|
@ -47,7 +47,7 @@ You could then use that variable like this:
|
|||
puts name
|
||||
```
|
||||
|
||||
That calls a the `puts` method and passes our argument `name` to it. It prints whatever the value is out to the console. If you put that in your game code and press <kbd>~</kbd> to open the console, you'll see it print `"Francis"` a bunch.
|
||||
That calls the `puts` method and passes our variable `name` to it as a parameter. It prints whatever the value is out to the console. If you put that in your `tick` method and press <kbd>~</kbd> to open the console, you'll see it print `"Francis"` a bunch.
|
||||
|
||||
`||=` in English is "or equals". That code above, `args.state.player_x ||= 120` would be read as: assign the property `player_x` on `args.state` the numeric value of 120 unless it's already assigned a value.
|
||||
|
||||
|
@ -59,9 +59,9 @@ Then, finally, we change the `x` and `y` value for the dragon sprite to be the v
|
|||
|
||||
## Checking for Input
|
||||
|
||||
In `tick` we'll check to see if a given input is pressed. If it is, we'll change the sprite's x and y position accordingly.
|
||||
In `#tick` we'll check to see if a given input is pressed. If it is, we'll change the sprite's x and y position accordingly.
|
||||
|
||||
Our ole buddy `args` has a little something known as `args.inputs`. This lets us check... inputs! Isn't programming nice? Most of the time the words used in programming make sense. But some of the time, they really don't, and it's a gosh dang nightmare. But let's commit right here, right now to trying to name things in a way that's useful. Okay, you're committed. When you name a method `def thingy`, you'll remember this. And your ears will ring a little bit and your eyes will get just a little dry and you'll remember that you broke this commitment.
|
||||
Our ole buddy `args` has a little something known as `args.inputs`. This lets us check... inputs! Isn't programming nice? Most of the time the words used in programming make sense. But some of the time, they really don't, and it's a gosh dang nightmare. Let's commit right here, right now to trying to name things in a way that's useful. Okay, you're committed. When you name a method `def thingy`, you'll remember this. And your ears will ring a little bit and your eyes will get just a little dry and you'll remember that you broke your commitment.
|
||||
|
||||
Let's make use of `args.inputs`:
|
||||
|
||||
|
@ -166,7 +166,7 @@ Then we do the same thing for the top and bottom of the screen by checking the y
|
|||
## Extra Credit
|
||||
|
||||
- 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?
|
||||
- Ruby has an in-built method which ensures that a numeric value is between some bounds, find it and replace our bounds checking code with it.
|
||||
- Ruby has a method which ensures that a numeric value is between some bounds, find it and replace our bounds checking code with it.
|
||||
|
||||
## What's Next
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
# Spit Fire
|
||||
|
||||
Our next mission is to make our dragon spit fire because that's just what they do. We'll piece this whole thing into a game with win and lose states, a narrative, and intentional design soon enough. But let's keep focusing on simple mechanics and the code for right now.
|
||||
Our next mission is to make our dragon spit fire because that's just what they do. We'll piece this whole thing into a game soon enough. But let's keep focusing on simple mechanics and the code for right now.
|
||||
|
||||
## Fire on Input
|
||||
|
||||
In the last chapter, we used `args.inputs` to check for player input from the four main directions. If those inputs were being pressed, then we moved the dragon. Now let's check to see if the <kbd>Z</kbd> key is pressed to know when to have our dragon spit a fireball.
|
||||
In the last chapter, we used `args.inputs` to check for player input from the four main directions. If those inputs are pressed, then we move the dragon. Now let's check to see if the <kbd>Z</kbd> key is pressed to know when to have our dragon spit a fireball.
|
||||
|
||||
To check if a key was pressed, we can use `args.inputs.keyboard.key_down` and then whatever key we want to check. So in our case, we'll check `args.inputs.keyboard.key_down.z`. In our `#tick` method, right above where we render the dragon sprite, let's check for that input:
|
||||
|
||||
|
@ -12,21 +12,21 @@ To check if a key was pressed, we can use `args.inputs.keyboard.key_down` and th
|
|||
{{#include code/chapter_03/01_input/app/main.rb:36:40}}
|
||||
```
|
||||
|
||||
Using `puts` is a really helpful way to check that our game works as we expect it to. In this case, every tick where the Z key is pressed down, it prints the string "Z key pressed" to the console (open it with <kbd>~</kbd>, remember?). Run your game and press the Z key a bunch and then open your console.
|
||||
Using `puts` is a really helpful way to check that our game works as we expect it to. In this case, every tick where the <kbd>Z</kbd> key is pressed down, it prints the string "Z key pressed" to the console (open it with <kbd>~</kbd>, remember?). Run your game and press the <kbd>Z</kbd> key a bunch and then open your console.
|
||||
|
||||
<img alt="screenshot of DragonRuby console showing Z key pressed 6 times" src="./img/c03-console-puts.jpg" style="max-width: 420px; width: 100%;">
|
||||
|
||||
## Expanded Control Support
|
||||
|
||||
When making a game, it's important to support a variety of input configurations to make the game as accessible as possible. Sure, the keyboard arrow keys and the Z key are sensible defaults. But what if our player wants to use a gamepad controller? Or what if they would prefer to use WASD for movement? From the start of coding player input, let's support as many different inputs as reasonably possible.
|
||||
When making a game, it's important to support a variety of input configurations to make the game as accessible as possible. Sure, the keyboard arrow keys and the <kbd>Z</kbd> key are sensible defaults. But what if our player wants to use a gamepad controller? Or what if they would prefer to use WASD for movement? From the start of coding player input, let's support as many different inputs as reasonably possible.
|
||||
|
||||
In our case, we'll support three configurations:
|
||||
|
||||
- Arrow keys and Z
|
||||
- WASD and J
|
||||
- Arrow keys and <kbd>Z</kbd>
|
||||
- WASD and <kbd>J</kbd>
|
||||
- Gamepad
|
||||
|
||||
DragonRuby GTK is a big help in this department. Our code eerily that checks `args.inputs.up` (down/left/right) already checks for the arrow keys, WASD, and gamepad input. Slick! We don't have to change anything there. But let's go ahead and update our logic check for firing the fireball to check all of the possible inputs.
|
||||
DragonRuby GTK is a big help in this department. Our code earlier that checks `args.inputs.up` (down/left/right) already checks for the arrow keys, WASD, and gamepad input. Slick! We don't have to change anything there. But let's go ahead and update our logic check for firing the fireball to check all of the possible inputs.
|
||||
|
||||
``` ruby
|
||||
{{#include code/chapter_03/02_input_expanded/app/main.rb:36:40}}
|
||||
|
@ -34,11 +34,11 @@ DragonRuby GTK is a big help in this department. Our code eerily that checks `ar
|
|||
|
||||
We learned about `||=` earlier, and that's a combination of two separate operators in Ruby. `||` represents "or" and `=` says to assign a value. If the value on the left doesn't have a value, assign it the value on the right. We can make use of the "or" (`||`) operator independently of the assignment operator (`=`) to control the logic within our game.
|
||||
|
||||
The code above says: if the z key is down OR the j key is down OR the A button on the gamepad is pressed, then output the string to the console.
|
||||
The code above says: if the <kbd>Z</kbd> key is down OR the <kbd>J</kbd> key is down OR the A button on the gamepad is pressed, then output the string to the console.
|
||||
|
||||
You can combine `||` on one line (`if monday || tuesday || wednesday`), but it can be helpful to break long lines to make our code easier to read.
|
||||
|
||||
Outputting info to the console isn't that helpful for the player, but can you begin to imagine how we'll use that check to instead display a fireball.
|
||||
Outputting info to the console isn't that helpful for the player, but can you begin to imagine how we'll use that check to instead spit a fireball.
|
||||
|
||||
## Displaying Fireballs
|
||||
|
||||
|
@ -56,19 +56,21 @@ Then where we check for the action input, push a fireball into the `arg.state.fi
|
|||
{{#include code/chapter_03/03_displaying_fireballs/app/main.rb:38:45}}
|
||||
```
|
||||
|
||||
Then 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!
|
||||
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!
|
||||
|
||||
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.
|
||||
We use arrays to represent various data in our game like labels and sprites, but we can create our own arrays to keep track of the data in our game. Arrays are a great way to collect data that we then use throughout our game. In this case, we're maintaining a collection of fireballs.
|
||||
|
||||
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.
|
||||
|
||||
![screenshot of the game showing the word 'fireball' throughout with the dragon flying around](./img/c03-fireball-display.jpg)
|
||||
|
||||
Wait, where are you going? Why are you muttering "I didn't sign up to read no stinkin' book where you output the word fireball on the screen, I'm here for the real flame, the good stuff..."
|
||||
Wait, where are you going? Why are you muttering "I didn't sign up to read no stinkin' book where you output the word 'fireball' on the screen, I'm here for the real flame, the good stuff..."
|
||||
|
||||
## Moving Fireballs
|
||||
|
||||
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.
|
||||
|
||||
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 ole 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:
|
||||
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:
|
||||
|
||||
``` ruby
|
||||
{{#include code/chapter_03/04_moving_fireballs/app/main.rb:38:48}}
|
||||
|
@ -76,14 +78,14 @@ When we moved our player dragon, we took the x and y position and added or subtr
|
|||
|
||||
Right between where we add a new fireball to `args.state.fireballs` and we display them using `args.outputs.labels`, our new code does this:
|
||||
|
||||
1. Loop through the array of `args.state.fireballs`
|
||||
2. For each fireball, update the array value at the `0` index, which is the x position of the fireball, to be the dragon's speed plus 2 (because we want the fireball to move faster than the dragon).
|
||||
1. Loops through the array of `args.state.fireballs`
|
||||
2. For each fireball, updates the array value at the `0` index, which is the x position of the fireball, to be the dragon's speed plus 2 (because we want the fireball to move faster than the dragon).
|
||||
|
||||
Move your dragon around, spit some fire, and bask in the glory of a word moving so smoothly across the screen that it almost looks like a... fireball!
|
||||
|
||||
Try changing around `speed + 2` to make the fireballs move faster or slower and see how that feels. Adjusting speed values can really change the vibe of your game and is important in tuning it to feel just right.
|
||||
|
||||
There's a lot of important concepts in those three newly added lines of code. In Ruby, when there's an array of data, we can loop through **each** item and modify their properties. Games are composed of huge collections of things: enemies, fireballs, menu options, player inventory. Arrays (and just collections in general) aren't anything to be afraid of, and soon enough, you'll be thinking about your games in them.
|
||||
There are a lot of important concepts in those three newly added lines of code. In Ruby, when there's an array of data, we can loop through **each** item and modify their properties. Games are composed of huge collections of things: enemies, fireballs, menu options, player inventory. Arrays (and just collections in general) aren't anything to be afraid of, and soon enough, you'll be naturally thinking of your game data in terms of arrays.
|
||||
|
||||
Looping through an array of data in each `#tick` and then doing _something_ is the stuff games are made of! Here are some ways this can be applied in all sorts of games: enemy behavior, checking for collision, animating. As our game (and any game you make) gets more complex, looping through collections of data becomes more and more common.
|
||||
|
||||
|
@ -113,7 +115,7 @@ dragon = {
|
|||
|
||||
Values of a hash are then accessed by their keys, so `dragon.name` returns the string `"Francis"`, `dragon.size` returns the string `"medium"`, and `dragon.age` returns the number `541`. This is much more clear than having to remember the position of these values within an array.
|
||||
|
||||
Quick note: if you see a hash with key-value pairs that look like this: `{ :name => "Francis" }`, don't fret! That's just an older style in Ruby known as the hash rocket.
|
||||
Quick note: if you see a hash with key-value pairs that look like this: `{ :name => "Francis" }`, don't fret! That's just an another style in Ruby known as the hash rocket.
|
||||
|
||||
In general, differentiate between arrays and hashes like this: **hashes are used represent one piece of data with multiple properties** and **arrays are used to collect data (often times hashes) to keep track of and manipulate them**.
|
||||
|
||||
|
@ -136,7 +138,9 @@ Download the fireball sprite below and put it in `mygame/sprites/fireball.png`:
|
|||
|
||||
![fireball sprite](./code/chapter_03/06_sprite/sprites/fireball.png)
|
||||
|
||||
We'll change the hash we push into `args.state.fireballs` to be a sprite and adjust how we render that collection. Nothing too major. Here's the changes near the bottom of `#tick` that you'll need to make:
|
||||
I just made that! It's not half bad, right?
|
||||
|
||||
We'll change the hash we push into `args.state.fireballs` to be a sprite and adjust how we render that collection. Nothing too major. Here are the changes near the bottom of `#tick` that you'll need to make:
|
||||
|
||||
``` ruby
|
||||
{{#include code/chapter_03/06_sprite/app/main.rb:40:56}}
|
||||
|
|
Loading…
Add table
Reference in a new issue