I need a break from studying for a few math finals, so I decided to jot down some thoughts I had about the next game engine I want to write. I think that the next engine I write needs to be debuggable, more than anything else. What I mean by that is: It's way more important that the programmers in the engine can readily tell the state of things in the engine than it is to be super performant, at least early on. As long as I keep in mind a few principles (basic data-access), then I won't be hurting myself in the long term AND it'll be easier for people to use an engine I write.
(I get that most people don't write engines--for good reasons--this post isn't for them.)
So, what are things that a C++ game engine needs, in order to be debuggable?
Here's my short list:
- Profiler
- Memory Manager
- REPL / Script Integration
- Error handler
- External Tool Support
- Debug Graphics
- Picking or Object Selection
Some quick thoughts on each of those.
Profilers
A profiler should just send out data points to plot for an external tool to draw or handle. This way I can send out the same data and represent it different ways: I could display the data if I'd like or log it or send messages back to the game based on the data. It decouples what I want to profile from what I do with that information.
Memory Management
This is C++ so we're going to be allocating and deallocating memory. I think that memory managers should be hierarchical. This makes it easy to see how much memory the whole game has allocated, then how much each system or level, then how for particular objects or whatever. I want to write a lot more about memory, but I'll do that at a later time.
REPL/Script Integration
Having to recompile C++ just to make changes doesn't make sense. It's hard to iterate and be creative when every thirty seconds a developer is waiting for her engine to recompile. Being able to bring up a console and query game state or trigger different events (turn on debug draw info, for instance), is a necessity for a real engine. The next step is being able to dynamically create and add scripts to an object. So basically, if I have a system like graphics, I could make a script that sends out the number of graphics objects that are currently being drawn. I didn't have to recompile or even restart the game to do this, I just had to bring up the console, type the script and attach it to the system. Think about how much productivity that adds.
Error Handler
This one is probably obvious, but getting a window to pop up when you break something is great.
External Tool Support
This is one that I don't think most people will agree with, but I shouldn't be forced to make tools for my game in C++ or any other language. If an external tool knows how to process some intermediate data format (like j-son), then that tool should be able to communicate with my engine. What does this allow me to do? I can make tools in whatever the best language is for that tool. I could use ruby to do something or lisp or C#.
Debug Graphics
I didn't put Debug Drawing for a reason, that's the minimum of what's needed. Of course, you should be able to draw lines and text in 2D and 3D. Another area that needs to be addressed is a debug camera. When I want to I should be able to make a copy of the current camera that can be moved around without affecting the original camera (and drawing and culling information). This lets me debug what my game (and graphics, especially) is doing.
Picking
Lastly, I should be able to select an object in some way. This ability, in conjunction with a REPL console is very powerful. Depending on what other systems you have in place, you can pick an object and then print out it's behaviors or change some values on it.
Conclusion
Of all the things that I mentioned here, Script Integration is the hardest to accomplish. Depending on your project, it may not be worth it. Still, I'm a firm believer that as little as possible of an engine should be in C++, especially in the early stages of development. The parts that should probably be in C++ are the core systems: Object and resource management, math, physics, graphics, containers, and message handling. Those are also systems the systems that either need to be most performant or are the least likely to change.
(I get that most people don't write engines--for good reasons--this post isn't for them.)
So, what are things that a C++ game engine needs, in order to be debuggable?
Here's my short list:
- Profiler
- Memory Manager
- REPL / Script Integration
- Error handler
- External Tool Support
- Debug Graphics
- Picking or Object Selection
Some quick thoughts on each of those.
Profilers
A profiler should just send out data points to plot for an external tool to draw or handle. This way I can send out the same data and represent it different ways: I could display the data if I'd like or log it or send messages back to the game based on the data. It decouples what I want to profile from what I do with that information.
Memory Management
This is C++ so we're going to be allocating and deallocating memory. I think that memory managers should be hierarchical. This makes it easy to see how much memory the whole game has allocated, then how much each system or level, then how for particular objects or whatever. I want to write a lot more about memory, but I'll do that at a later time.
REPL/Script Integration
Having to recompile C++ just to make changes doesn't make sense. It's hard to iterate and be creative when every thirty seconds a developer is waiting for her engine to recompile. Being able to bring up a console and query game state or trigger different events (turn on debug draw info, for instance), is a necessity for a real engine. The next step is being able to dynamically create and add scripts to an object. So basically, if I have a system like graphics, I could make a script that sends out the number of graphics objects that are currently being drawn. I didn't have to recompile or even restart the game to do this, I just had to bring up the console, type the script and attach it to the system. Think about how much productivity that adds.
Error Handler
This one is probably obvious, but getting a window to pop up when you break something is great.
External Tool Support
This is one that I don't think most people will agree with, but I shouldn't be forced to make tools for my game in C++ or any other language. If an external tool knows how to process some intermediate data format (like j-son), then that tool should be able to communicate with my engine. What does this allow me to do? I can make tools in whatever the best language is for that tool. I could use ruby to do something or lisp or C#.
Debug Graphics
I didn't put Debug Drawing for a reason, that's the minimum of what's needed. Of course, you should be able to draw lines and text in 2D and 3D. Another area that needs to be addressed is a debug camera. When I want to I should be able to make a copy of the current camera that can be moved around without affecting the original camera (and drawing and culling information). This lets me debug what my game (and graphics, especially) is doing.
Picking
Lastly, I should be able to select an object in some way. This ability, in conjunction with a REPL console is very powerful. Depending on what other systems you have in place, you can pick an object and then print out it's behaviors or change some values on it.
Conclusion
Of all the things that I mentioned here, Script Integration is the hardest to accomplish. Depending on your project, it may not be worth it. Still, I'm a firm believer that as little as possible of an engine should be in C++, especially in the early stages of development. The parts that should probably be in C++ are the core systems: Object and resource management, math, physics, graphics, containers, and message handling. Those are also systems the systems that either need to be most performant or are the least likely to change.