top of page
Search

Boyfiend & Ghoulfriend: Postmortem

Writer: Travis Pynn
Travis Pynn
Jul 23
6 min read


I’m writing this a bit late (Apr. 13), two months after the release of the game. Going forward, I should really do this immediately after launch. But I digress.


Learnings

I want to focus this reflection mostly on two things:

  • The technical learnings regarding Unreal

  • The tempo learnings


Tempo

Regarding tempo, I was able to create a pretty fun prototype fairly quickly. By the end of September (~1 month), it included the characters’ platforming abilities with jumps and gravity settings that felt tight, as well as their basic abilities (fireball and dig). I took the button logic from a different prototype I had been working on, but I ended up reworking a fair chunk of it anyway.

Room used for prototyping new mechanics and testing player metrics


Within 2 months I had most of the mechanisms working (which I’ll get into below), as well as five(?) fully playable levels. I didn’t reach my original October deadline, but it was still good to have since it kept me focused and working (most days).


Milestone: Alpha

By late December, my first alpha build was ready for playtesting. It had some major issues, but most people who tried it had fun, which was a good sign. Most were regarding the checkpoints which were recently added, so going forward, I think I’ll avoid playtesting content that is too new and unstable (even if it did give me good data).


Polish & Juice

I wish I had more time to polish - I’m mostly happy with the music and sounds that made it in, but the VFX and animation are pretty barebones. Same with the UI. Bugfixing and testing took longer than I was expecting, so a few polish items were shelved. Going forward, I should try to make better use of the Cheat Manager in tandem with other debug methods to increase the speed of my personal testing.


Overall, the process was approximately six months (Sept. 7 - Feb. 13), with about 4.5-5 months of actual work considering days I took off, holidays, etc. That time frame allowed me to create a cooperative puzzle platformer with 24 stages, which amounted to around 3-6 hours of playtime.


Technical Aspects

Dynamic Mechanisms

I’m pretty proud of the Dynamic Mechanism actor I was able to come up with and how modular it ended up being by utilizing both components and interfaces. Torches, moving/rotating platforms, gates, and more all inherited from this class.


Going forward I may rework the logic if I want to reuse it for future projects, as it had some flaws - I should have used Enumeration for their state instead of booleans for active/inactive and locked/unlocked. I also never really used the locked bool. The idea for it was to have some puzzle elements to be in a "locked" state so that they couldn't be done out of order, or the players would need to solve one part of the level to get to another, but I found it was easier to just do that in the level design itself.

A snippet of the Activation Event of the Dynamic Mechanism actor blueprint


Camera

Utilizing the orthographic camera to create a 2-dimensional look with an entirely 3D space and level construction was another proud moment. It gave the game a somewhat unique look in my opinion.


Stage 1-1 from its normal view

Stage 1-1 from its perspective view


That said, I learned that the orthographic camera makes it very difficult to achieve realistic lighting, so I had to spend quite a bit of time moving lights around, tweaking values, and adjusting post-processing to make things look right.


Classes & Coding Practices

I learned a lot about the relationship between actor components, events, interfaces, and good practices for object-oriented programming. That said, I still had too many weird dependencies at the end which made some aspects difficult to debug.


GameState

This was my first time trying to use the GameState class (as a LevelState), and while it worked for the most part, I think I ended up putting too much logic in it rather than simply using it to store information (i.e. the “state” of the “level”).

The Level State blueprint ended up being responsible for a LOT of things


Save Game

I was really happy to learn about the Save Game class and how to achieve session-to-session persistence. It was a much harder feat to apply that knowledge in checkpoints (level persistence), as utilizing the Reset Level function from the game mode was tricky to understand since it didn’t really work on the players. Creating custom ID variables was really helpful here. It was also cool to make the connection that I could utilize this for the Options menu as well, including accessibility toggles that are stored in the save, making A/B tests a very simple include.


Get All Actors

I learned that Get All Actors of Class is NOT good to use for things that should be ordered, as it returns differently in packaged builds compared to the editor. My solution was to manually make the arrays I wanted, but I want to figure out a better way to do this in the future, if possible.

Stage goals had to be manually assigned to the array to make sure they appeared in the desired order in the UI.


Physics

Physics kinda sucks to work with (at least in Unreal). The movable boxes got caught on the floor in multiple cases, the player sometimes wasn’t strong enough to push it, yet other times could send it flying. Jump hold time was easy to set up, but broke at low framerates (as did box physics). Going forward, I will probably try to rely on physics simulation as little as possible, and utilize gameplay abilities or root motion for jumping and stuff.


I will also make sure to add an FPS limit early on so that my packaged builds aren’t running at 2x the FPS as the editor and causing problems.


Platforms

The physics of moving objects/platforms also had problems at lower framefrates. One-way platforms in particular are something I may rework if I do another platformer. I’d like to make it impossible to fall through while they are moving, potentially by adding a check to see if the player is above the one-way check instead of below it before disabling their collision.


3D Art

I dabbled with Unreal’s modeling mode a bit to create variants of the mannequins for my characters; it felt similar to my brief foray into ZBrush (many years ago) so it was interesting to play with. I’m glad I did, as it made their silhouettes much more unique.


Other Reflections


Scope

Challenge Medals

Adding the level challenges happened later into the process and wasn’t part of the original idea, but I think it ended up being one of the more engaging parts of the game. It also was really helpful in learning how to track different statistics, save them, and evaluate them - I’m pretty happy with the Evaluate Goal function and how clean it turned out to be by utilizing inheritance.

Evaluate Goal is an Interface function, so each goal subclass can easily check it in its own way


Player Abilities

I also think I focused a bit too much on player abilities - I kept adding new things like the enhancements, which weren’t part of the original design. This allowed me to make some interesting puzzles and they were genuinely fun to use, but took up more time and was a definitive example of scope creep.


Marketing

Marketing was really hard to get into. Starting up a Twitter account didn’t achieve much, but I didn’t post as often as I should have. I made a TikTok post-release, so maybe I’ll try to post some videos there during a sale at some point. Regardless, I think going forward I want to keep more of an active devlog for my projects and remember to record WAY more of both my process and my progress.


Steam Achievements

Something I really wanted to add but didn’t get to was Steam achievements. I tried at one point before the alpha, but it broke my ability to build, and I realized I couldn’t be focused on it so I just scrapped it all. A major goal of my next project is going to be to get that SDK set up correctly and make them work!

UPDATE: I spent some time post release to do more research and get them working!

 
 
 

Comments


bottom of page