Hello, Daniel here!
Today I'm going to talk about Zirkon, a game framework on which I've been working on for the past couple of weeks, which will be used to further develop our sci-fi adventure Cryo. In the past, we used the code we originally wrote for Dyingworld, but there were a lot of problems that haunted us during the process of development of both games.
This blog post is more of a technical nature, in which I'm going deep into details of what we're working on. For those who wait for game announcements or news, we're preparing a May progress update which will release by the end of the month.
What is Zirkon?
Zirkon is a foundation for Cryo and possible future games. It is a game framework built on top of Godot that significantly simplifies the process of creation of the game, which will provide tools for designers to easily create new content. Dyingworld's base (to which I will refer as DWCore) was started back in mid-2019 when we transitioned from Unreal over to Godot. Godot and C# itself were new for us back in the day, and the fact that C# support wasn't mature as it is today resulted in fine bolognese and various bottlenecks. For example, because of the fact that Godot didn't support most C# types (arrays, lists, dictionaries), we were forced to use Godot ones to be able to export certain things to inspector for editing. When we wanted to use those Godot types in the code however, we converted them to C# ones, and those operations not only are useless in an exported build (players are not supposed to edit editor values), but also very costly.
When we started our work on Cryo in late 2020, we started to see how poor was DWCore with all of the workarounds and bad code, so around this time I also started conceptualizing DWCore 2.0. Based on the experience and mistakes, the core concepts of it were:
Modularity as a priority: we tried to develop a modular structure but not all parts took advantage of that. With Zirkon, we want to have modular logic as a priority.
Remove unnecessary bottlenecks: Its been a while, and C# support is mature enough to remove all of the bottlenecks we created. Bye bye, CPU torture!
Reusability: we want Zirkon to be more reusable. DWCore wasn't designed to be reused, so it was a pain to make it work for Cryo. Zirkon is not a template for creating FPS games (it doesn't have a PlayerController or stuff like that), rather a Git submodule that we will be using, to build on top of that.
Consistency and simplicity: some of the logic of DWCore ran on a frame process, physics process or a custom timestep (each and every script also had its own timer running, not good), and if we wanted to change that, it was painful. Additionally, It wasn't really consistent. Some things were component based, some were not. We want everything to be consistent, simple and predictable.
Architecture: Zirkon vs DWCore
Zirkon is a hybrid of OOP and ECS. Each Node can have multiple child Nodes called ComponentContainer that host Components. Component is a class that has logic and data, and it can access other Component's data "safely". Each component can be disabled or enabled.
The fancy way to call a Node with components in Zirkon is "Prefab". Now, take a look at the scene tree.
PhysicsLogic is a ComponentContainer that hosts a MoveComponent.
When a Component wants to do something with a Prefab, it can do so by accessing a Parent node from a ComponentContainer. Additionally, you can modify the timestep of the components using ComponentProcessMode enum property, which has 3 modes: Frame, Physics and TimeStep. First two are self explanatory. TimeStep is the custom timer that ticks components. To change the time step, you use the last float property, TimeStep.
As you might've noticed, we actually have two ComponentContainers, PhysicsLogic and FrameLogic. I can safely move the components to different containers as long as logic doesn't rely on physics (applying forces to rigidbodies, moving kinematic bodies, etc.) as things might break, but the point is, its really easy to create additional logic and change how it executes, without even touching the code. This also removes a bottleneck of some of the scripts unnecessarily having their own timers, especially when we had quite a few of them that took some of that sweet frame time.
And not only that, you can extend those components. Say, we have an InputComponent, which only handles keyboard input, and we want to extend it to account our mouse movement. Maybe this is not the best example, but we can extend the InputComponent into MouseInputComponent.
DWCore
DWCore is a different story. Its a mish-mash of everything. At one place it was a component-based system, in the other there was hard coding. It was so bad in fact that I decided to release this monstrosity under a permissive MIT license, so others can see how to NOT write software. Dyingworld's code is the representation of pure pain and suffering. I even start to believe that programmers that are sent to hell are going to be tortured by it.
Just take a look at this folder organization!
This is a SceneTree of the Player. You can already see some similarities to the current approach, but my point still remains. If you were to remove the Inventory, the HealthSystem will crash, for instance. There's no modularity, you can't change the logic on fly (for example, during a scripted sequence), and if you were to do so, you resorted to hardcoding to account for that. It was terrible to work with that.
What's next?
Now that I slowly finish my work on Zirkon, I can finally start rewriting Cryo from ground up. After we use it for a while, I plan to give it the same treatment as Dyingworld's code: release the source under MIT and develop it separately from our games. At its current form I'm not sure if it will get any attention, but as soon as we start working on our custom set of tools, I think the situation will change. For now, our priority and focus is to simply finish the game.
That's everything I wanted to share at the moment. Let me know what you think about this blog post so I know whether you like this form or not, or what I do wrong. Can't wait for your feedback!
0 comments