Clean Sweep
Project Type: PC Game (Windows)
Software used: Unreal Engine 5.3, Git, Jira, Draw.io, Figma
Languages: Blueprints, C++, ink, Google Apps Script
Team Size: 30 (6 core + 24 contract)
My Responsibilities: Lead Programmer, Co-Producer, and Co-Lead Game Designer
Duration: 2 Year and 3 months (on-going)
Awards: People’s Choice MQP Award from Worcester Polytechnic Institute
About
Clean Sweep is a comedic 3D character action RPG where everyone in Cleanland is a personification of a real-world cleaning product. You play as the Janitor who just inherited their aunt’s mansion in Cleanland. Meet various residents of Cleanland and have them assist you on your journey to fight the germs. Make meaningful connections to build up the strength of your party and uncover the mystery unfolding in your aunt’s mansion.
Download The Demo On Steam
Creating Clean Sweep
Clean Sweep was created using Unreal Engine. The game initially started in Unreal Engine 5.1, but was eventually migrated to 5.2, and then 5.3. Clean Sweep started as my Major Qualifying Project at Worcester Polytechnic Institute. We created one of the most ambitious games in the department, and, overall, I could not be more proud of my team. We achieved the People’s Choice Award and are continuing development after college as our own studio, Fresh Start Studios LLC.
Responsibilities
I had many, many responsibilities on the team. I was a producer on the game, lead programmer, game designer, and writer. I’d like to go further into detail on my role as a Producer and Lead Programmer.
Producer
As a producer for Clean Sweep, I created schedules for both the art and tech teams in order to set goals and deadlines for both teams to have, and I was in charge of cutting and limiting scope throughout the course of the project. One of the biggest parts of being the producer was wearing many hats. I had to know how much work needed to be done, how quickly it could be done, and what was happening on every facet of the project. I worked with every person on the team to discuss how things were going and had to adjust the production schedule on the fly due to various setbacks that would arise. I had the pleasure of meeting with Brenden Monroe, a senior producer at Microsoft with over 10 years of experience. He told me as a producer my job will be to wear many hats and to cut and re-prioritize tasks. With all of this in mind, I’ve made sure to listen to every member on my team, find out our strengths, and produce the project to it’s absolute fullest. This has led to us reaching our goals and deadlines such as showcasing at PAX East and releasing our demo on Steam.
Lead Programmer
As the lead programmer, my job was to manage the entire tech team. With being lead programmer and producer, I had a very in depth understanding of every part of the code for the project. Clean Sweep’s tech team followed the Scrum development cycle. I was responsible for leading our weekly stand-up meetings, creating tasks on our Jira board, and assigning those tasks to every member of the team. Additionally, when anyone had questions about the project or wanted insight on how to go about developing and integrate a system in the project, I was the one who was reached out to. I also wrote extensive documentation on the tools we created and used for the project. Overall, this boosted my ability to program within Unreal Engine. Becoming a resource allowed me to teach what I was learning and gain an overall better understanding on not just the engine, but programming in general. I led the weekly sprint, reviewed code people submitted for PRs, and I guided the team towards a finished project.
Systems
Over the course of the project, there were numerous systems that I had worked on. This includes the Enemy AI, Combat, Dialogue, Quests, Time, and various other smaller ones. Below, I’ll go into detail about the systems I’m most proud of.
Combat
Our initial combat system was... interesting. The combat in Clean Sweep built upon the hitbox notify state that was created in Steam Punch. The main issue we faced was that our character combat code was built entirely in Blueprints. Combat required each character to have unique abilities, unique stats, and unique effects (buffs and debuffs), while allowing the player to swap characters. Trying to work around these issues was very challenging. It took a lot of effort, but we did end up having the combat working with 3 playable characters.
The main issue, which was becoming readily apparent, was that this system was not scalable. Every time a new character was added, the entire base character class needed to be modified to support the new character, whether that be adding a hook to activating a new ability, refactor code that would otherwise run fine on every other character, and add new references to the new character’s class. That in itself was an issue. Swapping involved us destroying the player character, spawning in the class of the character we were swapping to, and possessing that new character as the player character. This caused a lot of headaches and didn’t allow for much communication between characters which needed to happen for yet-to-be-implemented abilities. Every fix to address a new issue felt like a band-aid solution that was ready to collapse at any second.
In order to solve this issue, I researched into potential solutions. I had a couple of goals in mind that the solutions needed to allow for:
- Instead of using 1 class per character, use 1 character that takes on the abilities each class
- Make abilities and character information more modular
- Make abilities separate from the Base Character Blueprint
Having a single actor would solve our issue of cross character communication while making the abilities and information modular would allow for better multi-person collaboration and prevent merge conflicts. Merge conflicts were a growing issue with the old model since only one person could work on combat at a time and if someone had outdated code, we’d potentially have to spend hours figuring out what code needed to be copy and pasted into the latest version of the blueprint asset.
My research eventually made me stumble into the Gameplay Ability System (GAS). GAS was an extensive combat system complete with abilities, effects, stats, and more. It was the perfect fit for Clean Sweep’s own combat system. In order to better grasp GAS, I had dedicated time to study both Lyra and the ActionRPG starter project. I also took time to study a great community resource, GASDocumentation, a fantastic resource created by Tranek and numerous others. I used this Github repository as a guide to assist in understanding and implementing GAS for myself. Setting up GAS was a bit of a challenge. Implementing stats, effects, and abilities was not very difficult, but the main challenge came from the core combat loop of Clean Sweep: character swapping. Unfortunately, every actor can only have a single Ability System Component, the component responsible for a character’s stats and abilities. I was initially hoping to swap which one was active, but that was impossible. I solved this roadblock by creating a separate actor that I called BP_PlayerData.
This Player Data actor was responsible for holding the stats, abilities, and character information of every active member of the party. Abilities would be activated and deactivated on swap and the Base Character (Clean Sweep’s player character class) was acting as the avatar controlled by each player data. Now swapping was as simple as changing the mesh, materials, and animations of the character while activating new abilities. This approach fulfilled all goals I had in mind, leading to a fully scalable system that would allow for easy creation of new characters.
Enemy AI
The enemy AI in Clean Sweep was modeled loosely after the Spider-Man PS4’s AI system. Thanks to the video The AI of Marvel’s Spider-Man | AI and Games #74 by AI and Games, we had a decent understanding of how Insomniac modeled the AI for Spider-Man. Our system was different than theirs, but mainly took inspiration from their Combat Management Systems.
We created AI token managers for each enemy AI that was responsible for handing out tokens for germs to attack. Germs could only attack when they had a token and would return it after completing their attack or taking damage. Tokens had the ability to be requested or stolen from other enemies. The amount of available tokens varies based on the current “intensity” of the encounter, changing based on difficulty and how long a player goes without swapping. The intensity value also determined the likely hood every second that an extra token would be generated that an enemy could request. If there were no available tokens, the enemy would wait for the next available one. If the player approached an enemy, for example a melee germ, and entered it’s radius, the germ would steal a token from the furthest away germ. There was also checks in place for seeing if a germ was too far away to request a token when it would be more reasonable to have a closer germ attack the player.
The token system was a great addition to the game and allowed for more control over every enemy’s attack patterns. There is still much work to be done to improve the AI systems that I hope to write about soon.
Event System
Clean Sweep is a very event driven game. Most actions within the game are sent out as events to any part of the game listening. The Global Event Handler plugin assisted with the sending and binding to various events. In order to minimize the size of events being sent, we found that every system in our game at most needed an integer and a name sent out as data with a gameplay tag dictating what kind of event was sent out. While the event system was simple, it was very important and fundamental to almost every system within the game. It allowed for systems like the Quest System to listen for player actions, the NPC system to listen to time events and control spawning, and the Dialogue System to listen for events to further the story. The event system was also a fundamental piece in a core actor known as the Scriptable Actor Parent.
These actors were responsible for listening to the events in the world and either displaying or hiding themselves. There were numerous children responsible for different effects, for example, some would trigger narrative events, others would block doors, and some would kick you out of a shop when they closed. These actors helped to advance the story forward, providing in-game visual effects and consequences brought about by completing story or quest missions. The event system was crucial in allowing cross-system communication and had the advantage of not needing every system to constantly bind directly to others since event binding happened based on the event to listen to, not the actor or object calling the events.
Quest System
The Quest System has been one of the most updated and revised systems we’ve had in Clean Sweep. Initially, it only supported linear quests, but currently supports large, branching quests with multiple endings, secret stages, and varying rewards and interactions. One of the biggest innovations is how we interpret quest data.

Each quest task is encapsulated in an object. The Quest Manager finds the quest task type associated with a specific stage’s objective, instantiates the object, and uses it as an interpreter to determine if the incoming event updates or completes the quest objective.

Each task object can interpret the incoming data as it pleases. Some tasks only use the tag coming in while others may use the name and int to determine how much to advance the specific objective. Once the data has been successfully processed, the quest’s active progress data is updated.

By using this design pattern, each new task type becomes extremely simple to create. It has allowed us to expand our quest system to listen for any kind of event. The most we need to do when creating a new task type is make sure we call an event somewhere in the game that the task will process and return that it is updated. The task system also allows us to directly link UI to the quest system, pulling the necessary data and allowing for auto filled in values such as task goal, name, and progress.
Dialogue and Flow System
Our dialogue system is built using the plugin Inkpot by The Chinese Room. It gave our writers the ability to write dialogue more closely to text than actual code. We also used the Flow Graph plugin developed by Moth Doctor and numerous other contributors. Flow Graph assisted in created scriptable events. Every action was a node created in C++ or Blueprints that the game performed, which included moving a character, spawning an actor, attaching an actor to another actor, playing dialogue, controlling music, or changing maps. I integrated the two systems together to allow for the dialogue system to advance the flow system, creating more interesting and dynamic encounters.
Our dialogue system also had custom variables that writers could set directly, influencing who was speaking, what sprites to use, and what voice line to play. Writers had basic control over dialogue UI for things like sprite animations so they could better build their scenes even without character facial animations. The system also interfaced with numerous other systems so dialogue could perform actions like completing quests, granting money, granting items, spawning actors, and changing time.
Development Tools
One of my most major responsibilities was making sure that everyone knew what they were doing and had an easy time developing. As broad as that was, it was up to me to ensure that everyone understood how to use the tools that either I developed or were part of the engine, as well as how to debug any issues. This led me to create documentation, tutorial videos, and “instruction manuals”. One example of this is a Draw.io document for writers on how to format quests for our programmers to implement:


Another way I supported development was through software I wrote. I developed a basic plugin to assist both designers and writers on implementing various game files. Our repository automatically imports files from our Google Drive, but unfortunately, .csv files, our main file for character and enemy stats as well as NPC schedules, cannot be edited within google drive. This would mean everyone would need to download the drive file, manually edit, and upload the .csv files. This worked, but I found it not ideal especially when wanting to take advantage of Google’s Sheets features like multi-person collaboration, highlighting, and commenting. In order to solve this, I created a custom Google Apps Script that automatically exported the necessary files as .csv files within the drive and distributed it to the designers and writers as a browser plugin.

Finally, some of the more in-engine tools I created were editor utility widgets. As of now, there are two main editor utility widgets. The first, created mainly for the writers, is the NPC Target Point Tester. Our NPC spawning system utilizes target points to determine where any npc should be at a given time. Each target point needs a unique tag and ample space to spawn an NPC. Writers, when adding these points to each map, needed a good way of testing this. I created this utility widget that would check for if the tags followed the proper naming conventions, were of the correct target point type, and if an NPC had space to spawn. It also, for organization purposes, had the ability to rename all target points to their tag name as well as update old target points that were used by the old system.

The other tool is the Scriptable Actor Parent Actions Widget. This tool checked levels for their scriptable actor parent actors and their children. It checked their conditions for appearing and made implementation a lot smoother. It made keeping track of every actor that could or couldn’t appear a lot smoother as well as point out immediately any issues as to why the actor would fail to spawn or destroy itself.
What's Next?
Clean Sweep is still on-going development! My team plans on working to fully publish the game in the future. Since this project is still active, not all of the information here may be fully up-to-date or accurate. If you want to follow development more closely, please take a look at our Steam page or our Itch page! There we have devlogs listed that more closely tell the active development story for Clean Sweep.
What I Learned
I have learned more than I can ever quantify due to this project. Clean Sweep has gotten me very comfortable with using Unreal Engine. It has taught me how to build a game from the ground up and scale it for the future. It’s taught me numerous development skills like how to pivot when things aren’t working, how to know when to cut scope, and how to plan for the future. It has improved my C++ skills considerably, and bolstered my game development skills. It has made me constantly think about system design and how to build a system that integrates with numerous others. It’s also taught me how to work on such a large team. It’s given me the skills to work well with others and how to onboard and assist those joining. It’s made me value and appreciate good documentation and implementation guides. I’ve also learned when I should spend time developing my own solution when plugins are freely available to ease development. It essentially helped me understand when I should avoid reinventing the wheel.
Clean Sweep has also helps fuel my passion to learn and grow as it makes me strive to continually learn new things to help fully realize this game. Since the project is still on-going, I know that there is so much more that I will learn from it!