Kicking off Vessel
- Rickperros

- 3 days ago
- 5 min read
Overview
In this post I’m talking about the project kick off. While most of the explanations will be quite technical I’m trying to keep it as an easy to read article. First, I will show which tools I choose to develop Vessel and explain why I decided to go with them. Then, I will dig into the code philosophy and strategies that we have adopted as a team, and talk about the reason behind choosing those. Phew! That will be quite a lot so let’s begin!
About development tools
Before diving into Vessel's technical set up and chosen tools, I want to drop here my vision on digital tools. Short and loud, a tool is a tool and it shall be chosen for being the most adequate for the job that you are trying to do. I know it might sound obvious but for some reason in the tech industry people tend to choose those like they are sports teams and usually forget about that basic premise. If you are not familiar with game development you might think: “Well, they are all game engines. They shall be similar”. And you are right, they are similar in the same sense that a chainsaw, a knife, and a scalpel are used to cut things. They pursue the same goal but they differ in their usage a lot.
So before explaining the tools that we will be using to build this game, we need to define the needs of the project:
From an art perspective, Vessel is a 3D game that will use low poly models lighted in real time. Since we are aiming for this retro PS1 (early PS2) graphics mostly any commercial 3D game engine like Unity, Godot, or Unreal can render it.
Regarding animation, we are aiming to use a realistic low fidelity style. This field is a big constraint for the team since we don’t have anyone fully dedicated to it yet. Therefore our goal is to use, reuse, and elevate bought assets as much as we can. In that sense our perfect engine shall allow us enough freedom to work with animations in it.
From a code and design perspective, the biggest challenge is building the companion AI. While most of the game will fall into the team's know-how this is a new challenge. So the perfect tool shall have quite extensive AI tools.
It is worth mentioning that we are not taking into account sound and music necessities since we are outsourcing them. Therefore, it is very likely that we end up using some middleware like FMod or WWise which are supported on almost any commercial tool.
All in all, we decided to build Vessel using Unreal Engine 5 as the game engine. Mostly by its better animation tools, its behaviour trees and AI support that come out of the box, and its particles and cinematic tools. Also, the team has more recent experience working with this and the know-how is a big plus.
This engine is distributed using two ways, you can either have the compiled version distributed through the epic launcher, or you can have the source version downloading the repository. We chose the first one for three reasons: reduce friction with the engine (using the compiled version means less freedom but also doesn’t require maintenance and support), simplify the start and version distribution across the team, and reduce development costs. I think this requires a more in depth explanation. Unreal Engine source is massive, really massive. Using it from source means that we need to add it into our own repository to make sure the whole team works on the same version; and since we don’t have any infrastructure to host this repository, we will need to start paying upfront just to keep the engine.
This leads us to the next tool, we will be using Git with Git LFS as a source control tool for Vessel. The main reason behind this is, again, to reduce costs. Unreal Engine serializes its assets in binary format. While git is not the best tool for this use case (P4 will have been arguably a better choice), the hosting solutions for this tool are bulk cheap in comparison with the others and allow a more granular scaling in the case the team grows. Specifically, we will be hosting our repository in Github, mostly by its pricing but also because it has support for diffing tools and it can be linked to a variety of visual clients which makes it more interesting for non coders.
Regarding code editing there are mostly two tools to choose to work with Unreal Engine. Visual Studio Community, or Rider. I personally use Rider since I find it faster and more helpful when pairing it with the engine.
As an overall philosophy our aim is to reduce any friction to the bare minimum and get the best results with the lower costs. This is, unfortunately, a must to make sure we are capable of building the game. That philosophy shows up on the election of the engine version, or the decision of buying some of the assets (like animation packages) instead of outsourcing a personalized content for the game (which will require manwork and be a lot more expensive).
About coding strategy and philosophy
From code perspective, this development will be influenced by two major constraints:
The lack of QA during the development phase.
The development time needs to be tight to make it profitable.
With that in mind the main goal is to build the code in a way that is modular, testable, and easy to maintain in order to avoid pitfalls and a neverending final bugfixing stage. To achieve that the team will be using several strategies based on defensive programming practices.
The first one is pretty standard, we will favor composition over inheritance when designing the systems and designate “breaking points”. In essence, all functionality will be encapsulated into components (following the single responsibility principle). Those components will be completely isolated among each other and get any reference they need by injection. Those components will be connected at actor level and communicate through them creating a localized “weak point” in the code architecture.
That makes the components a perfectably testable unit, meaning that we can just set them up, give some inputs and check the outputs with no dependencies at all. Notice that our goal is not to test the implementation but the functionality so we are not aiming to test every line of code but the overall component functionality. This is useful since our tests will ensure that components are working as intended, therefore if some issue happens it will be happening at actor level. That is interesting because it allows us to apply our efforts better.
The second one is crashing the game as early as possible. That doesn’t aim to ship it broken, but it aims to detect bad states as early as possible by crashing the game every time we detect an ill formatted var. That allows us to fix things quicker since errors are really noticeable. In order to not block the non-coding part of the team we pair it with feature flags. This allows us to disable any feature if we detect it is broken, which allows non-coders to keep working even if we struggle to find the fix.
The third main strategy is to use a variant of gitflow when working in the repository using a branch-per-task approach. This simplifies repository management and therefore reduces maintenance efforts.
Final thoughts
That has been a ride! As you can see our biggest constraint and the reason behind a lot of suboptimal choices regarding tools is the lack of funding and the need of being open to scale our infrastructure if needed. Some of these choices have a future hidden cost (like Unreal license). But let's discuss those when we arrive at that point. Hope you find it interesting, and as usual, drop a like, comment what you think about these choices, and join me on Discord!




Comments