Adding the bird
Download
bird-0x114.bmp,
edit it and place it inside the
res/images folder.
Create a new class named
Bird, I mean: create two files:
Bird.c and
Bird.h. Declare it in the
Makefile.
For now, let's just try to make our little bird appear and make it
fall.
Our bird will have a
x and
y coordinates,
width,
height, a vertical
velocity and of course a
bitmap image.
To make the little bird fall, I have set a
GRAVITY. At each
update, the
gravity is added to the velocity, which will then be
added to the bird's current y location:
Now we need to
add a bird to our
game state,
initialize it and add the respective
update,
draw and
delete method calls:
If you
compile, install and run, you should now see flappy
falling!
Making flappy jump
Now we need to make little flappy
jump. You may have noticed that the bird
update method receives an
integer named
jump. Well, my idea is: when the player presses the
space bar on the keyboard, we will call this method with
jump = 1, this tells flappy to jump. Otherwise, we just call flappy's update method with
jump = 0.
In order to accomplish this, let's modify flappy's
update method - if
jump == 1, let's modify it's
velocity:
Now, let's modify the game state's
update method to send
jump == 1 when the
space bar is
released:
By the way, let's change flappy's
default start position:
Quick preview
Compile and run. Now when you press the
space bar, flappy
flies! This is how the game looks like now. Cool isn't it?
Increasing FPS
Our game might be running with a little lag. Let's change that.
In
FlappyNix.c:
const int FPS = 60;
const int mouseFPSmult = 1;
In
Bird.c:
const int GRAVITY = 1;
const int JUMP_VEL = -12.5;
If you now
compile and run the game, it should be much
smoother.
Making flappy lose
Since everything is working so good, let's go further and make flappy die when it
touches the
ground. In order to do that, after each
update, we need to check if the
bottom of the bird's sprite is
below the
top of the ground sprite/image - easy, right?
To start, I have created an integer
groundY, because we were calculating it in the
draw method - and
draw methods should not contain any calculation what so ever. I initialize
groundY in the
constructor:
Furthermore, to check flappy's
collision with the
ground, I have implemented the
gameOver function. For now it only checks if flappy
hit the ground - I have created another function for that as well - but once we implement the moving
pipes, we will also check if flappy collided with any of them in this function.
Since we are modifying the
update function, and I would like to make flappy
fly by pressing either the space bar or the
left mouse button, let's add that option:
Compile and run the game. You should now be able to use either the
space bar or the
left mouse button to make flappy fly. If flappy touches the
ground, you should
lose and go back to the
main menu.
Adding the pipes
So we are pretty much almost done! We just need to add the
pipes now!
So let's do it! Create
Pipe.c,
Pipe.h and declare it in the
Makefile. This class will represent the pipe with the little
gap through which flappy is supposed to fly.
Download
top-pipe-0x114.bmp and
bottom-pipe-0x114.bmp.
Edit and place them inside your
res/images folder.
Every pipe will be described by
four variables: the
x and y coordinates of the
top left corner of the
gap, and the
width and
height of each half of the pipe - this is for future convenience. The pipe constructor will have
two parameters: the
x where the pipe should be created and the
ground y coordinate - because the pipe gap location will be
randomly generated, we need to know the ground location to set the
limit for the random function.
Since we are going to create
a lot of pipes, it is not a good idea for each pipe to have it's own images of the top and bottom parts loaded. A better approach is to load those images only
once, and use them to draw every pipe, only at
different positions - this is known as
flyweight, yet another
design pattern. We can resolve this using something like a
singleton, just like we did for the
mouse.
Here is what everything described above looks like:
Ok, now it's time to implement the
update,
draw and
delete methods. I have decided to put some
global variables in
Utilities.h, so yeah, I have made some changes to the rest of the code - you should be just fine without even having to do them, or if you do have to do them, it will be easy. Here is how the methods I told you to implement look like, as well as the global variables I created:
Ok, let's try to test our game by adding some pipes! Add an
array of
three pipe pointers in the
GameState struct and
initialize it like so:
Create a separate function to
update and
draw the pipes:
Do the same to
delete them. Do not forget to delete the
bitmaps as well, and
even more important, to
NULL reassign them:
Quick preview
Compile, install and run. This is what we got so far. How awesome is that?
P.S. - I am terrible at playing this game.
Implementing the pipes generator
We have almost, almost done. We have some
pipes moving, but now we have to keep them coming. After that we need to do something about the bird colliding with the pipes, and then our project is finished! So, let's go!
The first step is to change the
size of the pipes array. Since the
maximum number of
visible pipes on the screen is
four, let's make the array have
five pipes.
Now we have to edit the
updatePipes function: when the
left most pipe moves
off the screen, we have to
delete it,
shift every pipe on the pipes array
one time to the left and finally
create a new pipe at the
last position of the array. It is that simple!
Try to code this for yourself and only then compare with the screenshot below.
Adding pipe collisions
Fist things first: we need a simple function to detect
AABB collisions. I implemented mine in
Rectangle:
After that, we need to check if flappy really hit any pipe. Remember the
gameOver function where I have previously told you we were going to do that? Well, let's actually do that there and now.
I created an
integer variable called
flappyHitPipe that is initialized with
zero (false).
Then I created a
rectangle which corresponds to the bird's image limits -
bRect.
I am not quite sure about this one, but I guess we need to
check collisions on the
first two pipes, because although the first one might be a bit off the screen, flappy might be able to hit the second pipe before the first one is deleted. I do this with a simple
for cycle.
Inside the
for cycle we will need to check if our
flappyHitPipe flag is already
true - if it is, there is no need to check for any other collisions - therefore the
continue;. If the flag is still
false, we create
two rectangles - pRect1 and pRect2 - corresponding to the
top and
bottom halves of the
pipe being analysed; we then use the
colliding function from
Rectangle to check if the bird rectangle -
bRect - is colliding either with
pRect1 or
pRect2 and update the
flappyHitPipe flag accordingly. Then, inside the for cycle, I delete
pRect1 and
pRect2; outside the for cycle I delete the
bRect. Finally, I return the
flappyHitPipe flag. Here is everything explained above translated to code:
And here is a demonstration of flappy going
through the pipes,
against the pipes and
against the floor. The
collisions are working marvelously:
Although, you may have noticed a
bug! If we press fast enough to make flappy fly really high, it won't hit the pipes because the pipes are not that high, and you will be able to keep flappy going as long as you wish:
There is a really simple way to solve this: make the collision rectangle of the top half of the pipe start for example at
y = -500 and
do not let flappy fly higher than this.
Highlighted in the following screenshot are the parts of the code I had to
modify to resolve this bug:
The end
Phew, what a long and dangerous journey this has been!
These tutorials were great to write and I have learned a lot from them. I really like writing these tutorials, they test my patience. I just hope you have learned anything from them, even if it was just a little bit. The time has come for me to say good bye to this tutorial series and ship on to other projects.
If you would like to get in touch with me directly, go
here.
Back to index
Click
here to go back to the index post.