A personal engine developed with C++ and D3D11 starting fall 2019. For now, this engine supports both 2D and 3D rendering, simple 2D physics, XML format map/definition loading, multi-threading job system, event system, audio playing, TCP/UDP networking, and some other features.
All of my personal C++ projects are made with this engine.
I am still reviewing and updating this engine.
Both 2D and 3D rendering are done by drawing triangles and applying textures to them. So technically there are no real differences between them. However, certain techniques are more useful on one of them than the other.
Most of the 2D rendering I currently used in my projects is done by rendering "quads" and applying different textures to them. By doing so, I can get characters and scenes. I used stb library to load images.
One of the techniques that are useful for 2D rending is frame animation. Animations are loaded through XML files(which will be explained in a later section) and stored as a series of indices. Each index represents a section out of a sprite sheet, which is consists of many different frames. That way, by constantly changing the frame, we can have the animation playing.
3D rendering involves some other techniques that are not normally used in 2D games because I am trying to create realistic lighting. Therefore, we need more complex shaders and textures for that. I used Blinn-Phong shading for our shaders. To get a better rendering effect for meshes, we used MikkTSpace to generate normals and tangents.
This is a rendering with a normal map and a specular map. A normal map is a texture that contains normal information.
This is a rendering without a normal map. It looks all flat now.
This is a rendering with no specular map. A specular map is another texture that tells which part should be reflective.
Notice in the first image, only the "stones" are reflective. Without it, the whole surface is reflective.
A fancy techniques I can do with a noise texture: dissolving.
The noise texture we used for dissolving effect.
I used XML files to store data. That way I do not have to hardcode everything inside C++.
I used tinyxml2 to help with XML parsing. There is an XMLParsing class to convert strings into different data types we need. The XML files are used for storing entity definitions(name, status, animations) and levels/maps that are based on AABB(axis-aligned bounding box) tiles.
There are two sets of 2D physics systems in the engine.
One is a simple physics system that handles collisions among AABBs and discs. There is no complex physics calculation involved, but it is enough to handle most of the cases. I used this physics system to prevent entities from going through walls in top-down games.
This physics system is implemented inside maps. What it does is check if any entity is overlapping with a wall or another entity. If so, it pushes them out of each other by "teleporting" them.
Another is a more complex system that is capable of handling cases involving polygons, bouncing, drag, and friction. I used a standard "collider" and "rigid body" architecture that is widely used in game engines such as Unreal 4 and Unity.
For each update loop, this physics system finds all overlapping colliders and creates a "collision" for each pair. Then, it will resolve all the "collisions" with two steps. It first "corrects" the position of these colliders, and then applies impulses to the attached rigid bodies to make them bounce and rotate. It also comes with a trigger system that allows users to fire custom functions when colliders are touching and leaving each other.
Despite its complexity, this physics system does not feel super useful for 2D game development, unless it is a physics-based game such as Angry Bird. But it was a great practice to build it, the physics calculation and the update logic are both useful for future implementations.