Final Project: / Virtual Arcade Cabinet
Written By: / Jude Nelson
Run By: / Eric Stewart
Overview
Back in the 1980s, video arcade games were in their prime. Local restaurants, pubs, and arcades lured customers with all of the latest titles: Pacman, BattleZone, Galaxian, Donkey Kong, Tempest, Gee Bee, Dragon's Lair, Dig Dug, Tron, Asteroids, Centipede, Defender, and more. (Un)fortunately, the rise of home videogame systems and home computers relegated these gems to the back storage rooms of many establishments. They are not forgotten, however--even today, arcade cabinets are collected by enthusiasts and arcade ROM emulation systems such as MAME allow my generation to experience these relics first-hand on modern hardware. In this semester project, you will be creating a re-usable and modular game engine in Java that will allow enthusiasts to quickly implement and bring back to life the videogames of lore within the comfort of our own homes. The focus of this project is not on the games themselves, but on the engine that will allow us to emulate these games.
Game Engine Intro
From Wikipedia (http://en.wikipedia.org/wiki/Game_engine):
"A game engine is a software system designed for the creation and development of computer and video games. There are many game engines that are designed to work on video game consoles and desktop operating systems such as Linux, Mac OS X, and Microsoft Windows. The core functionality typically provided by a game engine includes a rendering engine (“renderer”) for 2D or 3D graphics, a physics engine or collision detection (and collision response), sound, scripting, animation, artificial intelligence, networking, streaming, memory management, threading, and a scene graph. The process of game development is frequently economized by in large part reusing the same game engine to create different games."
The game engine you will create for this project will be relatively simple, but it will be sufficient to emulate most 1980's arcade games. As it turns out, 1980's arcade games have a lot in common:
· They all have at least one user-controlled entity (the user's avatar).
· They all have 2D representations (with the exception of BattleZone and Tempest, which are wire-frame 3D).
· They all have a consistent scoring system.
· They all have a user-modifiable high score table.
· They all have a playfield of non-user objects, each with a specific, pre-defined behavior.
Some of the objects are scenery and are just for show; some are entities that can "kill" the user's avatar upon physical contact; some impede the user's avatar's movement; some can "kill" other objects upon contact, etc.
· They all have a simple goal the user must complete via performing a sequence of actions through their avatar in the game.
· They all have a way to start and stop at any time.
· They all have some sort of sound effects.
· They all have a series of buttons (and sometimes joysticks) from which to receive user input.
· They all have a concept of "lives".
· The game ends when the user spends all of his/her "lives."
Since these games have a lot in common, we can create a game engine that handles all of this functionality. Then, to implement a 1980s video arcade game, all we have to do is create a class that describes to the engine the specifics of the game and how to go about recreating it. The idea is to make all of these details invisible to the game engine itself, while being flexible enough to accommodate a wide variety of videogames. The game programmer should have to specify as little as possible about the game to make it work.
The Arcade Game Engine
A 1980s arcade game, abstractly, can be described as a collection of actors (at least one of which is controlled by the user), a set of states, and mechanism to transition between states when needed. An actor is an entity within a game that serves a purpose relevant to gameplay. For example, in the game Asteroids, the wedge-shaped ship is the user-controlled actor, while all of the asteroids, alien ships, bullets, and explosions are game-controlled actors. A game state is simply the pre-defined behavior of the game under certain pre-defined conditions. Using our Asteroids example, the game starts out in the "title screen" state, during which the game engine displays the title of the game and possibly a computer-controlled demo of the game. When the user inserts a coin, the game transitions to the "game play state", where the game will respond to user input, and optionally play sound effects and update the game-controlled actors until the user has run out of lives. Then the game transitions to the "end game state", where the game informs the user that they have lost (or won). When this state terminates, the game may transition to the "enter your initials" state if the user has earned a high enough score to be entered into the high score table. This state (and the "end game state", if the user does NOT have a high score) transitions to the "display high score" state, where the highest 10 or so scores are displayed to the user. Finally, the game transitions back to the "title screen" state. There are many state transition possibilities in general, but this is one of the most common state transition patterns you will encounter (your game engine should not assume that every game behaves like this, however!).
The game engine should define at least one class that describes an actor. In 1980s arcade games, actors always have at least these attributes:
· position in the scene
· spatial dimensions in the scene
· a way to update itself periodically (e.g. what the actor does on a frame-by-frame basis if nothing interacts with it)
In our Asteroids example, an asteroid rotates slightly and moves slightly in a pre-defined direction once per frame. An explosion will radiate particles outward for a pre-defined number of frames before being destroyed by the game engine. The user's ship will try to get the user's input and act on it (if the user is inputting commands).
· a way to interact with another actor, based on the game state and the other actor's type and attributes
In our Asteroids example, an asteroid will split into two smaller asteroids if a bullet actor occupies the same spatial dimensions as the asteroid, but an asteroid will do nothing if it intersects another asteroid. If the asteroid occupies the same space as the user's ship, it will destroy the ship if the user is "alive", or will do nothing if the user is already dead.
· an avatar
This is a data structure that describes what the actor "looks like" in the playfield. In our Asteroids example, the user-controlled ship's avatar looks like a triangular wedge. An Asteroid looks like an amorphous polygon. An alien ship looks like a flying saucer. A bullet looks like a point. An explosion looks like a collection of points.
· a way to provide the scene with an avatar to render
There are other actor attributes, of course, but these are universal.
The game engine is responsible for:
· scene management
Managing and rendering the visible components of the game.
· sound management
Managing and playing back music and audio sound effects.
· input management
Getting valid user input in a timely fashion.
· object management
Retrieving and saving data to and from disk.
· actor management
Creating, destroying, and updating the actors, based on the state of the game and the attributes of other actors.
Scene Management
The game engine needs to have access to the Swing container on which you intend to render each frame of the game. Given a collection of actors, it should be able to render the avatar for each actor. The actor should only know how to give its avatar to this part of the engine, and the engine should be able to access the avatar for information on how to render it. This information can be an image, a geometric description, or a method to be called that will perform the rendering instructions directly. This part of the engine is NOT responsible for loading avatar information from disk, but it may optionally cache the information. This part of the codebase should be able to determine what state the game is in, so it can display things other than actor avatars for the user (e.g. the high score table, the title screen, etc.) Keep in mind, however, that the engine renders avatars, not actors (or anything else). Errors related to rendering should be handled and recovered from as elegantly as possible and only report irrecoverable errors to the user. The code in this section may optionally run in separate threads, so as to render a particular number of frames per second regardless of how light the system load may be.
Sound Management
The engine needs to be able to load or stream sound effects and music from disk via the Object Management code. It should be able to cache sound effects in RAM, but background music should be streamed. It should be able to handle errors and exceptions transparently and report an error to the user only if it cannot recover. The code that governs sound playback should be interruptible, so sounds can be stopped immediately if necessary. The sound management logic must appear to the outside as hardware-agnostic--that is, outside entities should not need to know anything about how the Sound Management code gets the sounds and plays them for it to be able to ask it to play a sound. Streaming sound will run in a separate thread (one thread per stream).
Input Management
The engine should read information from the keyboard and mouse and provide a hardware-agnostic description of user input to external entities. Information may include a description of mouse button states (e.g. clicked or not clicked), mouse position in the screen, key strokes, and (optionally) joystick position and button states. The engine should be able to quickly read user input (e.g. no noticeable delays) and store it in a canonical format--a format that every participant in the game engine understands. The Input Management code should handle key-bindings--instead of telling the game about which keys are pressed or where the mouse is, etc., it will instead translate key and mouse input into actions that the user-controlled parts of the game can understand.
The game definition will define which keys correlate to which actions, and how actions affect user-controlled actors. For example, the Asteroids game definition may tell the game engine to translate a "g" keystroke into a "rotate the ship clockwise" action to be forwarded to user-controlled actors. It will then declare that the user's ship will respond to the "rotate the ship clockwise" action by slightly rotating the ship. When the "g" key is pressed, the Input Management code will create a "rotate the ship clockwise" action and pass it to the user's ship actor, which will cause the user's ship to rotate. We say that the user's ship is "event-driven", as are all user-controlled actors in general. Event-driven programming is a paradigm you should explore to help you with this section: http://en.wikipedia.org/wiki/Event-driven_programming. You already have experience with it--Swing GUIs are the epitome of event-driven programming--only this time, you get to define how the events are propagated from the input hardware all the way up to the user-controlled actors via the game engine. Note that it is possible that the user-controlled actors may not be able to keep up with the propagation of actions, so they will need a way to temporarily store them until they can be processed.
Object Management (API)
The game engine should perform all of its interaction with the disk via this API. This API provides an abstraction from the Java I/O facilities, and should gracefully handle I/O-related exceptions and propagate meaningful but irrecoverable errors to the user. This API may implement internal caching, if needed.
Actor Management
The game engine needs a way to manage all of its actors. This section of the engine should provide facilities to create, look up, and destroy actors. Also, it should be able to tell every actor to update itself once per frame, and it should be able to tell every actor to attempt to interact with every other actor once per frame. This is how actor behavior and actor collision detection (and simple physics) are handled. The game engine should make no assumptions about how the actors will interact, nor about how likely an interaction may be.
The Game Engine Core
The core of the game engine is responsible for transitioning between states in the game, setting up and shutting down the various components of the engine based on what game the user wishes to play, and propagating messages (e.g. errors) to the user. It should make absolutely no assumptions about the specifics of the game, but it should be able to set up a game based on a user-supplied description of the game.
Game Definitions
You should provide a common way to describe to the game engine what a particular 1980s game is. Specifically, a game definition would describe at least the following:
· what the avatars of each actor look like,
· which keys or mouse behaviors trigger which actions,
· how the user-controlled actors respond to each action,