# Asteroids multiplayer
A game of asteroids game with single- and multiplayer support.
## Table of Contents
* [About the Project](#About-the-project)
* [Built With](#built-with)
* [Getting Started](#getting-started)
* [Prerequisites](#prerequisites)
* [Installation](#installation)
* [Design Description](#design-description)
* [Package breakdown](#Discussion)
* [Control Package](#control)
* [Model Package](#model)
* [Util Package](#util)
* [View Package](#view)
* [Evaluation](#evaluation)
* [Teamwork](#teamwork)
* [Extras](#extras)
## About The Project
This project is the final project for the course Advanced Object Oriented programming performed at the RUG. The project is about a game called asteroids, where players are able to play as a spaceship in space. The aim is to avoid collisions with asteroids and shoot asteroids to destroy them. Players earn points by either shooting asteroids or killing other players (in multiplayer).
The key feature of the game is the multiplayer extension, where players are able to compeat over the internet using a stable UDP connection.
### Built With
* [Maven](https://maven.apache.org/)
## Getting Started
To get a local copy up and running follow these simple steps.
### Prerequisites
The latest versions of the following:
* Java
* Maven
### Installation
1. Navigate to the Asteroids folder
2. Clean and build the project using:
```sh
mvn install
```
3. Run the `Main` method of Asteroids using:
```sh
mvn exec:java
```
4. Alternatively you can run the `main` method in `Asteroids.java` using an IDE of your choice (e.g. IntelliJ). !IMPORTANT! Be sure to run the `Generate sources and update folders` on the `pom.xml` file before you run the application.
Should you want to run this program standalone, you can create a JAR file with the following maven command:
```sh
mvn clean package
```
The JAR file will appear in the `/target` directory.
## Design Description
In this section describes the overall design of the Asteroids game.
**The structure**
The architecture follows the MVC structure globally. Where the view is responsible for the for the UI, the controller is responsible for application logic and the model is responsible for holding data.
The structure of the game is made so that the view is decoupled as much as possible from the control and models. This means that you can instantiate the game without even touching the ui. If you also want to attach the UI, so you can actually see something, you can instansiate it separately and link it to the game.
This decoupling done so that the game and it's networking parts are easier to test. To find out more about the structure go to the [Package breakdown](#Package-breakdown) section.
**Game states**
The game has multiple states that determine it's behaviour. These states can be configured in the model classes before starting a game.
- **`running`** If the game is active or not.
- **`multiplayerMode`** If the current game is multiplayer game or single player.
- **`hostMode`** If the current game instance is hosting or a just a client.
- **`specating`** If the player is spectating a multiplayer match or not.
<!-- **What design patterns did we use?**
- MVC (Model View Controller)
- Command Design Pattern
- Observer pattern
-->
**Multiplayer and networking**
The host and clients can store all clients in a client pool. The clients in the pool contain information about a player, like his name, color and his spaceship.
When a game is running, the host sends information about new asteroids or bullets and the movement of all players.
Hosts and clients have a listener that can procces incomming packets. These packets contain a protocol 'header' that describes the intention of the message. The packet is then routed through a switch that invokes the right command. This command can read the data from the message and do something. This could be registering a new player or making an asteroid.
**High scores**
All the scores of the mutliplayer and single player matches are stored in a local database. When a multiplayer game finishes the `HighScoreDB` class stores the score for all players that have participated. The name gets alphabetically concatenated and seperated by commas. This way you can have a rematch with the same players and have a new score for the same group.
The singleplayer scores are only stored with the name of the player and his score, locally.
## Package breakdown
In this section the game's structure is broken down into it's packages and classes which are all desribed here.
### Control Package
This package contains all the game and network logic. All the important decisions get made here.
**control -> Actionlisteners**
This package contains action listeners that are bound to some buttons in the view. They are responsible for setting up games and tearing them down.
- **`HostNewGameAction`**: Gets executed when a new multiplayer session has to be hosted. Is responsible for making a UDP server and configuring the game.
- **`JoinNewGameAction`**: Gets executed when a new multiplayer session has to be joined. Connects to a host and sets up a local game.
- **`NewGameAction`**: Just makes a local game without multiplayer.
- **`QuitAction`**: Stops the current (multiplayer) game gracefully and stops the application
- **`StartMultiplayerGameAction`**: Gets called by the host to start the multiplayer match. Sends a command to all clients to also start.
- **`SwitchPanelAction`**: Can switch between different views on the GUI
**control -> networking**
The networking package contains all networking related actions for playing multiplayer matches.
- **NetworkListener** This class is responsible for accepting incomming packets on the UDP socket and passing them the the command switch.
- **NetworkUpdater** This class us responsible for sending data to clients or the host. Can send updates about asteroids, bullets and ship locations.
**control -> networking -> Commands**
For handling incoming commands we decided to implement a command pattern for seperating different kinds of packets. The commands can be registered on the `Switch`. Then the `NetworkListener` routes incomming packets to the right command classes. The following commands are available:
Client specific:
- **`NewPlayer`** For letting clients know a new player has joined. Also sets their name.
- **`DestroyPlayer`** When a player's ship gets destroyed it needs to be removed.
- **`CreateBullet`** Create a new bullet object on all clients.
- **`CreateAsteroid`** Create a new asteroid object on all clients.
- **`DestroyBullet`** Destroy an existing bullet object on all clients.
- **`DestroyAsteroid`** Destroy an existing asteroid object on all clients.
- **`RegisterConfirmed`** Gets called when the host confirms the new client in a session.
- **`StartGame`** When the host starts the game this gets called to also start the clients
- **`UpdateScore`** For updating the global score on all clients
- **`GameOver`** When every ship has been destroyed the host sends this to let all clients know the session is over
Host specific:
- **`RegisterPlayer`** Gets called when a new player wants to connect to a host session. The host in turn responds by given the client an id and sending existing players. The host also lets other clients know of the new player.
Both client and host:
- **`UpdatePlayer`** Gets called when the spaceship of a player has moved. This gets sent from a client to the host. The host then sends that change to all other clients.
- **`ClientDisconnect`** When a client disconnects, set the player as non-active.
**control -> GameUpdater**
The `GameUpdater` class is responsible for keeping the main game running. In a local match it can spawn asteroids and let the player move and shoot those asteroids. It also checks for collisions and destroys those collided objects if neccesary.
When the player is a client, the gameupdater only updates the movement of the spaceships, asteroids and bullets. All the actual desicions are made on the host. The host let's all clients know these decisions.
When a player is hosting a match he does everything a local player does, but makes it's changes known to all connected clients.
**control -> PlayerKeyListener**
The playerkeylistener is responsible for handling keyboard input for a single player. Players are bound to a local ship.
### Model Package
The model package of the application is concerned with directly managing the data of the application.
**model -> Game**
This is the most import model in the game. It holds references to all other models and keeps lists about the current in game objects like the player's spaceship, asteroids and bullets. It also has start and quit methods to spin up or gracefully stop (active) games.
Pretty much all control and view classes keep a reference to this model.
**model -> MultiplayerModel**
The multiplayer model class is concerned with setting data contains getters and setters for multiplayer data. (multiplayer mode / spectation mode / lobies etc.)
**model -> SocketHandler**
This class contains the UDP socket. It can send and receive data to clients or servers. Depending on `hostMode` it wil send data to clients or a server.
**Game objects**
**model -> GameObject**
This abstract class is the base of all game objects. It contains information about an objects location and velicity. Every object also has a collision radius so that if a different object comes too close it can be destroyed. All objects also have an id for tracking them over a network.
**model -> SpaceShip**
The spaceships class represents the players ship in the game. Most importantly the spaceship has a energy capacity, location and velocity. Whenever a spaceship turns, accelerates or shoots the ships energy capacity gets lowered. We added shipcolor to this class to change the color of the spaceship.
**model -> Bullet**
The bullet class is concerned with the bullets a player fires. A bullet only exists for a certain while, but then dies off.
**model -> Asteroid**
The asteroid class is an object that can be destroyed by players if they collide with bullets. The astroid has a varying size. If an asteroid is destroyed, it will spawn smaller asteroids.
**Clients**
**model -> clients -> ClientPool**
The clientpool is a class that keeps track of all players. It adds players to a hashmap of Clientplayer(s). The clientpool is instantiated in the multiplayerplayermodel.
**model -> clients -> ClientPlayer**
The clientplayer class, is the class concerend with keeping track of player data (name / id / spaceship mode) but also network information of players (ip address / port).
**Object queue**
**model -> networkQueue -> ObjectNetworkQueue**
The abstract `ObjectNetworkQueue` class keeps a list of messages for the creation and destruction of game objects. This class holds messages that will be sent to every client (player). The `GameObject` class has holds an unique object ID that can be used to differentiate between objects. The `ObjectNetworkQueue` is extended by the `BulletNetworkQueue` and `AsteroidNetworkQueue` classes.
**model -> networkQueue -> AsteroidNetworkQueue**
The `AsteroidNetworkQueue` has methods for creating and destroying astroids. For creating a specific asteroid on all clients a message can be constructed with coordinates, velocicity and asteroid size. The same with destroying an asteroid. The messages will be added to a queue which will be send and emptied by the `NetworkUpdater` class.
**model -> networkQueue -> BulletNetworkQueue**
The `BulletNetworkQueue` is similar to the `AsteroidNetworkQueue` class and is concerned with sending information for creation and destruction of bullets on all clients.
**Database**
**model -> HighScoreDB**
This is the class in which the high scores database can be accessed. It can retrieve and store game high scores for multiplayer aswell as singleplayer seperatly. For simplicity's sake, an sqlite database has been used. The class checks if there is a database available and creates a new database with tables if the database does not exist.
### Util Package
The util package contain miscellaneous utility classes / enumerations that are used by other classes.
- **`PlayerColors`** Different colors that players can have.
- **`PolarCoordinates`** Contains information about polar coordinates.
- **`Protocol`** Contains commands used for communication between game instances.
### View Package
This package is concerned with rendering the visual elements to the player. The package contains different panel which can be switched between. Most of the ui was designed using the IntelliJ GUI designer.
**view -> AsteroidFrame**
This is a window that contains the main panel. All other panels can be display in the main panel and also be switched between. It also diplays a simple menu bar on top for going back to the main menu and quiting the game.
**View panels**
- **`AsteroidsPanel`** The main game panel that shows the game.
- **`GameOverPanel`** This panel is shown when a game is done and displays the score.
- **`HighScoresPanel`** This panel shows all highscores stored in the database.
- **`HostSessionPanel`** With this panel a player can setup and start a multiplayer game.
- **`JoinSessionPanel`** With this panel a player can join a multiplayer game.
- **`LobbyPanel`** This panel is shown before a multiplayer game has started and shows all players.
- **`MenuPanel`** This is the main menu panel that has buttons for navigating to other panels.
- **`SinglePlayerPanel`** A simple panel where you can input a name and start a single player game.
**view -> view_models**
- **`GameObjectView`** This abstract view for objects can draw objects on the screen
- **`AsteroidModelView`** This view is concerned with drawing `Asteroid` on the screen.
- **`BulletModelView`** This view is concerned with drawing `bullet` on the screen.
- **`BulletModelView`** This view is concerned with drawing `SpaceShip` on the screen.
## Evaluation
**Unit testing**
For testing the core of the application multiple unit tests have been made. All unit tests focus on small parts of the code. Most classes have unit tests, but there are exceptions. The view is hard to test with unit test and can only be 'tested' by a human. The large parts about threading and networking are also hard to test so these are only covered by the intergration tests.
**Integration testing**
The intergration tests have been made fairly easily due to the structure of the game being decoupled from the view as much as possible. A game can be setup and even played without even starting the view.
The network integration test has been made by using the `HostNewGameAction` and `JoinNewGameAction` classes. These classes can easily setup a game between a host and one more more clients. After a session has been established the `StartMultiplayerGameAction` is used to start the game on the host and all it's clients. After a while (1 second) the game stops by calling `QuitAction` so that the host sends a `GameOver` command to all clients.
There database also has an integration test. This test concerns itself about adding, retrieving and removing data from an SQLite database.
**Real life testing**
We tested our application to work for local multiplayer and singleplayer, which is behaving like it should. After port forwarding and setting up the server, we also tested our astroids application to operate using multiple players over the internet, which was a success.
During the testing phase, we did not run into any errors we couldnt solve, although we have encountered a thread error once. The thread error occured while testing the application over the internet. We couldnt replicate this tread error however, so it is a little bit of a mystery where this error came from...
**Remarks**
Overall we are pretty satisfied with the stability and performance of the game in multiplayer sessions. This is due to all the movements of the objects being calculated locally on all clients. The player's spaceship is also locally moved. This way the player experiences minimal delay in input and drawing the resulting action on the screen.
In the future we would like to add the feature that if the client is no longer responding to the server or the server is no longer responding to the client in a lobby, the players get a notification about this issue. This situation can emerge from a sudden power loss (client / server), internet issues (cliet / server) or crashing the game application. This is also the case for the host not responing anymore.
There could also be a bit more checking on both the host and the client. In this state it's not very secure and pretty easy to take malicious advantage of.
The main feature that we did not implement yet is adding microtransactions. This would be the first thing we implement, should we have to continue working on this game. :)
## Teamwork
Despite the difference in experience when it comes to object oriented programming (which is around 2 years), the teamwork turned out to be great. The difficulty we found working together was that that certain topics were easier to follow for one person then the other. This lead to me (Nils) struggeling to keep up with Stern's pace. Of course there was a huge upside to this, which was that Stern was always ready to solve issues if needed.
We we both responsible for the design of the application and the approach on how to implement all required features. Stern was mainly concerned with the implementation of the multithreaded UDP server - client connection. Nils was resposible for adding the database functionality, writing test cases, assisting on network implementation and performing miscelanious tasks where needed.
## Future implementations
- Adding server / client not responding feature to the game.
- Adding microtransactions
- Adding sounds (music, effects)
- Improving graphics
- Adding anti cheat
- If the budget is high enough: security
## License
MIT License
Copyright (c) 2020 Stern Brouwer and Nils Visser
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
## Contact
sternbrouwer@gmail.com
nilsvisser1@gmail.com