Skip to content

Commit 2e28d29

Browse files
committed
Added C++ specification to game design chapter code blocks
1 parent a847fbf commit 2e28d29

File tree

1 file changed

+37
-36
lines changed

1 file changed

+37
-36
lines changed

chapters/game_design/chapter.md

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,17 @@ Let’s start with our testApp. There are a few things we definitely know we’l
7272

7373
###Gamestates
7474

75-
First let’s create the basic structure of our game. Games typically have at least three parts: a start screen, the game itself, and an end screen. We need to keep track of which section of the game we’re in, which we’ll do using a variable called a game state. In this example, our game state variable is a string, and the three parts of our game are `"start"`, `"game"`, and `"end"`. Let’s add a score and a player at this point as well.

76-
```
75+
First let’s create the basic structure of our game. Games typically have at least three parts: a start screen, the game itself, and an end screen. We need to keep track of which section of the game we’re in, which we’ll do using a variable called a game state. In this example, our game state variable is a string, and the three parts of our game are `"start"`, `"game"`, and `"end"`. Let’s add a score and a player at this point as well.
76+
77+
```cpp
7778
string game_state;
7879
int score;
7980
Player player_1;
8081
```
8182

8283
We’ll then divide up `testApp`’s `update()` and `draw()` loops between those game states:
8384

84-
```
85+
```cpp
8586
//--------------------------------------------------------------
8687
void testApp::update(){
8788
if (game_state == "start") {
@@ -103,7 +104,7 @@ void testApp::draw(){
103104

104105
Let’s set the initial value of `game_state` to `"start"` right when the app begins.
105106

106-
```
107+
```cpp
107108
//--------------------------------------------------------------
108109
void testApp::setup(){
109110
game_state = "start";
@@ -113,7 +114,7 @@ void testApp::setup(){
113114

114115
Finally, let’s make sure that we can move forward from the start screen. In this example, when the player is on the start screen and releases the space key, they’ll be taken to the game.
115116

116-
```
117+
```cpp
117118
//--------------------------------------------------------------
118119
void testApp::keyReleased(int key){
119120

@@ -129,7 +130,7 @@ void testApp::keyReleased(int key){
129130
130131
Great! Let’s move onto our player. Our player’s class looks like this:
131132
132-
```
133+
```cpp
133134
class Player {
134135
public:
135136
ofPoint pos;
@@ -168,7 +169,7 @@ The problem is that, in openFrameworks, `keyPressed()` does not return all the k
168169

169170
Here’s what our new `keyPressed()` and `keyReleased()` functions look like:
170171

171-
```
172+
```cpp
172173
//--------------------------------------------------------------
173174
void testApp::keyPressed(int key){
174175
if (game_state == "game") {
@@ -217,7 +218,7 @@ void testApp::keyReleased(int key){
217218
218219
Add `ofImage player_image` to `testApp.h`, then load the player’s image and instantiate the player in `testApp`’s `setup()`:
219220
220-
```
221+
```cpp
221222
void testApp::setup(){
222223
game_state = "start";
223224
player_image.loadImage("player.png");
@@ -228,7 +229,7 @@ void testApp::setup(){
228229

229230
Finally, update and draw your player in the appropriate part of `testApp::update()` and `testApp::draw()`:
230231

231-
```
232+
```cpp
232233
//--------------------------------------------------------------
233234
void testApp::update(){
234235
if (game_state == "start") {
@@ -257,7 +258,7 @@ Let’s make our bullets next. In order to have a variable number of bullets on
257258

258259
Our bullet class will look a lot like the player class, having a position, speed, width, pointer to an image, and various functions. The big difference is that the bullets will keep track of who they came from (since that will affect who they can hurt and which direction they move).
259260

260-
```
261+
```cpp
261262
class Bullet {
262263
public:
263264
ofPoint pos;
@@ -275,7 +276,7 @@ public:
275276
276277
Our `Bullet.cpp` will look like this:
277278
278-
```
279+
```cpp
279280
void Bullet::setup(bool f_p, ofPoint p, float s, ofImage * bullet_image) {
280281
from_player = f_p;
281282
pos = p;
@@ -306,7 +307,7 @@ Now that our bullet class is implemented, we can go back to `testApp::setup()` a
306307

307308
For now, our `update_bullets()` function will call the `update()` function in each bullet, and will also get rid of bullets that have flown offscreen in either direction.
308309

309-
```
310+
```cpp
310311
//--------------------------------------------------------------
311312
void testApp::update_bullets() {
312313
for (int i = 0; i < bullets.size(); i++) {
@@ -321,7 +322,7 @@ void testApp::update_bullets() {
321322

322323
Our `testApp::update()` and `testApp::draw()` will now look like this:
323324

324-
```
325+
```cpp
325326
//--------------------------------------------------------------
326327
void testApp::update(){
327328
if (game_state == "start") {
@@ -350,7 +351,7 @@ void testApp::draw(){
350351

351352
Finally, let’s add an if-statement to our `keyPressed()` so that when we press the spacebar during the game, we spawn a player bullet:
352353

353-
```
354+
```cpp
354355
//--------------------------------------------------------------
355356
void testApp::keyPressed(int key){
356357
if (game_state == "game") {
@@ -386,7 +387,7 @@ Remember, the first parameter in the bullet’s setup is whether it comes from t
386387
Let’s move on to our enemy. This process should be familiar by now. Add an `ofImage enemy_image;` and a `vector<Enemy> enemies;` to `testApp.h`. Additionally, add `float max_enemy_amplitude;` and `float max_enemy_shoot_interval;` to `testApp.h`--these are two of the enemy parameters we’ll affect with OSC.
387388

Your enemy class will look like this:
388389
389-
```
390+
```cpp
390391
class Enemy {
391392
public:
392393
ofPoint pos;
@@ -409,7 +410,7 @@ public:
409410
Our enemy’s horizontal movement will be shaped by the values fed to a sine wave (which we’ll see in a moment). We’ll keep track of our amplitude variable (so different enemies can have different amplitudes). We’ll also want to keep track of whether enough time has passed for this enemy to shoot again, necessitating the start_shoot and shoot_interval variables. Both of these variables will actually be set in our setup() function. Finally, we’ll have a boolean function that will tell us whether the enemy can shoot this frame or not.
410411

Our enemy class will look like this:
411412

412-
```
413+
```cpp
413414
void Enemy::setup(float max_enemy_amplitude, float max_enemy_shoot_interval, ofImage * enemy_image) {
414415
pos.x = ofRandom(ofGetWidth());
415416
pos.y = 0;
@@ -441,7 +442,7 @@ In update, we’re using the current elapsed time in frames to give us a constan
441442
In `time_to_shoot()`, we check to see whether the difference between the current time and the time this enemy last shot is greater than the enemy’s shooting interval. If it is, we set `start_shoot` to the current time, and return true. If not, we return false.
442443

Let’s integrate our enemies into the rest of our `testApp.cpp`:
443444
444-
```
445+
```cpp
445446
//--------------------------------------------------------------
446447
void testApp::setup(){
447448
game_state = "start";
@@ -496,7 +497,7 @@ void testApp::draw(){
496497

497498
Let’s implement our bullet collision checks. Add a void `check_bullet_collisions();` to your `testApp.h`, then write the following function:
498499

499-
```
500+
```cpp
500501
//--------------------------------------------------------------
501502
void testApp::check_bullet_collisions() {
502503
for (int i = 0; i < bullets.size(); i++) {
@@ -527,7 +528,7 @@ This code is a bit nested, but actually pretty simple. First, it goes through ea
527528

528529
Don’t forget to call `check_bullet_collisions()` as part of `update_bullets()`:
529530

530-
```
531+
```cpp
531532
//--------------------------------------------------------------
532533
void testApp::update_bullets() {
533534
for (int i = 0; i < bullets.size(); i++) {
@@ -545,7 +546,7 @@ void testApp::update_bullets() {
545546
Great! Except… we don’t have any enemies yet! Definitely an oversight. This is where our level controller comes in. Add `LevelController level_controller;` to your `testApp.h`.
546547

Our level controller class is super-simple:
547548

548-
```
549+
```cpp
549550
class LevelController {
550551
public:
551552
float start_time;
@@ -560,7 +561,7 @@ As you might guess, all it’ll really do is keep track of whether it’s time t
560561
561562
Inside our `LevelController.cpp`:
562563
563-
```
564+
```cpp
564565
void LevelController::setup(float s) {
565566
start_time = s;
566567
interval_time = 500;
@@ -578,7 +579,7 @@ When we set up our level controller, we’ll give it a starting time. It’ll us
578579

579580
We’ll wait to set up our level controller until the game actually starts--namely, when the game state changes from `"start"` to `"game"`.
580581

581-
```
582+
```cpp
582583
void testApp::keyReleased(int key){
583584
if (game_state == "start") {
584585
game_state = "game";
@@ -591,7 +592,7 @@ void testApp::keyReleased(int key){
591592
592593
Next we’ll integrate it into our `testApp::update()`:
593594
594-
```
595+
```cpp
595596
//--------------------------------------------------------------
596597
void testApp::update(){
597598
if (game_state == "start") {
@@ -626,7 +627,7 @@ Before we finish, let’s add in our last OSC feature: the ability to throw in b
626627

627628
`Life.h` should look like this:
628629

629-
```
630+
```cpp
630631
class Life {
631632
public:
632633
ofPoint pos;
@@ -643,7 +644,7 @@ public:
643644
644645
And it’ll function like this--a lot like the bullet:
645646
646-
```
647+
```cpp
647648
void Life::setup(ofImage * _img) {
648649
img = _img;
649650
width = img->width;
@@ -661,7 +662,7 @@ void Life::draw() {
661662

662663
Our `update_bonuses()` function works a lot like the bullet collision function:
663664

664-
```
665+
```cpp
665666
//--------------------------------------------------------------
666667
void testApp::update_bonuses() {
667668
for (int i = bonuses.size()-1; i > 0; i--) {
@@ -680,7 +681,7 @@ void testApp::update_bonuses() {
680681

681682
All that’s left for our lives functionality is to alter `testApp::update()` and `testApp::draw()`.
682683

683-
```
684+
```cpp
684685
//--------------------------------------------------------------
685686
void testApp::update(){
686687
if (game_state == "start") {
@@ -739,7 +740,7 @@ Finally, we’ve been a bit stingy with visual feedback, so let’s add in a sta
739740

740741
Change `testApp::setup()` to load in those assets:
741742

742-
```
743+
```cpp
743744
//--------------------------------------------------------------
744745
void testApp::setup(){
745746
...
@@ -754,7 +755,7 @@ Draw them in the appropriate game states using `start_screen.draw(0, 0);` and `e
754755

755756
Add in the last two functions:
756757

757-
```
758+
```cpp
758759
//--------------------------------------------------------------
759760
void testApp::draw_lives() {
760761
for (int i = 0; i < player_1.lives; i++) {
@@ -791,14 +792,14 @@ And let’s add the line to import the OSC at the top of your file after your pr
791792

792793
Add the following:
793794

794-
```
795+
```cpp
795796
#include <iostream>
796797
#include "ofxOsc.h"
797798
```
798799

799800
Next let’s set up all of our variables we are going to use to receive OSC data and map it to in game values. Add the following code into your class.
800801

801-
```
802+
```cpp
802803
class LiveTesting
803804
{
804805
public:
@@ -852,7 +853,7 @@ At this point, go ahead and launch TouchOSC on your device and the Touch OSC des
852853

853854
We are going to make this interface now and deploy it to our phone. We will make this interface to control these parameters in our game:
854855

855-
```
856+
```cpp
856857
//these are the values we will be tweaking during testing
857858
float max_enemy_amplitude;
858859
int interval_time;
@@ -947,7 +948,7 @@ Switch back to your device. You should see your computer listed under FOUND HOST
947948

948949
Finally, TouchOSC is set up. Let’s link it to our game and run our very first playtest. Go back to the programming IDE. Open up `LiveTesting.cpp`. In our default constructor, we will now set up our game to send and receive values over the network. To do this we will need to know which Ip address and port on our device we will send to as well as set up a port on our local computer’s network to receive incoming data. Your computer will have only one IP address but it can send and receive data on thousands of ports. While we aren’t going too deep into ports there, you can think of the IP address like a boat pier. Lots of boats can be docked at a single pier. This is no different. Your ports are your docks and your IP address is your pier. You can think of the data like the people departing and arriving. You’ll need a separate port for each activity in this scenario. If a port isn’t used by your operating system, you can send and receive data there. We are going to use `8000` and `8001`. The final thing to establish is the Address Pattern. It will look like a file path and it will allow us to specify the address pattern match our messages to their right values. Add this code:
949950

950-
```
951+
```cpp
951952
#include "LiveTesting.h"
952953

953954
LiveTesting::LiveTesting(){
@@ -977,7 +978,7 @@ Let’s move on to the next major function we want to write. We need to run an u
977978

978979
Each time we make a change on our device, it will send over the updates to our code via Touch OSC. We want to make sure we get all of the incoming messages that are being sent so we will create a simple while loop. We will loop through the whole list of messages that came into our game that frame and match it to the corresponding variable in our game via if statements.
979980

980-
```
981+
```cpp
981982
while (receiver.hasWaitingMessages()) {
982983
//get the next message
983984
ofxOscMessage m;
@@ -987,7 +988,7 @@ Each time we make a change on our device, it will send over the updates to our c
987988
988989
Every incoming message will come with its own unique address tag and new arguments. You can get access to a message's address via the getAddress function. For example,`if(m.getAddress() == "/game/max_enemy_amplitude")`, will test to see if the message address is /game/max_enemy_amplitude. If it is, set the variable equal to that value in your game's codebase and they are linked together. Every swipe of the knob will translate to direct changes in your game. We do this for every single value we want to set.
989990
990-
```
991+
```cpp
991992
if(m.getAddress() == "/game/max_enemy_amplitude")
992993
{
993994
max_enemy_amplitude = m.getArgAsFloat(0);
@@ -1009,7 +1010,7 @@ To pack up all of the values in our current running game and send them back to t
10091010

10101011
Here's the complete code to add to your LiveTesting.cpp file
10111012

1012-
```
1013+
```cpp
10131014
void LiveTesting::update()
10141015
{
10151016
//our simple while loop to make sure we get all of our messages

0 commit comments

Comments
 (0)