CPhys is a 2D game engine written in C# (.Net Core 5) using a forked version of SDL for Rendering, Audio, and I/O. I say forked because I forked it and added some new functions to it.
Entities in my engine are C# classes implementing a hybrid ECS and inheritance system. Entity components are their own classes and can be assigned to any entity implementing its associated interface. For example, while a Zombie may override the "Creature" class, which defines some basic rendering and physics checking, assigning "Burnable" to it, and giving its Mixin Dictionary the "BurnableMixin" object adds the code necessary to make the Zombie ignite when hit with a fireball.
AI for the entities is a Finite State Machine; each state is defined as a method in the Entity's class, and is adorned with an Attribute describing it as both an AI state (called a "Goal") and also some meta information about it (such as what "Target" entity should be passed to the method, making it simpler for enemy Entities to target the player). Goal methods can return things like
Code: Select all
Next("Walk")
Code: Select all
Frame()
Collision detection in my engine is a kind of convoluted Swept AABB system. I don't totally love this system but it works well enough and changing it would probably be a headache at this point. There are no tiles in my game, everything is an AABB entity of arbitrary dimensions and position. This allows me to do things like moving platforms pretty simply. Entities are placed in 1024x1024px 2D buckets for rendering, and their position in a Quadtree is calculated on the fly for collision detection.
Rendering is done with SDL2. Having learned more about SDL2 as I went through this engine, if I could do it again, I would implement the rendering in DirectX 11 instead. I feel like SDL does some things a little too slow (such as tile-based rendering). Though my spatial partitioning isn't tile-based, I do have wall entities whose sprites which are defined by tiles which are atlased from a spritesheet. Because SDL doesn't currently have a way to specify multiple UV-mapped quads in a single draw-call, I implemented this myself, which was a pretty good performance boost. This AABB entity system makes it simple to move geometry around at-will, but also makes it cumbersome to define arbitrarily shaped geometry. I'm working on an autotiling system to generate static AABBs to make the workflow a bit easier.
UI is currently an XML-based declarative syntax, similar to XAML or HTML. Models can be bound to these using Handlebars. Stylesheets for the menus are defined in JSON, similar to CSS. Callbacks for each element are a C# object defining methods like "OnClick", and "OnKeydown". This system was designed ad-hoc and isn't very strongly typed, so I'm refactoring it to have better typed definitions of what styles are available, as well as a more flexible callback system similar to Angular. Stylesheets were transitioned from JSON to YAML because I like the syntax's lack of quotation marks better; it's closer to CSS and more flexible that way, plus it allows better syntax highlighting.
Dialog is currently basically just stored XML files which define the UI for the various dialog boxes. Dialog boxes and menus are essentially the same thing, and I have a webapp which generates those menu files from dialog I type in and branching trees. I dislike this system a bit because the workflow is slow, requiring me to export from one program and import into another. The new UI system will enable me to edit dialog trees in-engine so that I don't have to deal with this export/import stuff. Since the game will focus heavily on dialog (not quite story-driven, but more of a logic puzzle adventure-type almost point-and-click game), it's important that the workflow for this work well.
Scripting is done in various places (such as in dialog/cutscene events, or in response to buttons being pressed), via Lua. I added a whole suite of Lua functions to enable scripts to control entities, force them into certain AI state, move them in certain directions, etc. I'd like to flesh this system out a bit better as well. I also have a Lua Interop library for debugging, but because this gives direct access to all of the .Net library, this can't be used for scripting due to security reasons, and I may have to move it to a non-interop version later on due to its ability to be abused via config files executing arbitrary code.
There's also cutscenes, which are defined as a series of keyframe transformations (camera pan, zoom, entities being manipulated, dialog being triggered, and lua scripts being executed), which is defined in XML.
There's quite a lot more, but these are the core features. Here's a screenshot I took of the editor, with all the editor menus open:
The dots are a resizable 32x32px grid, and the blue lines denote the edges of each bucket. The UI rendering is all done in SDL via my custom UI framework