data程序讲解 、辅导 c/c++语言编程
Project 3
For questions about this project, first consult your TA.
If your TA can’t help, ask Professor Nachenberg.
Time due:
Part 1: Saturday, February 24
Part 2: Sunday, March 3
WHEN IN DOUBT ABOUT A REQUIREMENT, YOU WILL NEVER LOSE CREDIT
IF YOUR SOLUTION WORKS THE SAME AS OUR POSTED SOLUTION.
SO PLEASE DO NOT ASK ABOUT ITEMS WHERE YOU CAN DETERMINE THE
PROPER BEHAVIOR ON YOUR OWN FROM OUR SOLUTION!
PLEASE THROTTLE THE RATE YOU ASK QUESTIONS
TO 1 EMAIL PER DAY! IF YOU’RE SOMEONE WITH
LOTS OF QUESTIONS, SAVE THEM UP AND ASK ONCE.
2
Table of Contents
Introduction......................................................................................................................... 4
Game Details....................................................................................................................... 5
So how does a video game work?....................................................................................... 8
What Do You Have to Do?............................................................................................... 11
You Have to Create the StudentWorld Class................................................................ 11
init() Details .............................................................................................................. 14
move() Details........................................................................................................... 15
Give Each Actor a Chance to Do Something........................................................ 17
Remove Dead Actors after Each Tick .................................................................. 18
Updating the Display Text.................................................................................... 18
cleanUp() Details ...................................................................................................... 19
The Level Class and Level Data File ............................................................................ 19
The Level Class......................................................................................................... 21
You Have to Create the Classes for All Actors ............................................................ 22
The player ................................................................................................................. 25
What the Avatar Must Do When It Is Created...................................................... 25
What the Avatar Must Do During a Tick.............................................................. 26
What the player Must Do When It Is Attacked..................................................... 27
Getting Input From the User................................................................................. 27
Wall........................................................................................................................... 27
What a Wall Must Do When It Is Created............................................................ 28
What a Wall Must Do During a Tick.................................................................... 28
What a Wall Must Do When It Is Attacked.......................................................... 28
Marble ....................................................................................................................... 28
What a Marble Must Do When It Is Created ........................................................ 28
What a Marble Must Do During a Tick ................................................................ 29
What a Marble Must Do When It Is Attacked ...................................................... 29
What a Marble Must Do When It Is Pushed ......................................................... 29
Pea............................................................................................................................. 30
What a Pea Must Do When It Is Created.............................................................. 30
What a Pea Must Do During a Tick...................................................................... 30
What a Pea Must Do When It Is Attacked............................................................ 31
Pit.............................................................................................................................. 31
What a Pit Must Do When It Is Created ............................................................... 31
What a Pit Must Do During a Tick ....................................................................... 31
What a Pit Must Do When It Is Attacked ............................................................. 32
Crystal....................................................................................................................... 32
What a Crystal Must Do When It Is Created ........................................................ 32
What a Crystal Must Do During a Tick ................................................................ 32
What a Crystal Must Do When It Is Attacked ...................................................... 33
The Exit..................................................................................................................... 33
What the Exit Must Do When It Is Created.......................................................... 33
What the Exit Must Do During a Tick.................................................................. 33
3
What the Exit Must Do When It Is Attacked........................................................ 33
What the Exit Must Do When It Is Revealed ....................................................... 34
Extra Life Goodie ..................................................................................................... 34
What an Extra Life Goodie Must Do When It Is Created..................................... 34
What an Extra Life Goodie Must Do During a Tick ............................................ 34
What an Extra Life Goodie Must Do When It Is Attacked................................... 35
Restore Health Goodie.............................................................................................. 35
What a Restore Health Goodie Must Do When It Is Created ............................... 35
What a Restore Health Goodie Must Do During a Tick ....................................... 35
What a Restore Health Goodie Must Do When It Is Attacked ............................. 36
Ammo Goodie........................................................................................................... 36
What an Ammo Goodie Must Do When It Is Created.......................................... 36
What an Ammo Goodie Must Do During a Tick.................................................. 36
What an Ammo Goodie Must Do When It Is Attacked........................................ 37
RageBot..................................................................................................................... 37
What a RageBot Must Do When It Is Created...................................................... 37
What a RageBot Must Do During a Tick.............................................................. 37
What a RageBot Must Do When It Is Attacked.................................................... 38
ThiefBot .................................................................................................................... 38
What a ThiefBot Must Do When It Is Created ..................................................... 39
What a ThiefBot Must Do During a Tick ............................................................. 39
What a ThiefBot Must Do When It Is Attacked ................................................... 40
Mean ThiefBot.......................................................................................................... 41
What a Mean ThiefBot Must Do When It Is Created ........................................... 41
What a Mean ThiefBot Must Do During a Tick ................................................... 41
What a Mean ThiefBot Must Do When It Is Attacked ......................................... 43
ThiefBot Factory....................................................................................................... 43
What a ThiefBot Factory Must Do When It Is Created ........................................ 43
What a ThiefBot Factory Must Do During a Tick................................................ 44
What a ThiefBot Factory Must Do When It Is Attacked ...................................... 44
Object Oriented Programming Best Practices .................................................................. 44
Don’t know how or where to start? Read this! ................................................................. 49
Building the Game ............................................................................................................ 50
For Windows................................................................................................................. 50
For macOS .................................................................................................................... 51
What to Turn In................................................................................................................. 51
Part #1 (20%)................................................................................................................ 51
What to Turn In For Part #1.......................................................................................... 53
Part #2 (80%)................................................................................................................ 54
What to Turn In For Part #2.......................................................................................... 54
FAQ................................................................................................................................... 55
4
Introduction
NachenGames corporate spies have learned that SmallSoft is planning to release a new
game called Marble Madness, and would like you to program an exact copy so
NachenGames can beat SmallSoft to the market. To help you, NachenGames corporate
spies have managed to steal a prototype Marble Madness executable file and several
source files from the SmallSoft headquarters, so you can see exactly how your version of
the game must work (see posted executable file) and even get a head start on the
programming. Of course, such behavior would never be appropriate in real life, but for
this project, you’ll be a programming villain.
In Marble Madness, the player has to navigate through a series of robot-infested mazes in
order to gather valuable crystals. After the player has gathered each of the crystals within
a particular maze, an exit will be revealed, and the player may then use the exit to
advance to the next maze. The player wins by completing all of the mazes.
Here is an example of what the Marble Madness game looks like:
Figure #1: A screenshot of the Marble Madness game. You can see the player (top-middle), two different
types of robots (RageBots and ThiefBots), a bunch of marbles, a bunch of pits (that can only be crossed if
they are filled in with a marble), ThiefBot factories, blue crystals, a healing kit, and an ammo kit.
5
Game Details
In Marble Madness, the player starts out a new game with three lives and continues to
play until all of his/her lives have been exhausted. There are multiple levels in Marble
Madness, beginning with level 0, and each level has its own maze. During each level, the
player must gather all of the blue crystals within the current maze before the exit is
revealed and they may use it to move on to the next level.
Upon starting each level, the player’s avatar is placed in a maze filled with one or more
blue crystals, marbles, pits, robots, robot factories and other goodies. The player may use
the arrow keys to move their avatar (the Indiana Jones-looking character) left, right, up
and down through the maze. They may walk on any square so long as it doesn’t have a
wall, a marble, a factory, a robot, or a pit on it. The player may walk onto a square
containing a marble if they are able to push it out of the way first. In addition to walking
around the maze, the player may also shoot their pea cannon – but beware, it has only
limited peas. Peas can destroy robots as well as marbles, but it takes more than one shot
to do so.
There are three different types of goodies distributed throughout the maze that the player
can collect in addition to blue crystals. If the player’s avatar steps upon the same square
as an extra life goodie, it instantly gives the player an extra life. If the avatar steps onto
the same square as a restore health goodie, it will restore the player to full health (in case
of having been injured by shots from the robots). Finally, if the avatar steps onto the same
square as an ammo goodie, it will give the player 20 additional peas.
There are four major types of robots in Marble Madness: Horizontal RageBots, Vertical
RageBots, Regular ThiefBots and Mean ThiefBots
As mentioned, RageBots fall into two categories – Horizontal RageBots and Vertical
RageBots. Horizonal RageBots simply move back and forth on a row of the screen (only
reversing course when they run into an obstacle), shooting at the player’s avatar if he/she
ever walks in their line of sight. Vertical RageBots are identical to their Horizontal
cousins, but move up and down within a single column of the maze. RageBots can start
out anywhere in the maze (depending on where the designer of the maze choses to put
them).
In contrast to the RageBot, the ThiefBots are a bit nastier. These robots wander around
the maze looking for goodies to steal. If they happen to step onto a goodie (an extra life
goodie, a restore health goodie, or an ammo goodie) and they don’t already hold one,
they may pick it up for themselves. As with RageBots, there are two types of ThiefBots:
Regular ThiefBots and Mean ThiefBots. Regular ThiefBots simply wander aimlessly
around the maze looking for, and picking up, goodies. They are otherwise harmless and
will not fire upon the player’s avatar. In contrast, in addition to picking up goodies, Mean
ThiefBots will fire a pea anytime the player steps in their path. So beware! When any
type of ThiefBot dies, if it previously picked up a goodie, it will drop this object upon its
square in the maze.
6
ThiefBots are created by ThiefBot factories, of which there are two types – one that
produces Regular ThiefBots and one that produces Mean ThiefBots. ThiefBots never
start out in the maze; they are added only by factories.
Once the player has collected all of the blue crystals within the current maze, an exit will
appear. The exit is invisible and unusable until all of the crystals have been collected
from the level. Once the exit has been revealed, the player must direct their avatar to the
exit in order to advance to the next level. The player will be granted 2000 points for
exiting a level. The player will also be given a bonus for completing the level quickly, if
they did so fast enough. The game is complete once the player has used the exit on the
last level.
If the player’s health reaches zero (the player loses health when shot), their avatar dies
and loses one “life.” If, after losing a life, the player has one or more remaining lives left,
they are placed back on the current level and they must again solve the entire level from
scratch (with the level starting as it was at the beginning of the first time it was
attempted). The player will restart the level with full health points, as well as 20 peas
(regardless of how many they had when they died). If the avatar dies and has no lives left,
then the game is over.
The Marble Madness maze is exactly 15 squares wide by 15 squares high, and both the
player’s avatar and robots may move to any adjacent square that doesn’t contain a wall, a
pit, a marble, a robot, the player or a factory. The one exception is that ThiefBots are
born in Factories, so they may start out on the same square as a factory, but are not
allowed to move back onto their birth factory once they’ve left it. The bottom-leftmost
square has coordinates x=0,y=0, while the upper-rightmost square has coordinate
x=14,y=14, where x increases to the right and y increases upward toward the top of the
screen. You can look in our provided file, GameConstants.h, for constants that represent
the maze’s width and height (VIEW_WIDTH and VIEW_HEIGHT).
In Marble Madness, each level’s maze is stored in a different data file. For example, the
first level’s maze is stored in a file called level00.txt. The second level’s maze is stored
in a file called level01.txt, and so on. Each time the player is about to start a new level,
your code must load the data from the appropriate data file (using a class called Level that
we provide) and then use this data to determine the layout of the current level.
Each level data file contains a specification for the layout of the maze, the initial
locations of all the RageBots and the player’s avatar, as well as the initial locations of all
marbles, pits, factories, crystals, goodies and the exit. For more information on the level
data files, please see the Level Data File section below. You may define your own level
data files to customize your game (and more importantly, to test it).
Once a new maze has been prepared and the player’s avatar and all the robots and items
in the maze have been properly situated, the game play begins. Game play is divided into
7
ticks, and there are twenty ticks per second (to provide smooth animation and game play).
During each tick, the following occurs:
1. The player has an opportunity to move their avatar exactly one square
horizontally or vertically, fire their pea cannon (if they have peas), or give up
(some levels are unsolvable if the player makes a mistake, so if the player realizes
this, they can press the Escape key to lose a life and restart the level from scratch).
2. Every other object in the maze (e.g., RageBots, ThiefBots, factories, goodies, etc.)
is given an opportunity to do something. For example, when given the opportunity
to do something, a RageBot can move one square (left, right, up or down)
according to its built-in movement algorithm (the RageBot movement algorithms
are described in detail in the various RageBot sections below).
The player controls the direction of their avatar with the arrow keys, or for lefties and
others for whom the arrow key placement is awkward, WASD or the numeric keypad: up
is w or 8, left is a or 4, down is s or 2, right is d or 6. The player may move their avatar
between the maze’s Walls as they please. The player can sacrifice one life and restart the
current level by pressing the Escape key at any time.
The player’s avatar may fire their pea cannon by pressing the space bar. A pea that hits a
RageBot or a ThiefBot does 2 points of damage to it. If, after repeated hits, the robot
dies, the player earns points:
For destroying a RageBot of any type: 100 points
For destroying a Regular ThiefBot: 10 points
For destroying a Mean ThiefBot: 20 points
The player also earns points (and special benefits) by picking up (i.e., moving onto the
same square as) various items:
Blue Crystal: 50 points (all crystals must be collected to advance to the next level)
Extra Life Goodie: 1000 points (the user gets an extra life)
Restore Health Goodie: 500 points (the user’s health is restored to 100%)
Ammo Goodie: 100 points (the user receives 20 additional peas)
Players also earn bonus points for completing a level quickly. Each level’s maze starts
with a bonus score of 1000 points. During each tick of the game, the bonus score is
reduced by one point until the bonus reaches zero (the bonus never goes below zero). If
and when the player completes the current level, whatever bonus remains is added onto
their score. This incentivizes the player to complete each level as quickly as possible
since the player wants to maximize their score in the game.
The player starts with three lives. The player loses a life if their health reaches zero (from
being shot by robots).
8
When a Player dies, the player’s number of remaining lives is decremented by 1. If the
player still has at least one life left, then the user is prompted to continue and given
another chance by restarting the current maze level from scratch. All the RageBots that
were initially on the level will again be alive and returned to their starting positions, the
player’s avatar will be returned to their starting position, and the maze will revert back to
its original state (all crystals, goodies, pits and marbles in their initial positions). In
addition, if the exit was exposed in the maze prior to the avatar’s death, then this too will
be hidden from the maze until such time that the player collects all Crystals on the level.
Then game play restarts. If the player is killed and has no lives left, then the game is over.
Pressing the q key lets you quit the game prematurely.
So how does a video game work?
Fundamentally, a video game is composed of a bunch of objects; in Marble Madness,
those objects include the player’s avatar, RageBots (Horizontal and Vertical), ThiefBots
(Regular and Mean), goodies (e.g., extra life goodies), crystals, marbles, pits, walls,
factories, and the exit. Let’s call these objects “actors,” since each object is an actor in
our video game. Each actor has its own x,y location in the maze, its own internal state
(e.g., a RageBot knows its location, what direction it’s moving, etc.) and its own special
algorithms that control its actions in the game based on its own state and the state of the
other objects in the world. In the case of the player’s avatar, the algorithm that controls
the avatar actor object is the user’s own brain and hand, and the keyboard! In the case of
other actors (e.g., RageBots), each object has an internal autonomous algorithm and state
that dictates how the object behaves in the game world.
Once a game begins, gameplay is divided into ticks. A tick is a unit of time, for example,
50 milliseconds (that’s 20 ticks per second).
During a given tick, the game calls upon each object’s behavioral algorithm and asks the
object to perform its behavior. When asked to perform its behavior, each object’s
behavioral algorithm must decide what to do and then make a change to the object’s state
(e.g., move the object 1 square to the left), or change other objects’ states (e.g., when a
RageBot’s algorithm is called by the game, it may determine that the player’s avatar has
moved into its line of fire, and it may fire its pea cannon). Typically, the behavior
exhibited by an object during a single tick is limited in order to ensure that the gameplay
is smooth and that things don’t move too quickly and confuse the player. For example, a
RageBot will move just one square left/right/up/down, rather than moving two or more
squares; a RageBot moving, say, 5 squares in a single tick would confuse the user,
because humans are used to seeing smooth movement in video games, not jerky shifts.
After the current tick is over and all actors have had a chance to adjust their state (and
possibly adjust other actors’ states), our game framework (that we provide) animates the
actors onto the screen in their new configuration. So, if a RageBot changed its location
from 10,5 to 11,5 (moved one square right), then our game framework would erase the
graphic of the RageBot from location 10,5 on the screen and draw the RageBot’s graphic
9
at 11,5 instead. Since this process (asking actors to do something, then animating them to
the screen) happens 20 times per second, the user will see somewhat smooth animation.
Then, the next tick occurs, and each object’s algorithm is again allowed to do something,
our framework displays the updated actors on-screen, etc.
Assuming the ticks are quick enough (a fraction of a second), and the actions performed
by the objects are subtle enough (i.e., a RageBot doesn’t move 3 inches away from where
it was during the last tick, but instead moves 1 millimeter away), when you display each
of the objects on the screen after each tick, it looks as if each object is performing a
continuous series of fluid motions.
A video game can be broken into three different phases:
Initialization: The game World is initialized and prepared for play. This involves
allocating one or more actors (which are C++ objects) and placing them in the game
world so that they will appear in the maze.
Game play: Game play is broken down into a bunch of ticks. During each tick, all of the
actors in the game have a chance to do something, and perhaps die. During a tick, new
actors may be added to the game and actors who die must be removed from the game
world and deleted.
Cleanup: The player has lost a life (but has more lives left), the player has completed the
current level, or the player has lost all of their lives and the game is over. This phase frees
all of the objects in the World (e.g., robots, walls, marbles, goodies, the player’s avatar,
etc.) since the level has ended. If the game is not over (i.e., the player has more lives),
then the game proceeds back to the Initialization step, where the maze is repopulated
with new occupants and game play restarts at the current level.
Here is what the main logic of a video game looks like, in pseudocode (we provide some
similar code for you in our provided GameController.cpp):
while (The player has lives left)
{
Prompt_the_user_to_start_playing(); // "press a key to start"
Initialize_the_game_world(); // you’re going to write this
while (the player is still alive)
{
// each pass through this loop is a tick (1/20th of a sec)
// you’re going to write code to do the following
Ask_all_actors_to_do_something();
Delete_any_dead_actors_from_the_world();
// we write this code to handle the animation for you
Animate_all_of_the_actors_to_the_screen();
Sleep_for_50ms_to_give_the_user_time_to_react();
}
10
// the player died – you’re going to write this code
Cleanup_all_game_world_objects(); // you’re going to write this
if (the player is still alive)
Prompt_the_Player_to_continue();
}
Tell_the_user_the_game_is_over(); // we provide this
And here is what the Ask_all_actors_to_do_something() function might look like:
void Ask_all_actors_to_do_something()
{
for each actor on the level:
if (the actor is still alive)
tell the actor to doSomething();
}
You will typically use a container (an array, vector, or list) to hold pointers to each of
your live actors. Each actor (a C++ object) has a doSomething( ) member function in
which the actor decides what to do. For example, here is some pseudocode showing what
a (simplified) RageBot might decide to do each time it gets asked to do something:
class RageBot: public SomeOtherClass
{
public:
void doSomething()
{
If the player is in my line of sight, then
Fire my pea cannon in the direction of the player
Else if I can move in my current direction w/o hitting an obstacle, then
Move one square in my current direction
Else if I’m about to run into an obstacle, then
Reverse my direction, but don’t move during this tick
}
...
};
And here’s what the player’s doSomething( ) member function might look like:
class Player: public …
{
public:
void doSomething()
{
Try to get user input (if any is available)
If the user pressed the UP key and that square is open then
Increase my y location by one
If the user pressed the DOWN key and that square is open then
Decrease my y location by one
...
If the user pressed the space bar to fire and the player has
peas, then
Introduce a new pea object into the game
...
}
...
};
11
What Do You Have to Do?
You must create a number of different classes to implement the Marble Madness game.
Your classes must work properly with our provided classes, and you must not modify
our classes or our source files in any way to get your classes to work properly (doing
so will result in a score of zero on the entire project!). Here are the specific classes that
you must create:
1. You must create a class called StudentWorld which is responsible for keeping
track of your game world (including the maze) and all of the actors/objects
(RageBots, ThiefBots, peas, crystals, goodies, pits, marbles, the player’s avatar,
etc.) that are inside the maze.
2. You must create a class to represent the player in the game.
3. You must create classes for Horizontal/Vertical RageBots, Regular ThiefBots,
Mean ThiefBots, factories, marbles, pits, walls, crystals, extra life goodies, restore
health goodies, ammo Goodies, walls, and the exit, as well as any additional base
classes (e.g., a robot base class if you find it convenient) that help you implement
the game.
You Have to Create the StudentWorld Class
Your StudentWorld class is responsible for orchestrating virtually all game play – it keeps
track of the game world (the maze and all of its inhabitants such as RageBots, ThiefBots,
the player, marbles, walls, the exit, goodies, etc.). It is responsible for initializing the
game world at the start of the game, asking all the actors to do something during each tick
of the game, destroying an actor when it disappears (e.g., a RageBot dies), and destroying
all of the actors in the game world when the user loses a life.
Your StudentWorld class must be derived from our GameWorld class (found in
GameWorld.h) and must implement at least these three methods (which are defined as
pure virtual in our GameWorld class):
virtual int init() = 0;
virtual int move() = 0;
virtual void cleanUp() = 0;
The code that you write must never call any of these three functions. Instead, our
provided game framework will call these functions for you. So, you have to implement
them correctly, but you won’t ever call them yourself in your code.
When a new level starts (e.g., at the start of a game, or when the player completes a level
and advances to the next level), our game framework will call the init() method that you
12
defined in your StudentWorld class. You don’t call this function; instead, our provided
framework code calls it for you.
The init() method is responsible for loading the current level’s maze from a data file
(we’ll show you how below), and constructing a representation of the current level in
your StudentWorld object, using one or more data structures that you come up with.
The init() method is automatically called by our provided code either (a) when the game
first starts, (b) when the player completes the current level and advances to a new level
(that needs to be loaded/initialized), or (c) when the user loses a life (but has more lives
left) and the game is ready to restart at the current level.
When the player has finished the level loaded from level00.txt, the next level data file to
load is level01.txt; after level01.txt, level02.txt; etc. If there is no level data file with the
next number, or if the level just completed is level 99, the init() method must return
GWSTATUS_PLAYER_WON. If the next level file exists but is not in the proper format for a level
data file, the init() method must return GWSTATUS_LEVEL_ERROR. Otherwise, the init()
method must return GWSTATUS_CONTINUE_GAME.
Once a new level has been loaded/initialized with a call to the init() method, our game
framework will repeatedly call the StudentWorld’s move() method, at a rate of rou