Frozen Sprouts
2D Renderer with Vulkan, Extensive Multiplayer Techniques, Old-school 2D Combat, Game AI, Physics-bases Puzzles
2D Renderer
Multiplayer
-
Coop Peer-to-peer -> Dedicated Server, login system, authentication server, gateway server, dedicated databases for credentials and world data.
Entity Component System (ECS)
Old-school Combat
Level Editor
Game AI
Physics-bases Puzzles
Odin Lang Fork
Language design and safer code
-
Odin Language fork focused on exploring language design, memory safety, explicitness and other subjective things.
-
A detailed explanation of the changes is documented in the fork located at: caioraphael1/Odin.
-
There was a lot of investigation and discussions around the main topics of change in the fork. For more information see my studies on Odin, or more specifically about the usage of context.
3D Vulkan Renderer
Exploring modern rendering techniques with Vulkan, using Odin Lang
-
A custom 3D renderer built to explore modern real-time rendering techniques while addressing the complexity of designing an easy-to-use API on top of Vulkan. The renderer emphasizes performance through aggressive CPU task parallelization using a custom job system and an ECS-based architecture.
-
It implements advanced GPU-driven techniques such as bindless textures and indirect drawing. It was instrumented from the start, with extensive profiling and debugging using RenderDoc, Tracy, and RadDbg.
-
Future work includes implementing Radiance Cascades for global illumination and Screen Space Indirect Lighting with Visibility Bitmask for ambient occlusion. A strong focus is placed on atmospheric lighting, neon-inspired post-processing effects, and support for heavy visual stylization.
Read more
Implemented Features
-
Camera system
-
Ponctual Lights
-
Forward renderer with PBR materials
-
ORM Textures.
-
Ambient Occlusion.
-
Metallic Map.
-
Normal Map.
-
Tone-Mapping
-
Skydome
-
Pre-recording of commands
-
Multithreaded texture loading
-
glTF/glb models with the gltf2 parser
-
Tangent generation for models missing tangents
-
I settled for an implementation based on https://terathon.com/blog/tangent-space.html, by Eric Lengyel. The MikkTSpace's tangent generation is probably a better algorithm, but the current Odin binding for it was quite a mess, so I opted for something a little bit more sane.
-
Multi-window system
-
Wrapper around image transitions and pipeline barriers, to improve synchronization consistency and API usability.
-
Descriptor Indexing / Bindless
-
Entity Component System (ECS)
-
Multi-Sampling Anti-Aliasing (MSAA)
-
Mipmapping
-
Custom Vulkan Allocator and custom CPU Allocators, for general tracking of memory usage/peaks with Tracy
-
GLFW input system.
-
Easy-to-use graphics pipeline creation via shader reflection with spirv-cross.
-
Depth Prepass
-
HDR composite pass
-
Jolt Physics
-
Jolt is an awesome physics engine, used now by Godot.
-
I made the bindings for it here: caioraphael1/jolt-odin.
-
The engine makes a wrapper around the binding. Dealing with the wrapper should be *much* easier to deal then with raw jolt, but the main goal is re-writing Jolt in Odin.
-
Custom Multiplayer library
-
Completely focused on server-side authority.
-
Custom RPC system with raw TCP packages
-
Supports authentication systems with a gateway and tokenizers, user databases and world databases.
-
I got good performance for a server-side prediction, reconciliation, interpolation/extrapolation, and a soft-rollback system. To make that work, I use it side by side with the fixed cycle system and some multithread + jobfication
-
Support for UDP packets and CPU drifting corrections will be implemented in the future.
-
Custom Job system
-
Cached transforms system
-
Cycle and Fixed Cycle system
-
Crucial for multiplayer, and a way to manage input processing, draw times, etc. Used in conjunction with a sleep scheduler system to avoid using too much CPU time.
-
Tween System
-
Event System
-
Extensive support for Tracy and Spall profiler.
-
3D level editor using a parser for Blender
-
UI
Future plans
-
Clustered Forward Shading
-
I plan to have lots of lights for great creative expression, and Clustered Forward Shading sounds the best options for performance and flexibility when comparing to modern techiques. I also considered Deferred Shading, but I decided for something that doesn't weight so much on the bandwidth.
-
Perspective and Orthographic project.
-
Radiance Cascades
-
VBAO/SSILVB.
-
Directional Lights, Spot Lights, Area Lights (without soft shadows for now).
-
Clustered Forward Shading
-
I plan to have lots of lights for great creative expression, and Clustered Forward Shading sounds the best options for performance and flexibility when comparing to modern techiques. I also considered Deferred Shading, but I decided for something that doesn't weight so much on the bandwidth.
-
HDRI Skies with .exr files
-
Emission / Bloom shader
-
Frustum Culling on GPU other 'Approach Zero Driver Overhead' techniques
-
Investigate a bit more into Buffer Device Address techniques.
-
Custom Font Rendering.
-
New UI layer with Clay
-
Remove GLFW and replace it with a new OS layer.
-
Shadows.
-
Fog.
-
Volumetric Fog.
-
Particle System
-
Mesh Skinning.
-
Support for VR with Variable Refresh Rate techniques (VRS).
-
Mobile support.
Mystical Forest V2
Extensive Multiplayer Techniques, Procedural Animations, Pixelart
Read more
Multiplayer - Netcode
-
Multiplayer was the foundation for everything in this game, being the first thing to be implemented and always something to come back to. I wanted to make sure to treat netcode as a priority and have the multiplayer scale well with time.
-
For this engine I went with JoltPhysics, which gives excellent physics simulation; for that I made this jolt-odin binding, bringing Jolt to the Odin programming language.
-
It's worth noticing that Jolt is a 3D physics engine, but this game is 2D, so changes had to be made so the simulation runs correctly and objects don't slip into a unseen dimension.
-
I opted for Jolt instead of something more usual, such as Box2D, as I was pretty sure I would use this binding later for a 3D game, and wanted to streamline the physics process. If necessary, I would later simplify the physics engine by making a full rewrite in Odin.
-
Even though this engine had a pretty robust physics engine, that wouldn't matter if the client felt laggy or if the client and server couldn't agree on the current physics state, leaving the client to be rolledback constantly. This was one of the first big challenges I had with netcode. To fix this issue, I decided to completely separate the updates inside the server and client via well-defined "cycles" and "fixed cycles", in a way that a single clock-sync when the client logs in would be enough to keep latency to a minimum. This, of course, only works in a vacuum, as CPU drift can occur and latency is not constant in time. For that reason, a series of measurements is taken at a fixed rate to identify delta spikes in latency, so the client can process faster or slower to properly have the physics update synchronized. The result is shown in the graph above: a much smaller delta ratio comparing gray entries (old) vs colorful entries (new), indicating a big improvement in synchronization. Not all was solved, as there was still a "minimum ms delta" due to restrictions around the server update frequency, as well as problems of "over-compensation" if the client has a delta-ms too large due to high RTT, but I believe that both could be solved with improved temporal metrics.
-
Beyond the solutions I talked about, I worked on creating my own encoding/decoding through a specialized serialization system, using CBOR for something more complex, such as the custom RPC system I created, or using something as compact as a single byte to identify instructions. This could also be improved even further by better utilization of UDP packets for non-crucial tasks, as well as better utilization of the TCP payload when considering the size of the header.
-
With that, the multiplayer was much better than before, while also requiring much less from the the server, as now not only the bandwidth is improved, but the server can process a lot slower as the client has now the tools to compensate for the increased latency without losing input/action precision.
Multiplayer - Login
Visuals
-
For the visuals, I decided to completely avoid an internal level editor. I'm of the belief that external editors are much better choices when it comes to customization and artistic choice. For the external editor in question, instead of creating something of my own, I decided to go for LDtk, from one of the creators of Dead Cells. For that, I made a custom parser that would translate the .ldtk files into custom logic inside the engine. Unfortunately, I had a very bad experience working with LDtk, which led me to edit its source code constantly in order to solve a lot of the bugs and missing features it was lacking; coding in Haxe/OOP/JS was not fun.
Rendering
-
For rendering, I decided to keep using RayLib for this game, as it has a very easy-to-use API that allowed me to focus on other parts of the engine. Though, when it comes to customization, I felt quite stuck without being able to evolve past what OpenGL gives me and what RayLib exposes.
Procedural Animation
-
A library was created for handling all 2D procedural animations, using Inverse Kinematics with the FABRIK algorithm as the solver. As shown in the videos, it's possible to represent "grab motions" and "fish-like" motions. I was also implementing constraints so a new variety of motions could be represented, such as arachnoids, drones, lizards, snakes, etc. As the game is 2D top-down, there's a limited amount of motion it can represent, but for 2D platformer the options change, being more resonable to represent mammals. My goal was to create a library with concepts easy enough to understand so it could later be implemented for a 3D game.
Key Takeaways
-
I was really proud of what I've accomplished with the Multiplayer, but after not being quite satisfied with Raylib and LDtk I decided to try something different and learn Vulkan in 3D, so I could finally answer my questions about the world of rendering, and in the mean time I could think of a better solution to improve the workflow of 2D or 3D tools to keep making games with less friction.
Jolt Physics Engine Binding
The Jolt Physics Engine, now for Odin Lang
-
The physics engine used in Horizon Forbidden West and Death Stranding 2, now in Odin Lang.
-
The binding is open-source, found at caioraphael1/jolt-odin.
-
An additional wrapper was created for my engine, as a way to store body states, to integrate the geometric system into the existing Spatial Library, to have safe handles to entity/key for the ECS implementation of the engine, and also to have a better API for 2D games by limiting the physics simulation to a 2D plane.
-
Further details from the physics engine can be found at:
Mystical Forest V1
Exploration of Multiplayer Techniques, Game AI, Real-time 2D Combat
Evolution of the Multiplayer
-
Coop Peer-to-peer -> Dedicated Server, login system, authentication server, gateway server, dedicated databases for credentials and world data
Game AI
Combat
The many problems I had with Godot
Multiplayer Library in Godot
Peer-to-Peer and Server-Authoritive
-
Godot already has a system for Peer-to-Peer multiplayer via using the MultiplayerSpawner and MultiplayerSynchronizer nodes, but at the time these nodes where extremelly buggy and unsafe, to the point where it was impossible to use them in a serious application. The first multiplayer library was developed to circumvent this issue and make synchronization happen via a lower-level API, using ENet as the backend and avoiding both multiplayer nodes Godot gives us.
-
With time, I became unhappy with the architecture decision for this library and decided on something with extensive control over safety and connections. For that reason, I switched from a Peer-to-Peer model and went for a Server-Authority model. This aligned with my game design decisions and helped organize what had become a mess by having both client and server behavior in the same project.
-
Switching to a Server-Authority model meant that I could place the client in a different project from the server, improving safety against cheating and making code maintenance more sane.
-
Even with previous decisions, the Godot model was still too invasive and high-level for my taste. Having to manage communication through the native Godot RPC API was really unsafe and confusing; some of that was due to how, in Godot 4, one has to declare a function in both client and server as RPC, and both should have the same name, otherwise this would result in network errors. This decision by the Godot team made it clear the philosophy of the engine, and how the multiplayer would be unnecessarily complicated by my having to constantly go against the engine's decision of enforcing Peer-to-Peer multiplayer, and with no safety for Server-Authority solutions. Later, this led me to leave Godot altogether and start a new multiplayer game with a new network library made from scratch in Odin, with decisions compatible with the networking architecture design I had envisioned. This Godot library was later deprecated.
Moss World: Turn-based/Grid-based Combat
Turn-based and grid-based combat, Game AI, Isometric Pathfinding, Isometric Art
Combat
Game AI
Pathfinding and Fake-3D
Real-time iteration
Top-down iteration
Utility AI Library in Godot
Library for AI with emergent behavior
-
The images show the interface for the library with curve customization for each Consideration inside a "Decision". Each Decision holds aggregation configurations and a reference to an "Action", defined by an external library. The second image shows the AI Agent (root node) with controls for memory duration for that entity, update frequency, and navigation optimization tweaks.
-
This implementation in Godot supports both real-time navigation and grid-based navigation systems.
-
For more information, see the Utility AI note.
Snow Shaders for the Snow Expedition game prototype
Exploring snow shaders
-
A prototype made while exploring snow shaders, fog effects for low-poly art in Godot.
-
The snow deforms when an entity walks on it, as well as physics objects and vehicles. The same goes for accumulated snow on top of rocks and mountains.
Blockbench Creative Mode Plugin
Bringing Minecraft movement and workflow to Blockbench
-
Blockbench is a modeling software written in JavaScript.
-
The plugin brings the option to place and remove cubes just like in Minecraft creative mode.
-
A detailed explanation of the changes and demo videos were at display in the Blockbench Discord, but unfortunately this discord server doesn't exist anymore.
-
The idea for this plugin came as an extension from this other PR I worked on, for letting WASD controls happen only when holding the mouse buttom, so it's possible to toggle between navigation modes.
Read more
Fly like in creative Minecraft
-
From 'WASD Control plugin': Use WASD to move around, E to go up, Q to go down (keybinds are configurable).
-
Use Shift to fly faster or Alt to fly slower (keybinds are configurable).
-
You can change the sensitivity of the camera, speed of flight, speed modifier for "go faster (shift)" and "go slower (alt)".
Painting the world
-
Select a "brush" (Cube).
-
Press T or click the icon to toggle the tool.
-
Start painting by clicking with the Right Mouse Button on other cubes.
-
Use Left Click to remove blocks, or Ctrl + Z to undo.
-
If you want to select a different brush, or customize the current one, just press T again to deactivate the tool and select a different brush (Cube).
-
Differently from Minecraft there's no limit distance to place blocks, so you can remove or place a block from really far away.
Known issues
-
The plugin may act weirdly when placing blocks with rotations or scales that differ from each other.
-
The Outliner can flicker up and down when placing lots of blocks. Selecting something in the outliner usually fixes that.
-
The performance can be a little weird when placing thousands of blocks in the same scene. However, that fixes itself when restarting the app, it's inconsistent what triggers the frame drops in this case.
Limitations
-
It's not supported to place a cube in a Mesh or in the "void".
-
While placing a tiny block in a huge block, that placement can be weird and offset to some corner. That's tough to fix, so there's no planning for that.
-
It's not possible to Ctrl + S to save the project while the tool is active. That's due to the WASD movement for the navigation.
-
It's not possible to position multiple blocks at the same time.
Future ideas
-
The plugin no longer implements a simple tool, but a new "edit mode" called 'Creative', placed next to Edit / Paint / Animate. This new tab will not show any Gizmo or selection; it will only be for 'placing and removing cubes'.
-
This new tab would have its own group system to help group the new cubes created; I've been using the plugin for creating a level design for my game, and I got 1000+ cubes in the scene, so it's important to have some group organization.
-
A new interface in this new tab, that would take the UV place, displaying the current selected cube (aka. the current Sample Cube used for painting the world).
-
A system that lets the user place cubes in an empty grid. The current state only lets the user place a cube next to another cube, so that can be a bit annoying at times.
-
Add middle click to pick blocks like in Minecraft (Suggested by Jannis).
Blockbench UV Rework
Improving the Blockbench modeling software
-
Blockbench is a modeling software written in JavaScript.
-
The way the software handles UVs was a bit all over the place. The PR presented aimed to bring a whole new way of managing UVs, while also bringing new functionality and ergonomics to existing features.
-
A detailed explanation of the changes is documented in the PR at: Repeating Textures, new UV Tools and UV options.
-
The PR was later added to core as a plugin.
Blender Better glTF Exporter Plugin
Batch export and export customizations for Blender
Billboarding and Low-Poly Experimentation
First look at 3D in Godot
-
An early testing around 3D in Godot, experimenting with billboarding visuals for a Coraline/Halloween-inspired puzzle game.
-
For billboarding, I tested with different projections and camera angles, trying to find the best compromise for visuals that kept the aesthetics I was envisioning. I also spent some time implementing a shadow system that made sense for 3D floating sprites; having to fight Godot for that was no fun.
-
I ended up not liking billboarding that much, so I took the opportunity to learn more about modeling and how to translate early 2D systems from Godot to 3D.
-
For gameplay, this prototype consisted of puzzles involving lighting manipulation through UV lanterns to interact with fire sources and glyphs to reveal secrets in the map. The prototype only had the first level.
-
As a final thing, I decided to test scenarios in broad daylight and see how that would change the mood. For that, I experimented with shaders for foliage sway in the wind and Draw Indirect to improve performance when drawing the grass.
-
Unfortunately, the performance in Godot for all these tests was really bad, even for most lighting being offline baked and applying the optimizations mentioned. Any Global Illumination solution was simply too heavy at a point where it was beginning to struggle to stay within the range of 60~90fps for these simple demos. This was one of the reasons that cuminated on me creating my own 3D engine in the future.
-
Credits for the tiny witch asset version goes to Jays Things.
Other projects will be added soon
.
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
-
Lorem ipsum dolor sit amet