Kibbi Keeper is a single player virtual pet exploration game in which the player must collect all 6 Kibbi in order to unlock the temple gate and win. Fifteen developers worked on the game in house, and five more produced most of the audio assets for the game from outside the studio.
As the lead programmer, with a team of 4 other programmers, I wrote tasks and managed feature implementation. I also worked closely with LDs to implement and optimize Unreal’s level streaming system for a relatively open world. Towards the end of the project, I worked on optimizing the game in all aspects, eventually achieving a stable 120 fps on our Guildhall laptops.
Kibbi Keeper was my first experience leading a team of programmers, and it taught me a lot about the way that leads have to think in order for a project to get done. Leads have to be masters of delegation, planning, and research (all of which I usually consider myself to not be good at).
KIBBI KEEPER Post Mortem
Kibbi Keeper suffered in the early stages from a lack of clear direction in the game and puzzle design. Even towards the end of the project, some of the game’s major puzzle systems had not been fully implemented, and the Ice Kibbi puzzle system turned out to be quite confusing to new players. We should have thought even more about how we teach the player the ice Kibbi puzzle mechanics in particular, because it requires a very specific solution that most new players did not think of.
Some of my personal learning outcomes:
I should have done more research into Unreal’s built in crowd navigation tools, because towards the end of the project we had a lot of issues with Kibbi pushing each other outside of the navigation mesh (and that bug still exists in rare cases).
I also did not discover Navigation Invokers in Unreal until the very last week of the project. Level streaming in combination with an open world caused large hitches when the player moved into and out of level streaming volumes. In the unreal frontend software, I found that Recast nav mesh building was to blame, and it was only then that I discovered Navigation Invokers as an alternative.
Some developers like to keep to themselves, which makes leading them very difficult. In that scenario, the lead must be the one to constantly reach out for updates so as to not be blindsided by issues that build up over time.
We (mostly Jacob Asofsky) developed a VR demo for the game with completely different mechanics alongside the main game. We should have put the VR project into its own unreal project, but due to convenience we kept it as a part of the main project. One major consequence of this was that when I switched the project to use Navigation Invokers to test them in the final days of production, it completely broke the VR game. By the time we realized this, it was too late and we had to revert the change and ship the game without invokers.
Snowpainters, released on Steam and built using Unreal 4.26, is an arcade racing game where you control penguins sliding on ice and paint. Some of my responsibilities on the project included camera behavior, performance testing, LOD, GameMode, and Audio Implementation.
I also heavily advocated for the team to get familiar using event dispatchers to clean up code and make the codebase easier to use across sub teams. Having events for race logic meant any blueprint could subscribe to those without needing to check out the file. Getting everyone on the team up to speed with these was a priority for me since I knew it would save the team a lot of headaches.
Race Events on the GameMode
For the main camera behavior, I used a spring arm as well as a look ahead point rather than a fixed camera angle. The camera LERPs a percentage of the way towards a “goal” for four different attributes, which were customizable by our designers through a struct of camera constants in the Game Instance. I heavily utilized Lerps based on deltaSeconds to make the camera behavior feel smooth in all situations, but perhaps not completely framerate independent
Custom Camera Lerps each frame.
Readable blueprints are important in large projects, because you will not be the only one looking at them. Often times I found that my peers had pattern matched my camera code, which made it feel like I was already familiar with code that I had not written. Because of this, I pushed for common coding standards on my capstone team to improve workflow.
As far as audio implementation goes, I was responsible for some of the audio events as well as writing a system to lerp between 3 continuous sliding sounds (one for normal snow, one for paint, and one for power sliding).
For performance, I was tasked with figuring out why our game’s framerate continuously and noticeably degraded over time. Using the unreal performance tools, I found out that every instance of our paint trail blueprint, of which there were 5000+ towards the end of a race, were ALL on Event Tick. Once we took paint trails off of event tick, our performance no longer degraded. I also took point on teaching artists how to LOD their static meshes, and personally set the LOD settings on many of the assets as the artists were swamped with work (only 8 artists for the whole game).
SNOWPAINTERS Post Mortem
This project was very important for my development as a software engineer, as it was my first major project working alongside other programmers. I was the only programmer on the team for my first Guildhall project (Mission Impossumble), so it was not until Snowpainters that I really got a sense for what it is like to work on a large team.
For a first publication, I feel that the team did very well under pressure to get the game in a workable state to launch. Our leadership did a great job giving out tasks and our process of using Jira and Scrum to facilitate task communication was key to the success of the game.
Mission Impossible is a stealth platformer built in Unity 2019.4.1 in which you control Penny the Possum on her journey to the trash kingdom. Along the way, you must hide in boxes and hiss at cats and animal control to scare them away or provoke them into traps. At the end of each level, Penny jumps into the Dumpster victoriously, feeling very sneaky and mischievous.
As the only Software Developer Track member of the team, my responsibilities were AI, physics, UI implementation, game mechanics, animation implementation, and builds.
using UnityEngine; public class Hide : MonoBehaviour ... public void HideInNearestBox() { Box box = GetNearestBoxInRange(); if (box) { isHiding = true; jumpInBoxAudio.Play(); } } public void JumpOutOfBox() { if (isHiding) { isHiding = false; jumpOutOfBoxAudio.Play(); } } public Box GetNearestBoxInRange() { float closestDistance = hideRange; Box resultBox = null; foreach (Box box in FindObjectsOfType<Box>()) { Vector3 boxPos = box.transform.position; Vector3 pennyPos = transform.position; Vector3 displacement = boxPos - pennyPos; if (displacement.magnitude < closestDistance) { resultBox = box; } } return resultBox; }
MISSION IMPOSSUMBLE Post Mortem
I learned a lot about communication on teams in Mission Impossumble. One day, one of our teammates made very logical concerns about the whiteboard design of the tutorial level, and another member of the team was pushing back a lot about it. The former team mate was getting flustered and their eyes were watering, so I decided to step in and describe the merits of both lines of thinking, and eventually convinced the team that the former’s line of reasoning made sense for our situation. Sometimes when two members are arguing about one decision, it takes another to step in and mediate to get the team back on track and working together. Also, game design is extremely subjective in most cases, and its not worth fighting with team members about ideas until you are playing it on the screen in front of you.