OOGASalad
What if the behavior of your system was largely controlled by the configuration of its plugins? What power would that give you? — Robert C Martin
Specification
In teams, write a Java program from scratch using OpenJFX (without FXML), that provides a No-Code authoring environment for game designers to build 2D games of a specific genre using a interactive, visual tools that require minimal programming, such as:
- choose and place game elements (i.e., what things will be in the game, their starting positions and values, etc)
- setup graphical elements (i.e., background, images/colors/shapes used for game elements or board spaces, etc)
- tweak settings (i.e., point values, game timing, projectile/obstacle/objects speed or number, etc)
- set game rules (i.e., what actions are allowed, what happens when two objects intersect, etc)
- set interaction types and reactions (i.e., what happens when a key is pressed or the mouse is moved, without hardcoding specific keys, and what object is controlled)
- set goals for the game (i.e., how to advance within the game, how to win or lose the game, etc)
- determine the order of advancement (i.e., what level or stage follows the current one)
- set instructions, splash screen, player setup, level bonuses, etc
Game Genre
Example game genres include:
- Basic games: these games are each relatively easy to implement, so these options would focus on many different game variations within the genre
- Card games
(e.g., Poker, Trick-based, Phase-10, Uno, etc.)
- Video games
(e.g., Centipong, Tetris, Tower Defense, etc.)
- Grid-based games (e.g., Bejeweled, Candy Crush, etc.)
- Block pushing puzzle games (e.g., Atomix, Sokoban, Rush Hour, etc.)
- Physics-based games (e.g., Pinball, N-Jump, etc.)
- Scrolling Platformer games (e.g., Super Mario Brothers, Doodle Jump, etc.)
- Strategy games (e.g., Checkers, Connect4, Othello, etc.)
- Google Map games (e.g., seven examples, ten more examples, Worldle, etc.)
- Complex games: these games are each relatively complex to implement, so these options would focus on the many variations possible within a single game
- Card games
(e.g., Solitaire, Fluxx, Slay the Spire, etc.)
- Video games
(e.g., Pac-Man, Street Fighter, Plague Inc, etc.)
- Grid-based games (e.g., ChuChu Rocket, SpaceChem with suggestions and tournaments, etc.)
- Physics-based games (e.g., Pool, Angry Birds, etc.)
- Scrolling Platformer games (e.g., Zelda, Evoland, Warcraft, Civilization, etc.)
- Strategy games (e.g., Chess (shotgun, human, and AI suggested variations), Settlers of Catan, etc.)
- Board games (e.g., Monopoly, Risk, Clue, etc.)
- Coding games (e.g., Baba is You, Corewar, Bot Arena, etc.)
- Mashup games (e.g., Habro's Game Mashups, Breakout Fantasy Mashup, etc.)
Data Files
No modern game hardcodes individual level data into its source code, likewise your game variations should be determined solely by configuration data files that also activate general game features (these files can facilitate the use reflection to specify game specific Java code to run, but cannot require specific Java setup code for an individual game). Games should be saved in a format that allows them the be loaded for additional editing or played by a user (perhaps using a separate program that might be run on the same machine as the editor or it might get access to game files via the web). The exact format and content of configuration file(s) will be determined by your team, but it must be a standard file type with a 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, but we recommend a third party library to help serialize objects
- JavaScript Object Notation, JSON, an open, industry standard, flexible format, that can be generated and parsed using a third party library
Example Games
Create a variety of games (as a team and individually) that differ primarily in their behavior to demonstrate the flexibility of your project's design:
- 1 test game that shows most of the project's features and is very easy to play
- 2 complete games with clear variations in rules, goals, and interactions determined completely by different data files
- 1 MOD game that differs primarily in all the basic data values rather than the functionality (although much of that should be driven by data files as well)
- 8-10 interesting games, one by each team member that help demonstrate your project's design flexibility
Game Player
Create a separate game player program that allow users to:
- show any number of available games automatically (i.e., adding a new game to play cannot require changing any Java code)
- see information about each game, including its name, author, description, and image/icon
- select any game to play repeatedly without quitting
- pause a game during play (note, depending on the game or its goals, you may want to blank the screen when paused to prevent "cheating")
- see dynamically updated game status information (i.e., heads up display (HUD))
- keep track of each game's high scores through successive runs of the program
- save their progress in the game to restart later (perhaps only at specific save points)
- play multiple, possibly different games at once
Note, this program can be as simple or complex as your team is interested in making it, depending on whether or not you want to add embellishments beyond simply playing games (like accounts, ratings, comments, etc.).
Separate Style and Language
Any colors, fonts, or other appearance styling should be able to be changed dynamically between at least three different options (such as Dark or Light modes, Duke or UNC colors, larger fonts for presentation mode, etc.). Any text displayed should be able to appear in at least four languages (Pig Latin is a popular option or you can use Google Translate if no one on your team can do it).
Testing
Test your program using JUnit and TestFX (with assertions both for typical situations and all possible thrown Exceptions) to separately verify the Model and View work as intended. Generally, aim to create a test class for each of your concrete classes with at least two well-named tests for each non-trivial public method (more than two are expected for complex methods) and try to achieve at least 85% Line test coverage of each class.
Extensions
Additionally, your team must include features from each category below to stretch your design further and to differentiate your project from others. These extensions must further the good design of your program by being integrated into the project through abstractions, not simply added at the last minute as classes or methods that require changing existing APIs or code that should be closed.
Some ideas include:
- Basic (2 expected)
- Preferences. Allow users to set preferences specific to each game played (like preferred colors, player tokens, starting configurations, key to action configurations, language, etc.).
- 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.
- 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, language, age (if parental controls are implemented), and favorite variants, tokens, colors, etc). Player information should be saved between runs of the program.
- Easy MOD Editing. Allow users to easily change many related data values at once (e.g., graphical icons, text, goals to turn a SciFi game into a political statement or a violent game into a peaceful one).
- Dynamic GUI Organization. Allow users to rearrange View layout, open and close components, and customize toolbar actions; as well as save these preferences between runs of the program(s).
- 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.
- Help System. Create a substantial help or tutorial system, perhaps providing templates or wizard dialogs to guide a designer through creating a game.
- Artificial Players. Allow game designers to easily create smart enemies to oppose the player.
Note, depending on the genre, this may be easy or extremely difficult. Also, making agents that appear "smart" but beatable is a challenging problem, so providing ways to debug these agents graphically is desirable.
- Incorporate AI APIs. Allow users access to popular AI tools to develop elements of their game like ChatGPT, DALL-E, DeepComposer, or Murf by integrating their APIs into your Authoring Environment. For inspiration, check out the Material Generator tool just released by Roblox.
- Live Game Editing. Allow game designers to interactively build their game while it is running. Note, in this case, you will likely need to embed all or part of your authoring environment within your player.
- 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 add-on packs 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 (1 expected)
- User Permissions. Offer different user roles that provide different access to program functionality (e.g., guest access to a few games, game author access to see usage stats about their game(s), admin access to see data about the users playing the games, add/remove users or games, etc.). Note, this will require a connection to an online database (or files that simulate a database) to keep track of user information that persists beyond the running of a single 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 an online database (or files that simulate a database) to keep track of user information that persists beyond the running of a single program. Real-time collaboration will also require some very basic networked connections (if you are not properly using a real-time database).
- Networked Players. Allow users to find games over the network that are starting or start one and wait for others to join. Updates on 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.
- Play Modes. Allow users to play a challenge mode, play through any number of randomly selected levels or even games, generated from those that have been created, or a tournament mode, play against other players competitively by displaying others' current or recent scores.
- Shared Editor. Like Google docs, allow multiple people to edit a game's design together. An update at any one computer should be visible immediately to all connected users. Where appropriate, allow users working on the same game to chat directly as well. Note, this will require agreeing on a protocol of exactly what information to send over the network to represent the game's design, but it is not as time critical as a networked game.
- Game Data 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.
- Make a Game out of Making a Game. Like MineCraft, gamify the process of creating the game. Note, this will require design of a different kind to determine what earns "points", what the rewards are, etc. Even better will be if this game runs on your standard game engine!
Submitting Your Work
Use GIT to push your team's implementation to the master
branch of the provided, shared, oogasalad_teamNN
repository hosted in the course's Gitlab group.
As your submission for this project, use GIT to add
, commit
, and push
the following:
src/main
folder: all project code and internal configuration files
src/test
folder: all JUnit test code and test specific configuration files
doc
folder: all design documentation and any supporting images
data
folder: all example game configuration files
- top-level (no separate folder): project README, and otherwise no other files created by you
Your code is expected to follow the course coding conventions and follow Javadoc conventions.
Your team's project GIT repository must show many, purposeful, commits from all team members rather than just one or two large "kitchen sink" commits and marathon merging or redesign sessions. Specifically, we will be looking for deliberate attempts to regularly:
- integrate each other's work
- refactor code to improve its design
- test your functionality
We strongly suggest using the course's suggested GIT workflow for teams to manage this process.
Deliverables
Each week you will have something due:
- Plan: plan project, design APIs, agree to standard file formats
- Sprint 1: implement the most basic version of the APIs, focusing on a simple, testable, core
- Sprint 2: implement the team's planned first priority features
- Sprint 3: implement the team's planned second priority features
- Complete: implement the team's complete functionality
- Demo: create additional example data files and record a demo of the games chosen to show off your design's flexibility
With each deliverable:
- each team will demo their progress to either the class or one of the Teaching Team
- individually you will reflect on your progress and teamwork
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)
Games that have a similar look and feel, but differ only in storyline are easy to implement. For example, Duke-opoly 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 be able to support these simple MODs (simply by not hardcoding values within your code), but do not limit your design to only these kinds of variations.
But Monopoly has an amazing number of variations, some of which completely change the game play in an effort to tie it into popular trends and products, modernize it, shorten it, or even encourage cooperation (people can even propose their own rules). For example:
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
- Properties: order on board; which property group, including utilities/railroads; cost; house/hotel prices; rents; mortgaging/un-mortgaging
- Property interactions: buying; auctioning; trading; paying rent based on mortgage, monopoly, house, or hotel status
- Chance/Community Chest: different actions on cards; keeping cards (e.g., get out of jail)
- Houses/hotels: cost; buying; building shortages
- Board: arrangement; number of locations; moving between locations; actions when landing on specific locations
- Go: collecting $200 or other amount; landing directly on it; when passing enables player to collect money
- Jail: various ways to get into and out of jail; various options for money paid to get out of jail; whether or not player can do business while in jail
- 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
It should be clear from this brief description that a design must be fairly general in order to support any of these varieties without changing any code, just selecting different subclasses. If you were just building a program to implement a basic Monopoly game, you might have classes called "Utility", "Dice", or "Chance". Instead, your design 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 protocols for how parts of the game interact.
Your task is to create a design that can accommodate many variations in the behavior 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 your design's generality, 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 rather than special case code.
Design Specifications
Your overall grade will be based on the program's design, the diversity 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 Solitaire or Breakout). So every team, no matter the size or ability, should be able to create a complete, well designed, program by picking a less complex game genre if necessary.
Ideally, a well-designed program will make implementing new features easier so, when choosing a new feature to implement, look for something that fits into your design or refactor your code first to accommodate it. Specifically, your design should be thoughtful and intentional: clearly avoiding duplicate code structures and making it easy to add new game variations without changing the existing code.
Adding functionality not related to an abstraction or resulting in poor code that diminishes your overall design efforts will not be rewarded. Specifically, the credit you receive for a functionality feature will be in proportion to how clearly it shows that your core classes are closed to modification while open to extension using abstractions to remove dependencies on concrete classes. Thus, a program with fewer features, but plenty of clear paths to easy expansion, is worth more than a program with many features but lacking clean code and good abstractions.
In addition to following the course Code Design Habits Checklist, your project design should clearly show the your progress learning the topics we have discussed in the course:
- Application Programmer's Interface (API). Think about your code as a service to other parts of the program (other team members) that allows those parts freedom to implement new features without regard to the internal workings of your code
- Model View Controller (MVC).
Create a cleanly structured GUI that separates the view from model with controller(s) that mediates the flow of information (including errors)
- Clean code. Write your code primarily for communication: to avoid duplication, to support your team mates, and so that it can be easily understood by others
- Exceptions. Communicate errors in a thoughtful, intentional, manner rather than returning
null
or other error prone values, possibly using Java's Optional
- Encapsulation. Key implementation details must be hidden such that they can be changed without impacting any other classes
- Build abstractions. Create inheritance hierarchies to define common methods that can be implemented in multiple ways in separate concrete classes
- Interfaces. Be intentional about how you expect other classes to use your object by controlling its available methods
- Immutability. Be intentional about what data you expect to be modified by explicitly restricting what other classes can change, perhaps by using Enumerated types, Records, or interfaces
- Data Driven Design. Use data files to drive the flexibility of as much of your code as possible rather than hard-coding it, using at least resources, properties, and styles
- Design Principles. Use SOLID Design Principles to guide your communication between the main parts of your project using abstractions to ensure that project details can be more easily changed
- 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
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. In other words, 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, these programs are multiple views of the backend and can be easily divided into at least the following APIs:
- Frontend
- Authoring Environment: program of visual tools for placing, specifying, editing, and combining general game elements together to make a particular game
Key design challenges are providing a flexible and extensible GUI that makes it easier to define a game than directly editing text data
- Player: program that loads the game data and uses the game engine to run a particular game
Key design challenges are 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?)
- Backend
- Engine: framework of general Java classes to support any kind of game within a specific game genre
Key design challenges are providing significant built-in functionality while still making it flexible enough to support a variety of games by ensuring plenty of places to plug in custom code
- Data: files, assets, preferences, and code that represent a particular game
Key design challenges are providing
standards for what data needs to be represented in files, loading the data for a particular game and assemble concrete classes, handling any errors in the data that might occur, and insulating the rest of the program from your format choices
Ideally, an API should not be changed after it is defined because that affects other's code. If, during the course of the project, an API must be changed, the change and its reasons must be clearly described in a separate file, doc/API_CHANGES.md
, that is updated regularly.
Individual Responsibilities when Working as a Team
This project requires steady, consistent, work — only by putting in consistent time each week will you see measurable progress and not have to pull "heroic" all-nighters.
Although this is a team project, everyone has individual responsibilities to the team that can be summed up as follows:
- actively participating in all team meetings
- regularly contributing clean code to the shared repository in reasonably sized chunks
- solving and coding at least one "interesting" design problem
- helping a teammate at least once by going above and beyond
Unfortunately conflicts are likely to occur, so please let the Teaching Team know as soon as possible — even if it has happened just once or twice since it is better to deal with the situation early rather than having a disaster at the end when little can be done to get back on track.
Resources
- General Framework Design
- Understanding Games
- Designing Game Engines
- Example 2D Game Authoring Environments