OOGA (Object-Oriented Game Architecture)
Games are an increasingly important medium in terms of international use, cultural impact, and profitability. Arguably, gaming has also driven many recent advances in computer hardware and are finally gaining acceptance within the academic community as an area worthy of study. And why not? Games contain all of the basic elements taught in computer science and commercial game engines are becoming increasingly complex software systems. The focus of this project is not to build commercial quality games, but you will experience all of the same basic concepts by building these games.
Today many popular games have an amazing number of variations in an effort to "localize" or tie in to other popular products. Beyond that, many games provide prequels or sequels or people simply make up their own rules to supplement the official ones. For really popular games attempts are made to re-energize it by creating variations that can modernize, shorten, or encourage cooperation --- they are even creating mashups of different games!
Deliverables
Each week you will have something due:
- Plan: plan project, design initial APIs, agree to standard file formats
- Sprint 1: implement the team's planned first release features
- Sprint 2: implement the team's planned second release features
- Complete: implement the team's complete functionality
- Final Demo: implement a variety of games to show off the design's flexibility
- Analysis: reflection on the project
With each deliverable:
- each team will demo their progress to their cohort teams and one of the Teaching Team
- individually you will reflect on your progress and teamwork
Specification
In teams, write a Java program, using OpenJFX, that allows users to play a variety of games within a similar genre. Differences between games must be determined solely by game specific configuration data files (these files can facilitate the use reflection to specify game specific Java code to run during the game, but there cannot be separate setup Java code for individual games). Indeed, one of the primary goals of this project is to identify common characteristics shared by the games within your chosen genre and to design a single framework (i.e., coordinated general classes designed to be extended or to delegate to abstractions that do the actual work) capable of supporting as wide a variety of specific games as possible.
You can choose from the following games or genres:
- Board games (e.g., Monopoly, Risk, Clue, etc.)
These games are themselves complex and each have many variations, so doing this option would focus on a single game type instead of all possible kinds of games.
- Card games
(e.g., Solitaire, Poker, Fluxx, etc.)
These games range from easy to complex and each have many variations, so doing this option could focus on either a single game type or many different kinds of games.
- Classic Video games
(e.g., Pac-Man, Tower Defense, Video Games, etc.)
These games range from easy to complex and each have many variations, so doing this option could focus on either a single game type or many different kinds of games.
- Coding Games (e.g., Top Coding Games, Corewar, Bot Arena, Osmo Coding, etc.)
These games are themselves complex and can vary in many ways, so doing this option would focus on a single game type instead of all possible kinds of games.
- Grid-based games (e.g., Bejeweled, Candy Crush, ChuChu Rocket, etc.)
These games range from easy to complex and each have many variations, so doing this option could focus on either a single game type or many different kinds of games.
- Physics-based games (e.g., Pinball, Pool, N-Jump, etc.)
These games are typically easy to implement because they share the same physics algorithms, so doing this option would focus on many different game types.
- Scrolling Platformer games (e.g., Super Mario Brothers, Doodle Jump, Zelda, etc.)
These games range from easy to complex and each have many variations, so doing this option could focus on either a single game type or many different kinds of games.
- Strategy games (e.g., Checkers, Connect4, Othello, etc.)
These games are typically easy to implement and share the same AI algorithm for playing against, so doing this option would focus on many different game types.
Your task is to create a design that can accommodate many variations in the behavior (as well as the details) of individual games, while using the basic play expectations within your game or genre to structure your work so the code does not have to be completely abstract. To verify the generality of your framework, you will need to demonstrate games that differ in as many ways as you can think of. If you are not certain about the abstractions at the start, think as concretely as possible about how to implement two different games, paying special attention to the code that they would have in common and the code that would differ. Then figure out a way to design something that captures that difference as an abstraction that can be used by the common parts so that, by the end of the project, any differences can be configured from a data file.
An Example
Consider the (un)popular game Monopoly and its official rules (which most people have likely never actually read) that determine:
- setup of the board and players starting funds
- interactions within the game
- how players win (based on the game's goal)
- how players lose (based on running out of funds).
Within the goals of these rules, there are tremendous variation that can completely change the game play as seen in variations like these:
These games (and many other Monopoly variants) share common traits, but allow for different behavior within them, such as:
- Dice: type of dice (2 6-sided dice, N-sided dice, even the Speed Die); extra turn after rolling doubles; go to jail after too many doubles in a row
- Funds: money bills; electronic money; starting amount per player; income-tax rate, etc.
- Properties: order on board; which property group, including utilities/railroads; cost; house/hotel prices; rents; mortgaging/un-mortgaging
- Go: collecting $200 or other amount; landing directly on it; when passing enables player to collect money
- Landing on properties: buying; auctioning; paying rent based on mortgage/monopoly/house/hotel status
- Chance/Community Chest: different actions on cards; keeping cards (e.g., get out of jail)
- Jail: various ways to get into and out of jail; various options for money paid to get out of jail
- Houses/hotels: cost; buying; building shortages
- Turn-based action: roll and move; moving again based on game actions; other results of move; any player can manage property
- Joining a game: choose token; choose first to go; choose starting position; choose number of tokens per player; choose "local" variation separate from game rules
By now, it should be clear that your design must be fairly general so that it will be possible to support any of these varieties without changing any of your code. If you were just building a program to implement a basic Monopoly game, you might have classes called "Utility", "Dice", or "Chance". Instead, your framework should use more general terms to indicate more possibilities, like "CombinableProperty", "Randomizer", and "Action", and allow them to be instantiated with options or subclassed to make a specific kind of game. This is especially important when designing the protocols for how parts of the game interact.
Games that have a similar look and feel, but differ only in storyline are easy to implement. For example, Dukeopoly is a variation that can be implemented simply by changing the text and images used in the basic game. A great many different games have successfully been made in this way (localizing Monopoly's properties has been popular since the game was first invented), but they are exactly the same game. You should support MODs simply by not hardcoding your values, but do not limit your design to support only MOD-style extensions.
APIs
The many variations within your game or genre typically differ in certain ways that you can exploit to create APIs that allow specific features to be "plugged into" your general frameworks, thus providing for the extensibility to support as many different variations as you can. Put another way, the core should be a platform that exposes APIs for extending a game in different ways so that concrete pieces can be created and combined to make a specific playable game.
At a high level, this program can easily be divided into at least the following APIs:
- Engine. framework of general classes to support any kind of game within the genre
- Data. classes that read configuration files, assets, and preferences to error check and assemble the correct combination of engine classes
- Player. program that loads the game data and uses the game engine to run a particular game
Engine
Games have many common characteristics that can be shared in a framework so that creating a new game requires only choosing the things specific to it. The engine provides a set of classes that handle these common tasks in a general way that can be tailored to any particular game. Common aspects to consider include:
- setting up, running, and completing levels or stages
- rules, interactions, or events
- goals, both small and large
- progression through the game
- behaviors or animations
- game status information
- game genre specific concepts
Note you do not want your framework to be over specialized — each game genre encompasses a wide variety of games and you want to make sure there are plenty of places to plug in custom code to build new kinds of features. The problem of providing significant built-in functionality while still making it flexible enough to support a variety of games is the key design challenge.
Data
No modern game hard-codes its data in source code, so the configuration of any game variation should be represented using data files. In addition to the obvious simple data variations (like strings or images displayed, point or item values, or size or shape of the game play area), think about how to represent and substitute game rules, interactions, or goals. No matter what genre you choose, basic characteristics of the look and feel of the game should be able to be easily changed:
- text displayed in the GUI (e.g., to localize it or display it in a different language)
- graphical icons used in game (e.g., to turn a SciFi game into a political statement)
- point values of game objectives (e.g., for tuning the game or to make a bonus level)
- number of levels, their starting configurations, and the order in which they are played
- keys used for interaction (e.g., to accommodate preferences, multiple players on the same keyboard, or using multiple controllers)
- basically any other data you can think of that might change!
The exact format and content of these configuration file(s) is to be determined by you, but you must use a standard file type and parser (rather than developing your own) such as:
- Properties File, a list of key/value pairs, specific to Java, but easy to parse and use
- Comma-separated Values, CSV, like those used to represent spread sheets, that can be parsed using a third party library
- eXtensible Markup Language, XML, an open, industry standard, flexible format, that can be parsed directly within Java
- JavaScript Object Notation, JSON, an open, industry standard, flexible format, that can be parsed using a third party library
You will need to determine what data needs to be represented in these files, to load all the data for a particular game and assemble concrete classes, to handle any errors in the data that might occur, and to read and generate them algorithmically. Defining the standards for these files and insulating the rest of the program from your format choices are key design challenges.
Player
Users need a GUI to select a game from the possible options, to coordinate the game play, to display game stats, and to let players know when they lose or win the game. Specifically, it should allow the user to:
- view the available games, including at least the game's name, image, and description
- select and play the game repeatedly without quitting
- customize the game before playing, such as colors, images, themes, number and names of players, key mappings for actions, and possibly turning rules on or off
- play the chosen game and see dynamically updated game status information (i.e., heads up display (HUD))
- switch between games repeatedly without quitting
- play multiple games at once
- select language for text, color modes (dark or other themes), game window size, and possibly other preferences
This player can be as simple or complex as you are interested in making it, depending on whether or not you want to add embellishments beyond simply playing games (like accounts, ratings, comments, etc.). The problem of providing a player that fits all possible games (e.g., high score can mean the highest or lowest value depending on the game's goals) and possibly generalizing beyond games completely (e.g., what is the difference between a game and a book when you are rating it?) are key design challenges.
Expectations
Your overall grade will be based on the program's design, the functionality of your games, and the overall complexity of the genre and features you choose to implement (i.e., Checkers or Monopoly are more complex games than Black Jack or Breakout). So everyone should be able to create a complete, well designed, program by picking a less complex game genre if necessary.
To review, the basic specifications are to create:
- Program that can play a variety of games of the same type or genre
- General framework of classes designed to allow for maximal flexibility with minimal duplication and hard coding
- Three significant example games that demonstrate the flexibility of your design by differing significantly in their behavior within the genre (such as test/simple, basic/moderate, and complete/complex versions)
- One example game that is a MOD, differing primarily in all the simple data values rather than in the rules or goals
Additionally, your team must do something "easy", "mild", and "challenging" to stretch your design further and to differentiate your project from others. These extensions must further the good design of your program by being planned into the project, sometimes even from the start, not simply be added at the last minute.
Some ideas include:
Basic
- High Scores. Keep track of games' high scores through successive runs of the program until the user clears it.
- Preferences. Allow users to set preferences specific to each game played (like preferred colors, player tokens, starting configurations, etc.).
- Load Games. Allow users to add new game variants by loading a set of configuration files or load a previously saved game to resume playing it.
- Save Games. Allow users to save the current state of any active game, so they can suspend a game, come back later, and load the game state back in to continue playing.
- Multiple Games at Once. Allow users to play multiple, possibly different variants, of games at once while running the program.
Mild
- Dynamic Game Rules. Allow users to change the rules of the game during the game, perhaps after voting or otherwise confirming that everyone playing understand the rule change.
- Artificial Players. Allow to select "smart" players to play against. Note, depending on the genre, this may be easy or extremely difficult. Also, making players that appear "smart" but beatable is a challenging problem, so providing levels of intelligence and ways to debug these agents graphically is desirable.
- Player Profiles. Allow users to log in, choose an avatar to be used within the game player, view personal high scores, and save their preferences (e.g., name, password, image, age (if parental controls are implemented), and favorite variants, tokens, colors, etc). Player information should be saved between runs of the program.
- Social Center. Offer social aspects by allowing users to rate, comment, or generally collaborate while playing games. Note, this will require a connection to a central database (or files that simulate a database) to keep track of user information that persists beyond the running of a single program.
- Dynamic Game Content. With fewer people willing to pay for games without trying them first, it is useful to have a model that allows game content to be "unlocked" or updated after the game has been started. Consider different models, such free versus paid for game content, unlocking levels, power-ups, or tools based on achievement or pay, subscription service to enable serialized delivery of levels to create "infinite" games, etc. Note, this will require designing the content of you game in a more modular way as well as designing a general way to provide access to the content.
Challenging
- Game Area Editor. Allow users to design the game's initial configuration and its content dynamically using a GUI, rather than just editing text data files. Users should be able to load any existing data for editing or save their design in the common format.
- Networked Players. Allow users to find games over the network that are starting or start one and wait for others to join it. Update at any one computer should be made visible to all connected users. Note, this will require agreeing on a protocol of exactly what information to send over the network to represent what happens in the game.
- Save Game Data in the Web. Allow users to save and load game data using an online database or web server with REST API. Note, these use the JSON data format so you likely would also.
- Game Data Producer and Viewer. All current high-profile games keep track of what happens during game play and allow it to be viewed so levels can be improved. Note, this will require creating a way for the game designer to choose what to measure in the game (as well as providing standard measures) and then a way to load and visualize that data in a meaningful way later, including comparing two different runs of the game.
- Multiple Views. In addition to the multiple view required within OpenJFX, allow multiple game views in different mediums like text, HTML, or even mobile.
Design Goals
Thinking deliberately about each class' public methods as an Application Programming Interface, or API, for others on your team can really improve how you approach the task of programming and design. One way to view an API is as a contract to provide a service and, once such a contract is in place, developers are enticed to use the API because they know they can rely on its stability. The design of the APIs is arguably the most critical part of designing a program, because it affects the design of other components dependent on them. So focus on organizing your program as a collection of interconnected services that work together.
This assignment provides a context to begin thinking about larger scale design issues:
- Develop Programmer's Interface. Change your focus from simply writing code that works to writing APIs, code that serves other parts of the program (other team members) and allows those parts freedom to implement without regard to the internal workings of your code.
- Design Patterns. Find the right design to help you solve specific problems and adapt it to your specific situation taking into account its trade-offs.
- Data Driven Design. Use data files to drive the flexibility of as much of your code as possible rather than hard-coding it.
Resources
- General Framework Design
- Designing Game Engines
- Understanding Games