top of page

Game Download

Crusade

The project, titled Crusade, was developed as a solo endeavour where I took on the role of lead developer. The tools that I utilizing are Unity and Photoshop, my primary goal was to create an engaging Action Role-Playing experience that emphasized key objectives, including multiplayer interaction and a seamless combat system. Throughout the project, I focused on overcoming challenges related to multiplayer implementation, ensuring smooth player interactions and consistent synchronization between the client and server to deliver a cohesive and immersive experience.

Role

Lead Developer

team size 

1 person

development time

6 months

Game Engine

Unity

Genre

Action Role-Play (Souls Like)

Technologies used

image.png

Unity

image.png

C#

image.png

GIT

image.png

Photoshop

image.png

Audacity

image.png

Trello

Theme/Story 

The player awakens in the depths of a ruined dungeon, disoriented and alone. As one of the last survivors of an ancient crusade, they have no memory of the events that led to the dungeon’s destruction. With their comrades likely fallen and the fate of the crusade uncertain, the player must navigate the treacherous ruins, uncovering forgotten secrets and evading mysterious dangers. Along the way, they will discover ancient artifacts—relics of a lost civilization—that hold untold power. Driven by duty, the player must escape the dungeon, recover these relics, and determine if their crusade is truly lost.

Role and Responsibilities

As the lead developer for the project, I spearheaded the design and implementation of essential gameplay systems using C#. My responsibilities encompassed a wide range of key features that contributed to the overall player experience, including crafting intricate player movement mechanics, developing advanced AI behaviors, and overseeing network synchronization to ensure a seamless multiplayer experience.

To achieve this, I implemented a robust poise system that prevents players from being stun-locked during combat, enhancing overall gameplay fluidity. I also designed a two-handed weapon system that allows players to equip different weapons strategically, further enriching combat dynamics. Additionally, I developed an armor system alongside a model-based equipment system, utilizing scriptable objects to manage player gear efficiently and enhance the game’s depth.
In terms of player interaction, I created an item-based pickup system and a fully functional player inventory system, complete with an intuitive user interface. These systems encouraged exploration and engagement with the game world. Furthermore, I introduced a stance system and a stance-breaking mechanic, which added layers of strategy to combat encounters by allowing players to exploit their opponents’ vulnerabilities.

I also implemented a riposte system that integrates critical hit and backstab mechanics, which enhances tactical combat options and rewards skilled players. Throughout the development process, I rigorously tested and optimized each system to ensure not only functionality but also a smooth and engaging gameplay experience for players.

By balancing these various elements, I aimed to create an immersive and challenging environment that keeps players invested in their journey through the game. Ultimately, my goal was to deliver a polished and dynamic gaming experience that meets the high standards of today’s action role-playing games.

Design Process

In developing The Crusade, I followed a five-step design process, which I will elaborate on throughout this portfolio piece. Each phase was crucial in shaping the game's mechanics, systems, and overall player experience.

1

DESGIN DOCUMENT

prototyping

rought blockout/coding

2

3

refinement of code and level design 

4

passover and feedback

5

Design Document

The first step in my design process was creating the Game Design Document (GDD), where I organized all the initial ideas for The Crusade and planned out the key features to be included. In this document, I outlined the core gameplay mechanics, establishing a clear vision for how the game would function and what players could expect in terms of experience and interaction. This foundational step helped guide the subsequent phases of development. 

Core Game Pillars

  • A customisable player  character

  • Responsive AI

  • ​ruined world environment 

  • exploration 

Gameplay Breakdown

The core gameplay loop involves the player exploring vast environments to discover ancient ruins. Once inside, they navigate labyrinthine layouts, searching for hidden items and battling enemies to grow stronger. As they progress and gain enough power, they take on challenging boss fights. After defeating the boss, the player returns to exploration, continuing the cycle of discovery, combat, and progression. This loop keeps the player engaged through a balance of exploration, combat, and strategic growth.

Explore Ruins

Find ancient artifacts

Fight enemy's

find loot

Second-to-Second gameplay :The player will explore both an expansive open world and the depths of ancient ruins. In the open world, they will search for new areas and hidden secrets, while in the ruins, they will navigate intricate, maze-like environments

Minute-to-Minute gameplay : The player will uncover hidden items and defeat enemies to grow in power, gradually enhancing their abilities and equipment. These elements of exploration and combat are key to the player's progression, allowing them to face increasingly difficult challenges as they advance through the game.

Hour-to-Hour gameplay : The player will face challenging bosses in order to unlock new zones and acquire ancient artifacts. Each boss fight serves as a major milestone, testing the player's skill and progression while rewarding them with access to new areas and powerful artifacts that enhance their abilities and deepen the game's lore.

Level Breakdown

The player begins in a small, confined room that leads into a narrow corridor. Along the way, they encounter three dead bodies, subtly hinting at an unknown threat lurking just out of sight. This design choice creates a sense of tension and unease, drawing players deeper into the environment as they anticipate the dangers that lie ahead.

1

image.png

2

At the end of the corridor, the player discovers a glowing object, which, when picked up, provides them with a sword to aid in their survival. This weapon becomes a critical tool for the player moving forward. As they proceed, they spot another corridor ahead, where two undead enemies are revealed. The player now faces a choice: either engage the enemies in combat or try to evade them and continue exploring, adding an element of strategy and tension to the gameplay.

image.png

3

At the end of the corridor, the player enters a small room with a single enemy, prompting a decision to either fight or flee. After clearing the room, the player ascends a staircase that opens into a courtyard. In the center of the courtyard, there is a small fire pit, which acts as a save point, restoring the player's health upon interaction. From here, the player is presented with three distinct paths. One leads to valuable armor, another to a challenging boss fight, and the third reveals a hidden corridor for further exploration. These options provide both strategic and immersive depth, giving the player control over how they advance through the game.

image.png
image.png

4

In this breakdown, after acquiring the armor, the player chooses to explore the hidden path. As they proceed, they soon realize that the hidden path opens up, revealing even more to discover. This new area presents three additional paths. One leads up a set of stairs, another takes the player toward an enemy, and the last is a small room with a corridor leading further into the unknown. These branching paths expand the player's sense of exploration, creating intrigue and encouraging further discovery as they decide which direction to take next.

image.png

5

In this breakdown, the player weighs their options, picks up another item, and heads up the stairs. Moving through a corridor, they eventually uncover one of the possible ways to end the level: a shining portal at the top of a mountain. As the player walks along a narrow pathway, they spot an opening that reveals a wind to the boss room. From there, they proceed into another corridor, building anticipation as they inch closer to the level's final challenge. This sequence offers a sense of discovery and choice, while also guiding the player toward critical encounters and the level's conclusion.

image.png
image.png

6

The player follows the corridor around, discovering another item and encountering an enemy along the way. After dealing with this, they peer down the final corridor, which leads into even more winding passageways. However, deciding not to continue exploring, the player turns back and retraces their steps to the courtyard, ready to face the boss and take on the challenge that awaits. This decision to return to the central area builds tension, as the player prepares for the pivotal encounter in the game. 

image.png

7

Once the player faces the boss, this is where the tutorial concludes, as the boss ultimately defeats the player. However, if the player had managed to win the battle, they would have been able to proceed to the portal, which would have revealed more of the world, marking the end of the tutorial and the beginning of the larger adventure. This outcome teases the vastness of the game’s universe, setting up the narrative and gameplay to come while also reinforcing the difficulty and challenge the player will face throughout the game.

image.png

Player Input / Combat Input

This script manages input handling for player actions in Unity. It is integrated with Unity's Input System, where input events are captured and translated into actions the player can use.

Overview of Unity's Input System

Unity's Input System allows developers to define input actions via an Input Action Asset. This system uses:

  1. Action Maps: Group related input actions (e.g., Gameplay, UI).

  2. Input Actions: Define specific actions (e.g., Jump, Attack).

  3. Bindings: Link input actions to hardware inputs (e.g., keyboard keys, controller buttons).

The script assumes:

  • Input states (dodge_Input, RB_Input, etc.) are updated based on player input.

  • These inputs are either polled or set via callback events provided by the Input System.

image.png
image.png
image.png
image.png
image.png

Class Overview:

The PlayerInputManager class is a singleton, designed to manage and process all player inputs across various gameplay aspects such as movement, camera control, combat, and UI interactions. It uses Unity's MonoBehaviour as its base and incorporates Unity's new Input System for handling player controls.

  1. Singleton Pattern Implementation:

    • The instance ensures there is only one active PlayerInputManager at any given time. If a duplicate is detected, it is destroyed.

    • The object persists across scene loads using DontDestroyOnLoad.

  2. Player Controls Integration:

    • Inputs are managed using a PlayerControles object, which consolidates input mapping for actions like movement, camera rotation, dodging, weapon switching, and sprinting.

  3. Input Categories:

    • Camera Movement Inputs: Handles vertical and horizontal camera rotation.

    • Player Movement Inputs: Processes movement directions and computes movement intensity (moveAmount).

    • Combat Inputs: Includes various combat-related actions such as dodging, attacking (using bumpers and triggers), and two-handed weapon mechanics.

    • Lock-On System: Implements a locking mechanism to target enemies and seamlessly switch between targets.

    • UI Inputs: Manages interactions with menus and UI elements, such as opening character menus.

  4. Scene-Based Input Management:

    • The OnSceneChange method dynamically enables or disables player controls based on the active scene, preventing unintended actions in non-gameplay scenes (e.g., main menus).

  5. Focus and Input Handling:

    • The OnApplicationFocus method ensures input functionality is paused or resumed when the application loses or regains focus.

  6. Queued Inputs:

    • Implements a system to queue specific inputs (RB, RT, etc.) with timers, ensuring precise action timing.

  7. Customisable Input Processing:

    • Input handlers are modular, allowing easy extension or modification for individual input types, such as two-handed weapon toggling, sprinting, and interaction mechanics.

AI System

In this project, I developed a complex AI system that handled everything from basic enemy behaviors to advanced boss mechanics. This included implementing distinct combat patterns, handling phase transitions based on health thresholds, and creating scalable systems that could support both standard enemies and challenging boss encounters.

Here's a brief video demo showing part of the AI system I worked on.

The AICharacterManager is responsible for managing the overall behavior and state of an AI character. It acts as the brain of the AI, controlling movement, combat decisions, state transitions, health updates, and integration with Unity’s NavMesh system for navigation.

The AICharacterManager is the brain/controller for AI characters in your networked game. It's in charge of:

  • Managing AI states (Idle, Pursue, Attack, etc.)

  • Interfacing with Unity's NavMesh system for navigation

  • Handling combat logic and target awareness

  • Syncing relevant data across the network via AICharacterNetworkManager

  • Acting as the root orchestrator of all AI-related subsystems

Architecture Overview

  • Inherits from a base class CharaterManager, which likely provides shared character logic (like animation, stats, death handling).

  • Integrates multiple subsystem managers (combat, movement, inventory, networking) to break down responsibilities clearly.

  • Manages its own NavMeshAgent for pathfinding and terrain navigation.

  • Uses Unity’s component-based design to keep things modular and testable.

AI Behavior Control

  • Uses a state machine pattern with modular AI states (IdleState, PursueTargetState, etc.).

  • Each AI state can return a new state, enabling clean and dynamic behavior transitions (see player → chase → attack).

  • Central method ProcessStateMachine() runs every FixedUpdate() to evaluate AI logic.

Main Lifecycle Hooks

  • Awake() sets up references to key components.

  • OnNetworkSpawn() handles initialization only when the instance has ownership (important for multiplayer).

  • OnEnable() and OnDisable() manage event subscriptions for HP UI updates, keeping everything clean and performant.

  • Update() handles ongoing tasks like action recovery (attack cooldowns).

  • FixedUpdate() runs the state machine and syncs movement data for animations and networking.

UI/UX

Conduct a comprehensive analysis of the User Interface (UI) and User Experience (UX), evaluating usability, accessibility, visual design, and overall user engagement to identify areas for improvement and ensure an intuitive and seamless interaction.

1. UI Layout & Design

The UI follows a Dark Souls-like design philosophy, emphasizing minimalism and immersion while providing essential game information.

a) HUD (Heads-Up Display)

  • Health, Stamina, and Focus Bars (Top-left corner)

    • The colored bars represent player stats:

      • Red for Health

      • Green for Stamina

      • Blue for Mana

    • The bars are small, keeping the player’s attention on the game while still conveying crucial information.

  • Quick Slot System (Bottom-left corner)

    • Displays the currently equipped left-hand weapon, right-hand weapon, and usable item (flask/potion).

    • Great UX Decision: The icon-based quick slot is intuitive, ensuring players can quickly recognize their equipped gear without needing to navigate menus.

  • Boss Health Bar (Bottom-center)

    • Displays "Grim Warden" with a red health bar underneath.

    • This separates boss health from the player's HUD, ensuring clarity in combat.

Code Example

PlayerNetworkManager Script Overview

This script is a key component of a multiplayer game developed in Unity, responsible for synchronizing player-related data across the network. It leverages the Unity Netcode for GameObjects framework to manage player states, inventory, equipment, combat interactions, and more in a distributed multiplayer environment.

Key Features

  1. Networked Player States

  2. Real-Time Equipment and Combat Management

  3. ​Player Stats Management

  4. Multiplayer Interaction Handling​

1. Networked Player States

  • Utilizes NetworkVariable to track and synchronize important player attributes such as:

    • characterName: The name of the player's character.

    • currentWeaponBeingUsed: Tracks the currently equipped weapon.

    • isTwoHandingWeapon: Indicates whether the player is using a weapon two-handed.

2. Real-Time Equipment and Combat Management

  • Dynamically updates player equipment and weaponry across the network, ensuring consistency in all connected clients.

  • Includes methods like OnCurrentRightHandWeaponIDChange and OnIsTwoHandingWeaponChanged to handle equipment changes.

3. Player Stats Management

  • Updates player health and stamina dynamically based on changes in attributes such as vitality and endurance.

  • Integrates with a custom Player UI to reflect updated stats on the HUD.

4. Multiplayer Interaction Handling

  • Includes ServerRPCs and ClientRPCs for reliable communication between server and client for weapon actions and updates.

PlayerEquipmentManager Script Overview

This script manages the equipping and unequipping of weapons and armor in a multiplayer game environment. It handles loading models, calculating stats, and synchronizing equipment changes across clients. The script also supports a dynamic two-hand system for weapons and ensures that equipment changes are reflected visually and mechanically.

Key Features

  1. Dynamic Equipment Loading

  2. Weapon Management

  3. ​Two-Handed Weapon Support

1. Dynamic Equipment Loading

  • The script dynamically loads models for equipped weapons and armor.

  • It uses predefined slots for each equipment type (e.g., head, body, legs, hands).

2. Weapon Management

3. Two-Handed Weapon Support

  • Allows players to two-hand either their left or right weapon.

  • Updates animations, strength bonuses, and model placements based on the two-hand state.

PlayerManager Script Overview

The PlayerManager script is the central hub for managing a player character in a multiplayer game using Unity and Unity Netcode. It orchestrates interactions between various sub-managers like locomotion, inventory, equipment, and combat, ensuring seamless synchronization of player actions and states across the network.

Key Features

  1. Modular Manager System

  2. Networked State Management

  3. Multiplayer-Specific Behavior

  4. Save and Load System

  5. ​Death and Respawn Logic

1. Modular Manager System

  • The script integrates multiple sub-managers (e.g., PlayerAnimatorManager, PlayerStatsManager) for handling specific aspects of the player character, adhering to the single responsibility principle.

  • Ensures all sub-managers are properly initialized during the player's lifecycle.

2. Networked State Management

  • Synchronizes player stats, equipment, animations, and actions across all connected clients.

  • Uses OnValueChanged callbacks to handle changes in network variables and update the UI or gameplay logic accordingly.

3. Multiplayer-Specific Behavior

  • Implements ownership checks (IsOwner) to ensure only the client controlling the player can execute certain actions (e.g., movement, input).

  • Loads and synchronizes player data when joining or leaving a multiplayer session.

4. Save and Load System

  • Supports saving and loading player data (CharaterSaveData) to ensure persistence across game sessions.

  • Handles equipment, stats, and positional data, restoring the player's state accurately when rejoining.

5. Death and Respawn Logic

  • Handles player death and revival, including UI updates and network synchronization.

  • Plays death animations and resets stats on revival.

Code Challenges and Solutions

PlayerNetworkManager Challenges and Solutions Overview

1. Ensuring Smooth Synchronization Across Clients

  • Challenge: In a multiplayer environment, ensuring all clients see the same state for critical variables like player equipment, stats, and actions can be difficult due to latency and potential desynchronization.

  • Solution:

    • Leveraged Unity Netcode's NetworkVariable system to track and synchronize key player states in real-time, such as equipped weapons, armor, and spells.

    • Used change callbacks on NetworkVariables (e.g., OnCurrentRightHandWeaponIDChange) to trigger updates whenever a value changes. These updates ensure that any modification is immediately reflected across all clients.

    • Implemented logical checks to prevent redundant updates, reducing unnecessary network traffic.

Achieved seamless synchronization, ensuring all players experience consistent gameplay regardless of their connection quality.

2.Managing Complex Equipment States

  • Challenge: Tracking and managing various equipment slots (weapons, armor, spells) while allowing for real-time updates presented challenges, particularly with interdependent equipment states like two-handed weapon usage.

  • Solution:

    • Designed a modular system using NetworkVariables for each equipment type (e.g., currentRightHandWeaponID, headEquipmentID).

    • Developed specialized methods (e.g., OnIsTwoHandingWeaponChanged) to handle state transitions dynamically, including animations, effects, and stat adjustments.

    • Integrated with a centralized item database (WorldItemDatabase) to ensure consistent item instantiation and data retrieval.

Allowed for robust handling of equipment changes, improving the user experience and enabling more dynamic gameplay scenarios.

QA Responsibilities

The testing process for Crusade played a crucial role in ensuring the game's functionality. After implementing new systems or code, I would conduct thorough testing to identify and address any emerging bugs or issues.

When a bug was identified, I documented it in a list of bug reports on Jira. This allowed me to effectively track which bugs had been found, monitor their status, and ensure they were addressed in a timely manner.

image.png

One notable issue I encountered was an AI-related bug titled "AI Bug – AI Character Decouples from NavMeshAgent". In the video below show the bug before I found a fix.

This occurred when the NavMeshAgent component wouldn't start where the AI character would be in the environment causing NavMeshAgent to lose synchronization with the AI character, causing it to stop moving or behave erratically.

After identifying a bug, I would log it in the Jira tracking system, provide a clear description of the issue, and record a video to visually demonstrate the bug in action. This helped communicate the problem effectively and provided valuable context. Once documented, I would begin the debugging process to investigate the root cause and implement a fix.

image.png

Throughout the testing process, I repeatedly reviewed the character AI code to isolate potential issues, carefully examining specific sections to determine if the problem stemmed from the code itself. To rule out environmental factors, I tested the AI in a separate level to see if the issue was related to the geometry. I also re-baked the NavMesh multiple times to ensure it was properly generated. After extensive testing, I implemented a solution by disabling the NavMeshAgent initially and enabling it only when the player approached the AI. This ensured the agent would spawn in the correct position and remain properly synchronized with the environment.

image.png

I consistently follow this process for all bugs encountered during the integration of new systems into the game. This ensures that I stay up to date with any issues that arise and maintain a structured approach to identifying, tracking, and resolving potential problems efficiently.

Challenges In Game Development Overcome

I faced substantial challenges related to network latency and synchronization, which required an in-depth approach to guarantee a fluid multiplayer experience. Initially, there were noticeable delays that disrupted the seamless interaction between players, so I focused on optimizing data management to reduce the data load and improve performance.I enhanced the game’s responsiveness, minimized lag, and ensured that interactions felt intuitive and consistent across all player devices. This careful handling of network challenges created a more immersive and enjoyable experience, enabling players to stay engaged without interruptions or delays.

  • Facebook
  • Twitter
  • LinkedIn

©2021 by Joseph Merrick. Proudly created with Wix.com

bottom of page