For this lab you will be refining an already created game to add more sophisticated forms of collision detection as well as adding elements to the gameplay.
As before, you may work in groups of 2-3. Feel free to email the TAs if you run into any problems along the way, and we'll be happy to help you out.
The game is a remake of a minigame from Super Mario RPG. In it, red and green shells fall down from the top of the screen. You control a beetle-shaped "ship" at the bottom of the screen. If a shell hits your beetle, you lose. Your beetle can move from left to right to dodge shells and can shoot at the shells to destroy them. Green shells are destroyed in one hit; red shells are turned into green shells when hit by shots. When a green shell is destroyed it explodes into several stars which radiate outwards in semi-random directions and act as bullets (thereby possibly creating chain reactions of explosions).
Start out by unzipping the source somewhere convenient. You should know how to get this working from the previous lab. This contains the source code for an incomplete version of the game. In this version, shells will only collide with (and bounce off of) the ground. You will have to write code to make them collide with bullets (and react accordingly), collide with the player's ship (destroying it), and collide with each other (bouncing off without being destroyed).
Because shells will be constantly falling from the top of the screen, the number of objects on the screen may get quite high. As a result, checking for collisions between each shell and every other shell in the game will become prohibitively expensive. Therefore, you will also have to implement some sort of a system for dividing the screen into cells, and having each shell only check for collisions with other shells in its own or neighboring cells.
There should be a pre-compiled executable binary of an example solution to this lab in the main directory. This will show you a version with correctly working collision detection implemented. It could, of course, be improved upon, but we're looking for about this level of detection.
The code is split into two main sections. The first section is "Game Code", which contains code controlling the basic dynamics of gameplay. The other section is "Game Objects". This section contains the code for the various types of objects in the game: shells, ships, bullets and stars, as well as a generic "gameobject" class that is the superclass of them all.
The game is controlled through the gameclass (contained in gameclass.cpp and .h). The gameclass's jobs include loading and unloading images, creating new objects, deleting objects and calling the game objects' member functions for updating and drawing.
Collision detection is handled by the gameobject class. When a gameobject's Collide(gameobject *o) function is called, the gameobject will call the GetType() function of both itself and the object it is colliding with in order to determine the types of objects that are colliding (e.g. shell - shell, ship - star, etc.). It will then call a special HandleCollision(TYPE_1 *a, TYPE_2 *b) function corresponding to the two colliding types.
A large part of your job in this lab will be implementing these HandleCollision functions, which are currently just stubs, for the various possible types of colliding objects. However, keep in mind that these will never be called unless you also add code in the gameclass to call the Collide() function of the gameobjects.
Take a look at the gameobject header to learn what functions and data members it has available. In particular, note the various GetPosition, GetVelocity, SetPosition, SetVelocity and Destroy functions. These will be your main way of getting information about and affecting objects.
As mentioned, there are various stubbed HandleCollision functions in gameobject.cpp. You will be filling these in to implement collision detection and response. You can treat all collisions in this game as simple circle-on-circle collisions, with the radius of each circle determined by the _radius member variable.
This is probably the toughest of the functions you will have to implement in terms of collision detection and response. First, you will have to detect whether or not the two indicated shells are colliding. Then, if they do collide, you will have to react to this collision (the shells should bounce off of each other). It is a good idea to not only change the colliding shells' velocities, but to also change their positions such that they are no longer interpenetrating.
In these cases, both the shell and the object it collides with should be destroyed. If the ship is destroyed, this will end the game. The shell's Destroy() function takes into account that for red shells, being "destroyed" simply results in turning green, so you don't have to worry about that. If you want, you can have shells be pushed away from whatever object they are colliding with (e.g. to have a bullet knock a red shell upwards when they hit).
If you wish, you can have this also result in both parties being destroyed.
Generally speaking, other types of collisions should not result in anything happening, but if you want to change this (e.g. have stars colliding with bullets multiply into 3 stars, or something) feel free.
It's a good idea to work out the math of the shell-shell collisions before you start writing code. It can be a little confusing, but as long as you plan it out beforehand rather than trying random hacks it shouldn't cause too much trouble.
The gameclass is where you'll be implementing checking for (as opposed to reacting to) collisions. As mentioned before, you will have to create a grid of collision cells. To do this, you will first have to define a collision cell class. How you do this is up to your discretion. In general, the role of collision cells is to record what objects are in a certain area (e.g. a 50 x 50 pixel rectangle) of the screen. Then, when you are updating an object, you can minimize the number of collision checks by only calling Collide(gameobject *o) with the objects in its own and neighboring collision cells.
Take note of the various member variables of gameclass, in particular the arrays of shells, ships, bullets and stars. These arrays are where all the game objects are stored. You can add new gameobjects using the AddObject(gameobject *o) function.
If you need to do anything to initialize your collision cell matrix, which should be declared as a member variable of the gameclass, this would be the place to do it.
This function is called every frame. Its responsibilities are to call the Run() functions of every gameobject in the game, to add new shells as they fall from the top of the screen, to remove old objects from the object lists when if they have been destroyed, to make shells properly bounce off of the special terrain elements (the rectangular step and the circular bump) and to initiate collision handling. All of these tasks except for the last are already implemented. To implement the last, you will have to go through the gameobjects and call the appropriate Collide(gameobject *o) functions, using the information stored in the collision cells about what objects are nearby to minimize the number of calls.
When you are designing your collision cells, try to be speed-conscious. Given that there will be a relatively small number of collision cells it probably won't matter for this particular game, but in games with wide open scrollable terrain you could have tens of thousands of collision cells, at which point speed would become a real factor. Try to think of a framework that doesn't require performing some action on all collision cells (even empty ones) every frame.
This function should make the shell bounce off of the circular bump on the bottom of the screen. As with HitBox, the function is passed in an object to check for collision and the position of the bump at that point in time (which changes as the background scrolls). Also like HitBox, this should not only change the velocity of the shell but also move it so that it no longer penetrates the terrain. As before, treat this as a circle-on-circle collision.
To test out your code, there is a Flood button ('F'), which floods the playfield with shells. The game should not slow down with tons of shells handled. Try debugging by shrinking down the shells and making sure you can handle a couple thousand shells without any slowdown.
In addition to implementation of collision detection, you should improve upon the game with at least two good new gameplay elements. There are no limits on what these can be, but they should be non-trivial, cool, and make the game more fun.
Here are some possibilities for these. You can also think of your own. Points are for thought and effort! This is a Game-Design course, after all, so be creative!
Make sure your additions actually make the game more fun, interesting, or unique. Include in the readme file you will submit what sort of additions you made, how you did them, and why you decided they would be good things to include.
You should write a readme.txt file explaining the gameplay changes that you made and any other additions to the spec you may have made (for example handling the extra cases of collision detection), as well as any comments on your own code you may have. To submit, zip the readme.txt up along with any .cpp and .h files that you modified. Also include a Release-build binary, so we don't have to compile everything. Submit the ZIP file on CMS.
This lab project is due Monday, March 28th by 11:59pm (midnight).