donkey-kong

Donkey Kong: Rush

AI Disclaimer

During the preparation of this work, the authors used GitHub Copilot and DeepL to assist with writing the Javadoc and to check the grammar of this report. Moreover, Copilot has been used as a review tool in some pull requests on GitHub. After using this tool/service, the authors reviewed and edited the content as needed and take(s) full responsibility for the content of the final report/artifact.

Abstract

This report presents the “Donkey Kong: Rush” project, realized for the “Distributed System” course at the University of Bologna. The project involves the development of a 2D multiplayer platform video game inspired by the classic Donkey Kong. The system is designed around an Entity-Component-System (ECS) architecture written in Java, utilizing JavaFX for rendering. The main focus of the project is the implementation of smooth multiplayer gameplay. The solution combines the Host’s authority over the deterministic environment with a reactive handling of local inputs, guaranteeing an experience free of blocking lag for the players.

1. Concept

“Donkey Kong: Rush” is a desktop application featuring a graphical user interface (GUI). Specifically, it is a 2D multiplayer platform video game, which takes inspiration from the original Donkey Kong arcade game.

1.1 Use case description

The software provides a competitive multiplayer platforming experience. Users are located on separate desktop machines connected over the same local area network. Thus, distribution is a fundamental requirement for this project to enable a seamless multiplayer experience, as it allows players on physically separate machines across a network to connect, interact, and share the same virtual space.

Interaction is continuous and in real-time during an active game session. The system captures inputs and exchanges state updates across the network multiple times per second to maintain synchronization.

Players interact with the system via the GUI during setup or keyboard controls during the game. The game controls consist of standard keybindings for movement (left/right, climbing ladders) and jumping.

The system does not require persistent, long-term data storage. All necessary data represents the state of the ongoing match (such as player and barrel coordinates) and is kept strictly in RAM.

The game relies on multiple user roles:

2. Requirements Elicitation and Analysis

Glossary
Term Definition
Host A player who actively plays the game, processes local input, acts as the authoritative entity for game-world generation (e.g., barrels), and broadcasts the state to clients.
Guest A player who actively plays the game, processes local input, and receives continuous world state updates from the Host.
Spectator A passive user who does not generate input but receives real-time updates to render and watch the match.
Lobby The pre-game networking state where users connect and are assigned their respective roles (Host, Guest, or Spectator) before the match begins.
Entity Any distinct object in the game world.
Barrel A dynamic entity that deals damage when a player comes into contact with it.
Ladder A climbable entity in the game level that enables players to move vertically regardless of gravity.
Functional Requirements
Description Acceptance Criterion  
The system must allow users to join a lobby and automatically assign them a role (Host, Guest, or Spectator) based on join order or preference. A user successfully connects to the server and receives a distinct role assignment (Host, Guest, or Spectator) before the game starts.  
The system must allow active players to move horizontally (left/right), jump, and climb ladders. Pressing the designated keys updates the player’s position appropriately on the screen according to game physics (gravity, collision).  
The system must synchronize the game state (entities positions, and lives) between all connected clients in real time. When the Host moves or a barrel spawns, the Guest and Spectators see the updated positions on their screens without noticeable desynchronization.  
The system must detect collisions between players and damaging entities (e.g., barrels), deducting a life upon impact. When a player’s character intersects with a barrel, the player’s life count decreases by 1, and the character respawns at the starting position.  
The system must declare a winner if a player reaches the goal (Pauline) or declare a loser if a player’s lives reach zero. The game transitions to a “Game Over” screen displaying the correct winner or loser when the goal is touched or 3 lives are lost.  
Non-Functional Requirements

These requirements define the behavioral aspects and quality attributes of the system.

Description Acceptance Criterion
The game must update and render at a consistent frame rate to ensure smooth gameplay. The local game loop executes consistently at the target of 60 Frames-Per-Second (FPS).
State updates must be transmitted rapidly to prevent visual stuttering or unfair advantages. State update payloads are serialized, transmitted over the local network, and deserialized by the receiving client in under 33 milliseconds (roughly 2 frames).
The system must ensure automatic recovery from disconnections for non-Host users. If a Guest or Spectator loses their network connection and subsequently reconnects to the server while the match is still active, the system automatically restores their role and resumes sending them real-time game state updates without requiring a full lobby reset.
Code must be modular and documented to make extensions and changes easy. Modularity is enforced by strictly decoupling data structures from execution logic, avoiding deep and rigid inheritance trees. Maintainability is verified by the presence of comprehensive Javadoc comments on all core API interfaces, ensuring new features can be integrated rapidly.

2.1 Relevant Distributed System Features

Design

This chapter explains the strategies used to meet the requirements identified in the analysis.

Architecture

The project follows the Model-View-Controller (MVC) and Entity-Component-System (ECS) architectural patterns. The MVC pattern is used to separate the user interface from the game logic, while the ECS pattern is used to manage the game entities and their behaviors.

For what concerns the distributed aspect of the project, a client-server architecture is used. The host player act as both the client and the server, while the other player and any spectators act as clients. The server is responsible for managing the game state and broadcasting updates to all connected clients.

This architecture was selected for its simplicity, efficiency, low latency, and ability to abstract complexity from the user. A decentralized peer-to-peer alternative, where each user operates an interconnected server, was evaluated but rejected due to high implementation complexity and network latency overhead. Its sole advantage, mitigating the single point of failure if a central leader goes offline, did not justify the operational trade-offs.

3 Design

This section details the architectural and structural decisions made to fulfill the system’s requirements.

3.1 Architecture

The project follows the Model-View-Controller (MVC) and Entity-Component-System (ECS) architectural patterns. The MVC pattern is used to separate the User Interface (UI) from the game logic, while the ECS pattern is used to manage the game entities and their behaviors.

Regarding its distributed nature, the system utilizes a centralized Client-Server architecture heavily reliant on an Event-Driven model. The server acts as a central authoritative game lobby and message relay, while the clients maintain local instances of the game. This design minimizes peer-to-peer connection issues and provides a single source of truth for matchmaking, role assignment, and fault management.

3.2 Infrastructure

To support the game’s multiplayer requirements, the infrastructure relies on a centralized star topology where all network traffic flows through the main server.

Component Diagram

3.3 Modelling

Class Diagram

3.4 Interaction

Sequence Diagram

3.5 Behaviour

State Diagram

3.6 Data and Consistency Issues

3.7 Fault-Tolerance

3.8 Availability

3.9 Security

4 Implementation

This chapter details the specific technology-dependent choices made to realize the architectural design, focusing on network protocols, data serialization, and the frameworks exploited.

4.1 Technological Details

The project relies on a specific technology stack to achieve its concurrency and rendering goals:

5 Validation

To ensure the reliability, correctness, and performance of the distributed game, the system was subjected to a rigorous testing phase, divided into automated testing for core logic and manual acceptance testing for gameplay feel and GUI responsiveness.

5.1 Automatic Testing

Automated testing was implemented using JUnit 5 and managed via the Gradle build tool. The tests are executed automatically within a Continuous Integration (CI) pipeline using GitHub Actions (ci.yml and pr-checks.yml), ensuring that every pull request is validated before being merged. Tests can be run locally by executing ./gradlew test via the command line interface.

5.2 Acceptance Test

Manual testing was a critical phase of the validation process, conducted in a production-like local area network (LAN) environment with multiple physical machines.

6 Deployment

This section outlines the process required to deploy and run “Donkey Kong: Rush” on a local machine. The deployment strategy focuses on simplicity, leveraging the Gradle build automation tool to manage dependencies and execution without requiring complex manual configurations.

Prerequisites

Before deploying the software, the target machine must meet the following software requirements:

Installation and Execution from Scratch

The software does not require a traditional installer wizard. It is deployed and executed directly from the source code using the included Gradle Wrapper.

  1. Obtain the Source Code: Clone the repository using Git or extract the provided project archive.
    git clone <repository_url>
    cd donkey-kong-feat-multiplayer
    
  2. Execute the Application: Run the application using the Gradle Wrapper. This ensures that the exact required version of Gradle is used, eliminating the need for the user to install Gradle manually.
    • On Linux / macOS:
      ./gradlew run
      
    • On Windows:
      gradlew.bat run
      

      Expected Outcomes:

      Upon executing the run command, the Gradle Wrapper will automatically download all required third-party dependencies (e.g., Eclipse Vert.x, JavaFX modules, Netty), compile the ECS engine and network logic, and finally launch the DonkeyKongRushUI JavaFX application. The user will be presented with the Main Menu graphical interface, confirming a successful deployment.

Configuration Files and Environment Variables

The system is designed to be “plug-and-play” and does not rely on external configuration files (e.g., .env, .yaml, or .properties files). All network configurations, such as the target IP address for the Lobby Server, are intentionally exposed directly through the graphical user interface. This choice maximizes user accessibility, allowing players to establish connections dynamically without modifying text files before deployment.

Containerization Strategy

While modern distributed systems frequently rely on containerization tools like Docker or Kubernetes, “Donkey Kong: Rush” explicitly avoids this deployment model for the following reasons:

  1. GUI Constraints: Containerizing desktop applications with hardware-accelerated GUIs (JavaFX) requires highly complex X11 socket forwarding or virtual framebuffers (VNC) mapped to the host machine. This significantly degrades rendering performance and frustrates the user experience.
  2. Embedded Server Logic: The central server (LobbyVerticle) is not a standalone microservice that needs isolated scaling. It is automatically deployed by the Host’s instance of the application at runtime.
  3. Distribution Format: For production distribution beyond the source code, the deployment pipeline is configured to package the application into a single executable “Fat JAR” containing all dependencies, allowing users to run the game with a simple java -jar donkeykong.jar command, achieving total portability across operating systems without container overhead.

7 User Guide

This section provides a step-by-step guide on how to interact with the “Donkey Kong: Rush” application.

Launching the Game

Upon executing the application via Gradle (./gradlew run), the user is greeted by the Main Menu window. This graphical interface provides text fields and buttons to establish network connections.

How to Play

1. Hosting a Game (Player 1)

2. Joining a Game (Player 2)

3. Spectating a Game

Main Menu UI

Gameplay Controls

Once the game has started, active players (Host and Guest) can interact with the environment using the following keyboard bindings:

Game Objective: Navigate your avatar from the bottom of the screen to the top to rescue Pauline. Avoid the rolling barrels spawned by Donkey Kong. If you collide with a barrel, you will lose a life and respawn at the bottom. The game ends when a player reaches Pauline (Win) or loses all 3 lives (Lose), triggering the Game Over screen.

Active Gameplay Arena

Self-evaluation

9 Future Works

While the current implementation successfully fulfills the core requirements of a distributed, real-time multiplayer platformer, several avenues for improvement and architectural expansion remain.

Client-Side Prediction and Interpolation

Currently, the Guest and Spectator clients act as “dumb terminals” for external entities, strictly overwriting their local entity coordinates with the incoming network snapshots from the Host. On a high-latency network, this could lead to visual stuttering or “rubber-banding.” A primary future improvement would be implementing Entity Interpolation (smoothing the visual transition between the last known network state and the current one) and Client-Side Prediction (allowing the Guest to predict the physics of barrels locally, correcting them only if the server’s authoritative state deviates significantly).

Scalability and Cloud Matchmaking

The system relies on users manually sharing LAN IP addresses and hosting the LobbyVerticle on their personal machines. To scale this into a production-grade application, the LobbyVerticle could be decoupled and deployed as a standalone microservice on a cloud provider (e.g., AWS or Google Cloud) using Docker and Kubernetes. Furthermore, introducing a Matchmaking Service would eliminate the need for manual IP entry, automatically pairing available clients into isolated game instances dynamically orchestrated by the cloud provider.

Security Enhancements (WSS and Tokens)

Currently, the system uses unencrypted WebSockets (ws://) and implicitly trusts connections based on routing order. A critical future extension would involve upgrading the infrastructure to utilize WebSocket Secure (wss://) by provisioning TLS certificates. Additionally, implementing a lightweight authentication system using JSON Web Tokens (JWT) would prevent malicious users from spoofing the /play endpoint on public networks, ensuring that only authenticated users can claim the Host or Guest roles.

Dynamic Level Progression

From a gameplay perspective, the game currently features a single, hardcoded map generated upon startup via the MapFactory. Future iterations could introduce dynamic map loading (e.g., parsing JSON or Tiled map formats). This would require extending the network protocol to broadcast a LEVEL_LOAD message, ensuring that all distributed clients load and synchronize the same level assets before the GAME_START event is triggered.