Fungustris - University of Notre Dame

Transcription

Fungustris - University of Notre Dame
Fungustris
Robert Bruggner and Matt Corgan
University Of Notre Dame, Notre Dame, IN 46556, USA
Abstract. Fungustris started as an effort to mimic the famous arcade-style game
Tetris. Our inspiration was an assignment for a Data Structures class which required
that we make use of data structures and algorithms to implement a program of our
choice. Suggested genres for programs included databases, networking applications,
string processing, and video games. Thinking about video games, we noticed that
many of our favorites were written in the late 1980’s and early 1990’s when objectoriented programming was not nearly as dominant as it is today. With this in mind
we wondered if we could create a game such as Tetris in an object-oriented fashion,
unlike most of its original versions. The following details that attempt.
Keywords: Fungustris, Tetris, SDL
1
Introduction
The authors delved headlong into the task of making a video game without
really knowing how to implement the graphics. The closest either of us had
come to programming outside of a console window was with the Java Swing
GUI builder. We realized that this would not be adequate for an arcade game.
Browsing the Internet we came across the Simple DirectMedia Layer, or SDL
for short. We describe it in further detail below, but it is essentially a set of
libraries written in C for accepting real time input and drawing graphics to
the screen.
2
2.1
Tools
SDL
For implementing the graphical layer of Fungustris, we chose to use the free,
cross platform libraries of SDL (Simple DirectMedia Layer / www.libsdl.org).
We decided to go with SDL because it supported all the tools we needed to implement Fungustris: direct drawing to the screen (SDL BlitSurface/SDL LowerBlit),
real-time updating of specified screen areas (SDL UpdateRect/SDL UpdateRects),
timing mechanisms to create the effect of frames (SDL GetTicks, SDL Delay),
etc. The SDL Libraries were designed to be used with C which altered our
programming style a tad.
2
2.2
C++
C++ was the programming language of choice for our implementation of
Tetris. It has majestic support for encapsulation enabling us to build upon
smaller concepts such as an individual piece, to larger ones such as a game
board, and finally to the full concept of the game. C++ is also backwards
compatible with C, allowing us to use the SDL libraries mentioned above.
3
3.1
Procedures
Program Breakdown
Because Fungustris was a team effort, we needed to find a way to split up
the programming between the two authors. To do this we decided that we
could break the program into three logical pieces. The first piece deals with
input acceptance. The second piece is responsible for receiving the current
state of the game and translating it to the graphical representation that is
seen by the user. The third and final piece sits between the first two. It could
be considered the brains of the program, receiving the input from the first
part and passing the output to the second part.
3.2
An Event Driven Program
Unlike the console applications we were most familiar with, Tetris needed to
be an event driven program. We designated certain keys to activate different
events. The SDL provides a keyboard monitoring function. With this function we were able to map the control keys to functions that performed their
corresponding actions. These actions are the standard Tetris moves: move
left, move right, rotate, move down, and drop. The keys we chose to activate
these events were the left arrow, right arrow, up arrow, down arrow, and
space-bar, respectively. There is no standard for the keys used to perform
these functions because of the wide variety of authors’ preferences and the
many different control modules for various gaming systems.
One of the main functions of our game was the event listener. Using the
SDL Event struct, we were able to watch for an SDL Event, in this case
a keystroke, and appropriately respond to the pressed key. We declared an
SDL Event, ’keystroke’ , and continually monitored it for an SDLK KEYDOWN
action. In the event of SDLK KEYDOWN, the SDL libraries place a ’1’ in
an array of all the keyboard keys. By looking at this array, we were able to
determine which keys were pressed and call the appropriate game functions
(i.e. move the piece left in the event of the left arrow key being pressed, quit
the game if ’q’ is pressed, etc.).
3
3.3
The SDL Layer Class
One of Fungustris’ two most important classes was the SDL Layer class. This
class was designed and written to be the translator between the game class
(the other most important class) and the screen using a multitude of functions
and data. The basic idea of the SDL Layer class is that it creates a new
window, dfunctionsraws the game background, reads an array received from
the game class that indicates where the pieces are, and updates the screen
accordingly. In a little more detail: Every tetris board consists of an 18 x
10 grid of blocks. We created a base data structure, ’square’, that contained
information such as the the square’s image, its position, and whether it was
alive or not. We then declared an 18 x 10 array of squares and turned each
one on and off, based on the array received from the game class. Each time
the SDLK KEYDOWN event occurred, the SDL Layer class synchronized
with the game class board array, drew squares in their appropriate position,
and then updated the screen.
3.4
The Game Class
The third piece of the program is invisible to the user. Its purpose is to
encapsulate the logic of the game and hold its current state. It needs to
provide interface functions to the event listener and to the graphics drawing
functions. All of this is incorporated into a class called Game. In its most
abstract sense, class Game provides start, moveLeft, moveRight, moveDown,
rotate, and drop. Each of these functions does just as its name implies.
On the output end, class Game provides functions getScreenData, getLevel,
and getScore. Function getScreenData returns an array of integers 18 high
and 10 wide. Each integer corresponds to what block should be placed in each
grid position. A 0 indicates that no block is currently in the grid position, and
the numbers 1 through 7 indicate that there should be a block whose color is
decided by the number. Function getLevel returns the level of play that the
player has worked up to. Completing 10 rows moves the player to the next
level. The getLevel function is used by the event listener to determine how
quickly to automatically drop the pieces, and it is used by the graphics drawing functions to indicate the level to the left of the playing board. Function
getScore is used only by the graphics drawing functions so that they may
post the score to the left of the playing board.
3.5
More On the Game Class
publicThere is much more to class Game than just its interface functions. It
contains all the functionality of the game of tetris. Take a look at the header
file for Game found below in order to see all of the private methods and data
members used to implement the video game’s internal structure.
Class Game is composed of a Board object, a pointer to a Shape object,
and some other data members such as the row and column where the active
4
piece is located. The function isValidMove( Shape*, int, int ) is of special
interest. When the user requests a move, the move must be validated before
allowing it to happen and propgating its effect on the rest of the game. If the
attempted move is invalid, such as moving the active shape off the side of the
screen, the program would surely malfunction. So, if a move is requested, the
function performing that move queries the isValidMove function. It passes
the shape, which knows its own orientation, and the row and column of the
upper left hand corner of the shape in the move under inspection. It also has
access to the Game’s Board. The function applies the shape to the board and
checks a number of things such as the overflow on the left, right, and bottom
borders, and a collision with squares that are already occupied.
3.6
The Header File: game.h
class Game{
p:
Game();
//functions called by the keyboard listener
void start();
void stop();
void rotate();
void moveLeft();
void moveRight();
void moveDown();
void drop();
//function called bythe screen drawer
int** getScreenData();
//returns the screenData array
bool getGameOver();
//returns whether the game is over
int getLevel();
//how fast should the pieces fall?
int getScore();
void reset();
private:
void updateScreenData(); //updates the screeData array for use by SDL
//call these when a piece is finished falling
void addShape();
//generate new shape and put at top of grid
void removeRows();
//delete the complete rows and shift everything down
bool isValidMove( Shape *, int, int );//tests the shape on the board
void printTextScreen();
void printScore();
//used for console based game
//prints scoring data in the console
5
private:
Board b;
Shape *s;
int row, col;
int** screenData;
//private data members
// the intelligent board class
// the active shape
// top left grid position of the shape s
// contains the board and the active Shape s
int score;
int* rowCounts;
//player’s score
// 0-total rows, 1-single rows, 2-double rows, etc...
bool shapeIsActive;
bool gameOver;
bool textVersion;
int errorType;
bool commentsOn;
};
// true if a shape is falling
// becomes true when board fills up
// set to true in constructor for text game
//indicates the type of out-of-bounds error
//print console information while running
3.7
The Shape Class
Another integral part of the program’s structure is its reliance on the Shape class.
Class Shape is an abstract base class which contains most of the characteristics and
functionality of a shape. There are seven classes derived from Shape: bar, bird, box,
left dog, right dog, left periscope, and right periscope. Each of them implements its
own setOrientation function as a virtual function. In the program the specific shapes
are referred to polymorphically through a Shape pointer. This functionality was one
of the biggest benefits of using C++ over C to program Tetris.
4
Conclusion
Fungustris was a definite success! The three segments of the program work together
seamlessly and provide for a top quality Tetris clone. Fungustris has basically all
the functionality of the true game: all of the same pieces, the same controls, the
same scoring and disappearing rows, and the same increase in speed as the levels progress. It is also quite visually pleasing thanks to the SDL’s capabilities in
displaying regular bitmapped images which we were able to design using standard
image editing software.
The object-oriented design made the game a pleasure to create. C++ was the
perfect language thanks to its encapsulation techniques, its virtual functions, and
especially its backward compatibility with the SDL libraries.
6
Fig. 1. A screenshot of Tetris implemented with the SDL
5
Version Two
One of the biggest strengths of our program is its ease of modification. If we want
to go back and change some of the logic, we must simply add or modify functions in
the Game class. If we want to add new shapes, something that might make the game
a little more interesting and unique, we must simply add new classes descending
from class Shape and add their ”new” declarations to the switch statement in Game.
They would then function properly throughout the whole game because it is coded
so as to be independent of whatever shapes it might be asked to use. Modifying
the appearance of the game would probably be the simplest and most noticeable
change. We can edit the images used to build the board, the pieces, and the score
and level digits with the most basic of image editing programs. Version two will
most likely be Piratetris.
7
Adding sound to the game could make it much more enjoyable. It might be as
simple as playing a background song constantly, adding in short clicks when keys
are pressed, and adding friendly error sounds when a move cannot be completed.
Piratetris would also have an ”Arghh!” when the player scored a ”Tetris”.
6
References
I. The SDL Documentation Project: http://sdldoc.csn.ul.ie/
Provides basic documentation for the SDL libraries and their functions.
II. Bjarne Stroustrup. The C++ Programming Language. AT&T Labs, 1997.
Core C++ information and methods.
III. SDL Library - Video: http://www.chs.rit.edu/ benjamin/desktop/webpages/video/video.html
Provides a closer look at the SDL Video Library.
IV. H. & P. Deitel. How To Program C++. Prentice Hall, 2001.
In depth look at C++ class programing.
V. John Hall. ”A Crash Course in SDL”. Specialized Systems Consultants.
Seattle, WA. 2001.
Introduction to programming with Simple DirectMedia Layer.
8
7
About the Authors
Fig. 2. Authors Matt and Robert
Matt Corgan is currently studying Computer Engineering as a junior at the
University of Notre Dame. He was born and raised in Gaithersburg, Maryland and
enjoys skiing, biking, road trips, Bruce Springsteen’s music, and eating crabs for
hours. Matt currently works in the Management Information Systems computer
laboratory at Notre Dame. In the past he has done lawn-service, catering, and has
spent two summers with the Heat Transfer and Alternate Energy Group at the
National Institute of Standards and Technology. At present his plans for the future
lean towards software engineering in the Rocky Mountains.
Robert Bruggner is a native of Havana, Fl. and constantly asks himself how
he ended up in South Bend, In. He’s studying Computer Engineering but his real
intrests lie in sound and audio work (recording, mixing, playing). When he’s not
working (and even when he should be ), Robert can usally be found playing frisbee
(ultimate and/or golf ) with those crazy arts and letters hippies and loves every
minute of it. Classically trained in piano and an avid fan of talking in third person,
Robert hopes to live on a coast somewhere after graduation.