top of page

UNANNOUNCED

Gameplay Programmer

Role

Gameplay Programmer

Presence

From early prototype to alpha (current state)

Engine

Unity

Genre

Party game | PvP

Platform

PC

Status

In development

Type

Profesionnal

ABOUT

This project is a PvP party game where teams of 3 players play some champions and fight each other.

This project is still in development and still unannounced, so only few information about the gameplay can be shared.

PORTFOLIO PRIVATE ACCESS

Details about most of the work I've done on this project is locked behind a password.

Please click the button below and use the password available on my resume to get access to more details, more images and code snippets of my work.

MY ACHIEVEMENTS

On this project, I worked as Gameplay Programmer.

​

My achievements are:​​

  • Developed a robust and modular AI for players to face, utilizing influence maps, move prediction, and projectile prediction algorithms.

  • Enhanced AI behavior by training an AI model to extract data from playtest videos using YOLOv8 and Python, enabling the AI to better mimic player movements.

  • Created a backend and community features, including a friends list, lobby system, and cloud-based inventory and economy, using Unity Game Services and JavaScript Cloud Code.

  • Developed many of the champions of the game within a client/server architecture.

  • Expanded player options by implementing a gameplay events system that triggers at fixed intervals and is easily customizable by the design team.

  • Fixed the majority of gameplay-related bugs, ensuring a smoother player experience.

AI SYSTEM - FSM

I developed a modular AI system for our upcoming game, featuring an increasing level of difficulty.

The system is designed using a Finite State Machine (FSM) to manage AI states.

​

The system was developed to be highly modular and easy for game designers to edit. To achieve this, I utilized Serialized Objects and Serialized Interfaces.

​

The core of the system is the AIChampion script, which handles the FSM logic.

​

Each State includes:

  • One or multiple IActions interfaces, which define how the AI behaves in a given State.

  • One or multiple ITransitions interfaces, which define the States the AI can transition to and under what conditions.​​

Each Transition also contains an IDecision interface, which determines the condition under which a Transition is considered fulfilled.

​

This system enabled us to code only a few Transitions and Decisions to handle most of the scenarios requested by the design team. Designers can then configure the AI to behave however they want.

​

Additionally, the system allowed us to handle edge cases, such as special skills for certain champions (e.g., a channeled skill), without modifying the base code. These cases were addressed by extending the system.

​

Below, you’ll find the logic of the AIState base class. With this system, it remains simple while still accommodating a wide variety of cases.

​​​

AIState.PNG
CODE SNIPPET - AIState.cs

The following code shows the base AIState class which handles IActions and ITransitions:

MOVE ALGORITHM

For this project, I designed and implemented an advanced AI movement algorithm that utilizes an influence map to guide the AI's decision-making.

This system ensures that AI characters make strategic movement choices based on the influence mapprojectile predictions, and player proximity, creating a challenging yet dynamic experience for players.

​

The algorithm samples positions within a configurable radius around the AI, then assigns weights based on:

  • The influence map

  • Proximity with other ally players

  • Close projectiles

 

By leveraging these weights, the AI selects the optimal position for movement, adapting to real-time changes in gameplay. This modular approach enables seamless integration of additional decision layers (such as dodging projectiles) while maintaining performance.

Below is an example of the position sampling and weighting logic used in the algorithm:

CODE SNIPPET - Move algorithm

The following code shows a few functions of the AI move algorithm.

​

This first function is the one returning the position the AI should move to.

This function gets evenly distributed position around the AI, which are then used to calculate weights. The range and amount of positions to fetch can be customized.

It is a C# implementation of the sunflower seed distribution.

Finally, this function calculates a weight value for a given world position based on a heatmap texture.

It maps the 3D world position onto the 2D texture by scaling the world coordinates to the texture's dimensions.

It then retrieves the grayscale value of the corresponding pixel in the heatmap, which represents the weight of that position.

The move algorithm is highly customizable by the design team, allowing them to change weight strength, close to player weight, sample position count and move radius.

Move.PNG
PROJECTILE PREDICTION ALGORITHM

I implemented a projectile prediction algorithm to enhance the AI’s ability to dodge incoming projectiles.

This algorithm predicts whether a moving projectile (given its start position, its direction, its speed and its radius) will collide with a player or AI character within a given timeframe.

 

This function simulates the future positions of both the projectile and the target by iterating through small time steps and checking their distance at each step.

 

If the combined radius of the projectile and the target overlap at any point, a collision is detected.

This system allows the AI to anticipate and evade projectiles dynamically, providing more reactive and challenging gameplay for players.

CODE SNIPPET - Projectile prediction
TARGET PREDICTION ALGORITHM

The prediction algorithm is used by the AI to determine where to aim its projectiles in order to hit the target.

​

In our game, players move dynamically and frequently. Initially, I implemented a simple prediction algorithm using a quadratic equation, which took into account the speeds and directions of both the projectile and the target to predict the target’s future position.

However, since players change direction often, the AI appeared to target random positions, as players would frequently intent a new move action before reaching the predicted location.

​

To improve this, I enhanced the prediction algorithm by factoring in the time since the player last moved (timeSinceLastMove) and comparing it to the average time between two player movements (averageTimeBetweenMove), which was gathered through playtesting.

​

The new logic works as follows: the closer timeSinceLastMove is to averageTimeBetweenMove, the more likely the player is to change direction soon, so the AI throws the projectile closer to the player. Conversely, if timeSinceLastMove is lower, indicating the player is less likely to change direction, the AI throws the projectile closer to the predicted position.

​

You can find below a code snippet of the function I created for this task.

CODE SNIPPET - Target prediction

After playtesting, the AI was considered strong enough without further adjustments.

However, the prediction could be further refined by dynamically adjusting the averageTimeBetweenMove for each player based on their actions, rather than using the same value for all players.

This would enable the AI to target players more accurately, whether they move very dynamically or more predictably.

AI MODEL TRAINING

To enhance our AI system, I trained a YOLOv8 AI model on several playtest videos to track player movements. Using a Python script I developed, I processed these videos, tracked player positions, and generated a heatmap based on the detected coordinates.

​

The process involved:

  • Training a YOLOv8 model on frames extracted from the videos using Roboflow

  • Ensuring the model's accuracy by utilizing a larger dataset of still frames

  • Writing a Python script that takes input videos, extracts their frames, applies the trained YOLOv8 model to detect player coordinates, and aggregates these positions into a heatmap using OpenCV.

The resulting heatmap, shown on the right, is used as an influence map for the AI’s movement logic, by giving weight based on the heatmap's colors, allowing the AI to move more like a real player.

​

In the future, we could automate the gathering of player positions and dynamically generate heatmaps for real-time influence mapping, which could be fed to the AI based on the current game environment.

​

Below, you'll find the Python script I wrote to extract frames, collect data, and generate the heatmap.

heatmap_combined.jpg
GenerateHeatmap.py
BACKEND SHOP SYSTEM

For this project, I developed a robust item/unit shop system using Unity Game Services (UGS), integrating Economy, Inventory, Cloud Save, and Cloud Code to build a scalable backend.

 

The system retrieves purchasable items from the cloud, and caches them locally within a custom class which links Unity Inventory Items with our actual gameplay items. This implementation reads custom data from Unity's inventory system, ensuring that each virtual item is correctly linked to its in-game counterpart.​

​

Below is a snippet of the InitializeBuyableItemsAsync function, responsible for caching purchasable items locally and associating them with real gameplay items:

CODE SNIPPET - InitializeBuyableItemsAsync

Initially, configuring each InventoryItem and VirtualPurchase in the Unity Dashboard was a manual process.

To increase efficiency this, I developed a C# script that automatically creates and deploys InventoryItems and VirtualPurchases based on our gameplay-configured items.

 

This solution enables us to deploy all buyable items with a single click, significantly improving efficiency.

​

Below is a snippet of the function responsible for exporting our gameplay-configured items into Economy files that can then be deployed:

CODE SNIPPET - Export Economy Files

The Unity Dashboard doesn't provide direct options for modifying a player's inventory, such as adding or removing items, or updating custom data.

​

To address this limitation and enable administrative control over our backend, I implemented Unity Cloud Code using JavaScript. This allows us to modify player inventories when necessary.

​

Below is one of the Cloud Code scripts I wrote, designed to remove an item from a player's inventory:

CODE SNIPPET - Javascript Cloud Code

As the system became more complex —with API calls to multiple services and interactions between various classes and structs— I created some documentation to ensure the maintainability of our backend.

​

Below are some examples from the documentation I wrote for our team:

Flowchart of the UGSManager, Shop window and Arsenal window

Extract of the documentation

FRIENDS LIST

I have been working on integrating Unity Game Services (UGS) Friends into the game, creating a robust friend management system using the FriendsService API.

 

My implementation includes handling friend requests, managing online status, and synchronizing friend lists in real-time. The UGSFriendsListManager script centralizes these operations, ensuring seamless communication between players.

 

Below is a snippet demonstrating how I register event callbacks to dynamically update the friends list when a new relationship is added:

CODE SNIPPET - Friends event register

A crucial aspect of this implementation is the use of Unity's async/await pattern, which allows non-blocking operations while interacting with Unity Game Services. Since operations like fetching friends, sending requests, or updating statuses require server communication, they are wrapped in Task-based asynchronous methods.

 

For example, the SendFriendRequest function asynchronously retrieves a player's ID, sends a friend request, and handles potential errors:

CODE SNIPPET - Add friends

By using async Task methods, I ensure that network calls do not freeze the game, maintaining a responsive and smooth player experience.

 

Additionally, I use Task.WhenAll to send batch messages to multiple friends when necessary, improving efficiency when handling multiple network requests simultaneously.

GAMEPLAY CONTENT

In this project, I am responsible for developing the core gameplay content, including in-game champions and various other gameplay elements. These are implemented within a client/server architecture using RPC to ensure synchronization.

​

Additionally, I designed an in-game event system built on an async/await architecture and Serialized Interfaces.

Using Serialized Interfaces enhances modularity and extensibility, making it easy for the design team to modify the system and for the development team to extend it if needed.

​

The configuration window, shown on the right, enables designers to add as many events as required at predefined times. For each event, they select an implementation of the IEventTask interface and configure it accordingly.

​

If designers want a new type of event, the development team simply has to create a new event class that inherits from IEventTask.

bottom of page