This project implements a real-time four-player fighting game across two Basys 3 FPGAs. Each board handles two local players and renders game state to a VGA display while synchronising player actions over a custom inter-FPGA communication link. The design required deterministic timing for video generation, input handling, physics updates, and audio output.
Full setupThe game engine is structured as a synchronous hardware pipeline driven by a global frame tick. 4 player inputs from 2 keyboards (arrows and wasd provides for 2 different players per keyboard) are debounced and converted into action commands that feed a character state machine. Movement, attack cooldowns, health updates, and collision detection are computed once per frame, ensuring consistent gameplay speed independent of rendering.
A VGA controller generates pixel coordinates which are used to index sprite ROMs for characters, projectiles, and UI elements. Priority compositing ensures correct layering of players, attacks, and background tiles. Health bars, ultimate meters, and character indicators are rendered using a separate overlay path to avoid modifying sprite assets.
On-board display showing health, ultimate status, and character selectionThe 7 segment shows the health of each character. The positions correspond to the characters' positions on the OLED screen. The LEDs on the Basys 3 charge up as time goes by (at different speeds for different characters), and will start blinking once it is ready.
The two boards exchange player state and action packets over a parallel link. A lightweight protocol encodes position, health, attack state, and ultimate triggers.
Different attack styles for each characterEach character is implemented as a parameterised hardware module with configurable movement speed, attack rate, damage, and health. This allowed rapid balancing without modifying the control logic.
Dead characters replaced by tombstonesWhen a character’s health reaches zero, the module transitions to a tombstone state that removes it from collision checks while preserving its screen position.
Sound effects are generated using a PWM audio module triggered by attack and ultimate events. Tone frequency and duration are stored in ROM, allowing multiple effects without increasing logic complexity.