I’m trying to get better at C++ and learn the SFML framework, and my wife likes chocolate. What follows makes perfect sense.
Chocolate Quest Part One is a small and very simple game I wrote for my wife to play. Instead of a “You Win!” screen, there’s a screen revealing the location of some chocolate. Win-win. The arrow keys move a poorly drawn avatar around a poorly drawn version of my back yard, and the goal is to pick up the poorly drawn eggplants. I’m not an artist.
I’m not going to do a line-by-line breakdown, but here’s some notes.
C++ and OOP
The big reason to learn C++ has been to get a grip on OOP and other common programming principals. I made an attempt at writing some useful classes for the game. There is a base class called Scene, and two child classes called Intro and Game. Intro was poorly named. It should have been called CutScene or something. An instance of the Intro class takes a pointer to the game window, and an image that should be big enough to fill the entire window. When invoking the Run method, it shows this image on the screen and waits for a press of the space bar (and then ends itself). I used this for the intro screen, the instructions screen, and the end screen. This was a OOP win – I’ll be able to re-use this class in other little games when I use SFML.
The other child class, called Game, takes a pointer to the game window, a location of a background texture, location of a player texture, and the location of the items to pick up texture. The constructor for the class creates all the sprites from the textures, and sets their starting location. The Run method shows them all on the screen and handles the key motion to move the avatar around. Every key press also fires off a collision detection function (Pickup) that polls the player position and all the pickup-able items and sees if they intersect. If so, the pickup-able item that’s colliding with the avatar gets moved off the screen. It’s a cheap trick, but it works.
Here’s the header for the Intro class.
class Intro : public Scene
Intro(sf::RenderWindow *window, const char *backgroundTexture);
void ProcessEvent(sf::Event event);
My naive take on private and public parts of a class is that if I don’t think I’ll need to get info in a class from somewhere outside of the class, it’s private. Also, I put underscores before private variables because I’ve seen lots of C that does that to indicate private-ness (to other programmers, not the compiler).
The other two C++ issues I’ll have to work through are using references and taking advantage of the Vector class. The items to be picked up could have been stored in a Vector class instead of a fixed-size array. I started to do this, but kept getting errors and I was in a hurry. I use C-style pointers instead of C++-style references to deal with accessing the instance of the sf::RenderWindow class in Main(). I’ll try to use references next time. I’m not completely certain what’s going on there yet. It seems unnecessary to me, but I’m sure it’s there for a reason.
Every time I had a “oh no how do I do this?” moment, I’d find something built into SFML that handled it. That was great. Sprite positions and movement? Handled. Collision detection between two rectangular items? Handled. I wouldn’t be using SFML if I was trying to learn game loops and rendering closer to the metal, but for learning C++ it’s great.
Doing the collision detection in SFML did take me a while to figure out. Here’s the method in the Game class.
unsigned int numItemsToPickUp = 3;
//get rectangle type of player
for (unsigned int i = 0; i < numItemsToPickUp; i++)
I set a local variable numItemsToPickUp to 3 because I know that there are three items to pick up. Then, I create an instance of the sf::FloatRect class called playerRect that holds a rectangle equal to the player sprite global bounds. There’s a method in the sf::Sprite class called getGlobalBounds(), so this part is easy enough.
The sf::FloatRect class has a method called intersects(), which takes another sf::FloatRect as an argument. The loop goes through each item in the _itemsToPickUpSpriteArray and tests that item’s global bounds (cast as a sf::FloatRect so that it can be used as an argument for the intersect function) against the player’s and if so, moves the item’s position off screen at 900,900. Eh, that’s not a good explanation. There aren’t any good posts on this easy collision detection in SFML that I could find through Google, so I might bang a more clear example out later.
I have tons of other little game ideas. The next few will be simple like this, but I’ll try to get better at organizing and styling my code.