Leaves of Fate Logo
← Back to About the Game

💻 About Tech 💻

Key Takeaways

  1. Using source control is critical to the technical process.
  2. Develop crucial features first and ignore everything else.
  3. Research game code and architecture ahead of time.
  4. Plan for and create custom developer tools. It will pay off.
  5. Understand what your engine can do, can’t do, and how it’s set up to help you.
  6. Borrow, don’t build.
  7. Be careful about technical debt.

Tech Goals

Because our core team is basically all programmers, we established strong technical conventions and practices early. We set up our development process to be quick and easy to give us more time to iterate on our designs. To this end, we developed a comprehensive Tech Bible to use as a reference throughout production for anything related to tech. Here are the major decisions we made.

Source Control and GitHub

We established clear cut conventions and practices for using source control, git, and GitHub in our tech bible and made setting up source control and a GitHub repository the very first production task.

Read more about our git guidelines and conventions in the "Source Control Rules" section of the Tech Bible.

Lesson 1: Using source control is critical to the technical process.

Collaboration at this scale is impossible without source control and clear conventions. Make a plan and make it the first step of production.

Major Code Systems

Knowing that we wanted to make a 2D platformer, the major systems we started with were:

See the list of systems we brainstormed in pre-production here:

The major systems we figured out we also needed during production were:

We sometimes fell into the trap of designing code for features we thought we would need, not simply the feature we needed, which wasted development time. One example is player health. We developed a full player health system and had to build the player dying on top of it. Then we switched to making the player die from any hazard, meaning we had to refactor and disentangle player health from player death logic.

Lesson 2: Develop crucial features first and ignore everything else.

If you find yourself working on a feature you think you might need, table it. You can come back to it once you realize you actually need it. It will make your code less cluttered and easier to understand.

Modular Design & Game Programming Patterns

We wanted to develop code that let us modify a value to test its impact on game feel without recompilation or idle time. For this purpose we decided to use data driven design as our main programming paradigm. We successfully used data driven design throughout production, especially in the early stages.

Read more about our use of data driven design in the "Data-driven Design" section of the Tech Bible.

Later in production we discovered the value of entity-component systems (ECS). ECS is a software architecture pattern that focuses on composition instead of inheritance. Data-driven design focuses on modularity through reusable systems, and ECS takes the concept of modular code to a much higher level than OOP. We realized that ECS complemented many of the systems we hadn’t anticipated needing and pivoted to make use of its principles. Adapting to make use of entity-component systems gave us the modularity we use for cutscenes, the player interact and grab, and game event triggers.

Read more about our use of ECS in the "Entity-component System" section of the Tech Bible.

Lesson 3: Research game code and architecture ahead of time.

Doing research helps you determine what architecture or programming patterns will best support your game. It also gives you reference code that makes designing your systems easier.

Creating Dev Tools

In pre-production we determined that making custom developer tools would make our development process faster. Our primary ideas for custom tools were a level editor and a debug menu. While we had these ideas in mind, we did not document or plan out what tools we wanted explicitly.

Early in production we developed a rudimentary debug menu, essentially on a whim. It had two features: a debug property panel for watching values change during runtime and a noclip panel for teleporting the player to any room. As simple as it was, the “on a whim” debug menu ended up being critical to our design process because it let us quickly test ideas and playtest room designs.

Read more about our design process on the Design Page.

Lesson 4: Plan for and create custom developer tools. It will pay off.

Take some time to plan out some developer tools that would be helpful to your team and put effort into them early. Developer tools should not be an afterthought.

Also, keep it simple. Simple tools can have a big impact. You don’t need a fully fledged level editor to speed up your process.

General Tech Pipeline

How Godot Supported Our Tech Goals

We decided to use Godot because it was the best fit for our game’s genre and our goals. Here are some of the major draws of the engine:

Selecting Godot as our engine worked out really well for us. We prioritized understanding Godot’s core features and OOP-based mindset. Here are some engine features that we used and learned from throughout the entire development timeline:

Because we prioritized understanding Godot’s core features and OOP-based mindset during production, there were some features we planned to use that ended up on the backburner. In future projects we want to take advantage of features like:

Read more about how we set up and used Godot here: Tech Bible

Read more about Godot Engine's features here: Godot Official Docs

How Godot Hindered Our Tech Goals

Godot has some limitations that slowed development because we had to find workarounds to get things up and running. For example, Godot’s scripting language does not have support for structs, interfaces, or nullable static types. This hindered our ability to follow Godot’s OOP-based mindset and is what led us to learn about and use entity-component systems. Going into production we did not realize that these features were unsupported by Godot, and we could have prevented some of our technical debt if we had known earlier.

Lesson 5: Understand what your engine can do, can’t do, and how it’s set up to help you.

Game engines are designed to serve a specific purpose for a particular programming mindset. For example, you wouldn’t use RPGMaker to develop a first person hero shooter. Once you make a decision about what engine to use, do some research to understand how the engine wants you to structure your project and what features it provides for your use case.

Also be lenient with yourself. Projects like this are a learning experience, and no one knows exactly how to use an engine out the gate. You don’t know what you don’t know, so don’t beat yourself up over it; be willing to adapt and learn what to do better next time.

Using Plugins

Godot provides powerful building blocks, but developers need to build their game’s systems out of those blocks. Using Godot plugins saved us a lot of time by giving us pre-built versions of complicated systems that show up in many different games. For example, the dialogue system, smooth camera manipulations, and player states are all thanks to Godot plugins we found and used in our code. Plugins let us focus on implementing the systems unique to our game.

Read more about the plugins we used here: Tech Bible

Lesson 6: Borrow, don’t build.

Borrowing from existing projects made Leaves of Fate possible. Borrow from existing projects instead of reinventing the wheel.

Retrospective

One of the biggest challenges we faced was technical debt, especially in the last three weeks of production. The rapidly approaching deadline led us to cut technical corners a lot of the time. The conventions we had difficulty maintaining during production were:

Looking back, we realized that it is important to routinely iron out inconsistencies and bring project files up to standard to prevent technical debt. We did do some cleanup but it was always when someone didn’t have something else to do or was already refactoring something anyway. This caused us a lot of stress and crunch time in the final weeks of production because we had to deal with disorganized code to get final features and systems working.

Lesson 7: Be careful about technical debt.

Periodically make sure to bring your project files up to par. It’s never a bad idea, especially if you’re working on a project over a long period of time. Conventions are easy to overlook when you “just need to get it done”, but technical debt slows everything down the longer it goes unattended.

Tech Bible

Want to see even more about tech? Check out the Tech Bible below for all the details.