It's been a year since I've started working on a custom 3D game engine called YUME. At first, I knew nothing about OpenGL or 3D game development in general, so it has been a very tough, but very rewarding learning experience. In fact, making this engine is the hardest thing I've ever done.
Today, YUME is powering the game that I'm currently working on - Speebot. The game is far from completion, but the engine has come a long way!
I thought I'd use this chance to give a basic rundown of what the engine can do.
Like every 3D renderer, YUME can display 3D models - characters, props, etc. These models are stored in specially formatted files. OBJ file format is a common standard that is supported by most 3D modeling software, including Blender, which I use. This is the format that YUME originally supported, but now all models are stored in my own file format called MOE - a format that's inspired by OBJ, but supports various neat additional features, such as skeletal animation.
But before writing the renderer, before delving into OpenGL documentation, tutorials and forum posts, I wrote a timestep system.
A timestep system ensures that an engine displays frames at specific intervals. Unlike most current game engines, YUME does not have a framerate cap, i.e. it's not tied to 30 or 60 frames per second. In fact, the framerate can be anything from 1 to 250 frames per second, and the game will still appear to be running at the same speed no matter what the framerate is (only the screen will be updated at different intervals). This is achieved by separating game logic from rendering. Rendering a single frame can take different amount of time on different computers, so the render framerate depends on the program's performance. The logic cycle, on the other hand, is tied to a 64 tick rate - meaning the game logic is updated 64 times per second, no matter what the render framerate is. There are a few edge cases that the timestep system has to account for, but the principle remains the same. As a result, the framerate decreases on weaker computers without ruining the game flow.
Writing and refactoring the 3D renderer took months, and it was pretty simplistic at first. Today, YUME's 3D renderer supports dynamic shadows, ambient lighting, directional lighting, point lights, spot lights, texture glossiness, translucency, real time reflections, distortions, and a large amount of moving particles. Objects can have skeletal animations, attach and be attached to other objects.
Besides the 3D renderer, there is also a layer for displaying 2D graphics. This layer can be used for rendering user interface elements - text, buttons, icons, and so on.
A mouse input system had to be written from scratch, so that the 2D buttons (and later - 3D objects) could actually be clicked. Keyboard input and gamepad input had to be implemented from scratch, too.
As all of these sub-systems were coming together, I could start working on a menu system and interface components, such as buttons, dropdown menus and sliders. All these components are extensively used in Options sub-menus, and they let the player tweak the quality of almost every aspect of the engine, to gain performance on weaker machines.
Shaders were a completely alien concept for me at the time, and I could only get by with tabs upon tabs of tutorials and code examples open. Eventually I had to be able to understand GLSL (OpenGL shader language) well enough to write and optimize various custom shaders on my own, including a water shader with animated textures, reflections and distortions.
At this point I already had an early prototype of Speebot, complete with a custom 3D collision detection system, a basic physics system and a built-in map editor, so that I could rapidly design new levels for the game. Maps in Speebot are tile based.
A 3D sound system had to be written from scratch. All audio in YUME is implemented using OpenAL.
A post-processing stage had to be implemented in the rendering pipeline, so that I could implement fast shader-based anti-aliasing.
With these major engine features complete, I could focus on working on Speebot - this means creating a level progression system, designing actual levels, scripting cinematic sequences, modeling and animating objects, adding NPCs, creating sounds and new gameplay mechanics.
Currently I've been spending most of my free time practicing making music. The only changes to YUME these days include performance optimizations and bugfixes.
Engine-wise, I think I've implemented all the major features I need for now. Eventually, I'd like to support other platforms besides native desktop, but that comes later.
There's still a lot of work to do on Speebot!