This project will be documenting and demonstrating the development of making a game from scratch1! Every step of the game development process and every line of code will be explained thoroughly.
The game will be a 3D based game. More will be revealed about the game as the project persists.
YouTube Channel: GingerGames
GitHub: Dunjun GitHub
1With minimal libraries such as GLEW, GLFW (Pre Day 73), SDL2 (Post Day 73), and the STB libraries.
- Dunjun Playlist
- Bare Bones
- Vectors and Matrices
- Model Assets and Model Instances
- Quaternions and Rotations in 3D
- Camera and Input
- Mesh Creation
- Model Generation
- Scene Graphs and Component Based Design
- Lighting and Deferred Rendering
- 001 - Project Setup (Visual Studio)
- 002 - Creating a Window (GLFW3)
- 003 - Drawing with OpenGL (GLEW)
- 004 - Shader Program Class
- 005 - Textures (STB)
- 006 - Image Loader
- 007 - Texture Wrapper
- 008 - Error Handling & Code Tidying
- 009 - Introduction to Transformations with Matrices
- 010 - Implement Basic Vector Types
- 011 - Vector Functions
- 012 - Matrix4 Type
- 013 - Matrix Transform Functions
- 014 - View & Projection Matrices & Angles
- 015 - Constants, Code Tidying & GLSL Convention
- 017 - Introduction to Complex Numbers
- 018 - Introduction to Quaternions
- 019 - Quaternion Interpolation
- 020 - Implement Quaternions
- 021 - Quaternion Functions
- 022 - Transform Type
- 023 - Fixed Time Step & Code Tidying
- 024 - ReadOnly Types & Camera Type
- 025 - Complete Camera & Depth Testing
- 026 - Basic First Person Camera Input
- 027 - Game Separation and Input Wrapper
- 028 - XInput Gamepads
- 029 - Gamepad Camera Control
- 030 - Mouse Buttons and Scroll Input
- 030.5 - Input Enums & Camera Transform Fix
- 031 - Plans for Game
- 032 - Basic Level and Billboards
- 033 - Finish Billboards and Start Mesh
- 034 - Materials and Meshes
- 035 - Textured Tiled Room
- 036 - Add Tile Surfaces and Random Tile Sets
- 037 - Level Class and Code Tidying
- 038 - Fullscreen Support and Window Functions
- 039 - Level Generation
- 040 - Random Numbers and Experimental Camera
- 041 - Camera Swapping & Mesh::Data Helpers
- 042 - Random Non-Connected Rooms
- 043 - Non-Overlapping Rooms
- 044 - Code Review
- 045 - Scene Graphs and SceneNodes
- 046 - Component Based Design and NodeComponent
- 047 - Renderer and FaceCamera Component
- 048 - Passing SceneNodes to the Renderer
- 049 - Room SceneNodes
- 050 - Drawables and Level SceneNode
- 051 - Random Walk Level Generation
- 052 - SceneNode Optimization & Many Room Levels
- 053
- 054 - Distance Culling and Cone Culling
- 055 - Batch Rendering - Sorting by Material
- 056 - Diffuse Point Lighting
- 057 - Point Light Implementation
- 058 - Ambience, Specularity, and Attenuation
- 059 - Limit Light Range and Material Structure
- 060 - GLSL Material and Light Range Calculation
- 061 - RenderTexture
- 062 - Deferred Shading & GBuffer
- 063 - Deferred Geometry Pass
- 064 - Deferred Point Lighting
- 065 - Resource Holder
- 066 - Specialized Holders and glGen* placement
- 067 - More Holders & Lighting RenderTexture
- 068 - Directional Lights
- 069 - #include for GLSL
- 070 - Time Class & sleep(Time)
- YouTube: GingerGames
- Email: [email protected]
- GitHub: Dunjun GitHub
No! In fact, the game design has been made to require complex concepts which exist in more than most game designs.
No! 99%1 of the programming for the game is recorded in the videos; every step of the game development process and every line of code will be explained thoroughly.
1Some of the code will not programmed in the videos but this will mostly be bug fixes or minor changes to the code that can be explained quickly.
This game will support Windows1, Mac OS X2, and Linux34.
1XP and Above 2OS X 10.8+. 3Including Steam OS. 4Most likely Debian based systems only.
Please feel free to contact with any problem:
- YouTube: GingerGames
- Email: [email protected]
- GitHub: Dunjun GitHub
Before we can begin, you need to make sure you have all the things you will need.
- A reasonable amount of experience with C++
- C++11 experience will help
- Graphics card compatible with OpenGL 2.1
- DirectX 9 Equivalent Cards
- Text Editor and C++11 Compiler, or IDE (MSVC 12 compiler capabilities at least)
- The initial libraries:
- GLFW - For creating the context, window, and handling input (Pre Day 73)
- GLEW - To use new OpenGL functions
- SDL2 - For creating the context, window, and handling input (Post Day 73)
At the moment, only Windows is supported through the Visual Studio solution. Mac OS X and Linux will implemented later when needed/wanted.
Most of the code should compile on Mac OS X and Linux with probably only a few minor changes.
Graphics APIs:
- OpenGL 2.1 (through GLEW)
Platforms:
- Windows (Through MSVC 12)
- OS X (To be added)
- Linux (To be added)
- C++ compiler with decent C++11 support
- If Visual Studio, please use at least MSVC 12.
- Clang is preferred to GCC on other platforms but not necessary.
- OpenGL (Rendering)
- GLFW 3.1 (Window, Input and, Context Handling)
- GLEW (OpenGL Extension Wrangler Library)
- STB Libraries (Image and Font Loading)
- See clang-format-style.yaml for formatting style
- Allman Indenting
- CamelCase
- Tabs for indentation
- Spaces for alignment
- More below!
PascalCase (Upper CamelCase) (e.g. ShaderProgram)
camelCase (e.g. loadFromFile)
PascalCase (e.g. Dunjun::)
The end of a namespace must appended by namespace
then its name.
Example:
namespace Dunjun
{
namespace Inner
{
...
} // namespace Inner
} // namespace Dunjun
In C++11, using
is a superset of typedef
. using
is preferred in this style guide.
// Using
using FooBar = std::pair<Foo, Bar>;
// Typedef
typedef std::pair<Foo, Bar> FooBar;
C++ style comments //
are preferred but C-style comments /**/
can be used. The reasoning is that C-style comments cannot be nested and most IDEs/Editors can comments whole blocks in the C++ style which can allow for uncommenting a single line easily.
When an collection of data is needed, use a std::vector
unless it is fixed at runtime. If it is fixed at runtime use a classic C array or std::array
. std::array
is preferred as it is more C++ but they are exactly the same as it is just a class version of the classic C array.
The vector's elements are guaranteed to be contiguous, so you can pass &v[0]
to any function expecting a pointer to an array; e.g., C library routines, OpenGL. Also, std::vector<char> buffer(2048);
is a brilliant way to allocate a local buffer.
Use std::vector
unless the profiler says that there is a problem and the array is tiny.
Raw pointers (e.g. Bar*) can be used, but if a smart pointer can be used, please do so.
Shorthand for smart pointers (std::unique_ptr
, std::shared_ptr
, std::weak_ptr
) of classes can be declared with using.
- UPtr -> unique_ptr
- SPtr -> shared_ptr
- WPtr -> weak_ptr
Do not use std::auto_ptr
, use std::unique_ptr
as it is much better and std::auto_ptr
is depreciated.
std::shared_ptr
s and std::weak_ptr
s are to be use sparingly.
Example:
class Bar
{
public:
using UPtr = std::unique_ptr<Bar>;
using SPtr = std::shared_ptr<Bar>;
using WPtr = std::weak_ptr<Bar>;
...
};
If a class/etc. does not need a certain smart pointer, do not give a shorthand.
camelCase (e.g. temp, m_world, s_time)
- m_ for protected/private member variables
- s_ for static/local persist variables
- g_ for global variables (should never be used! (except on a few rare occasions but if done so, place them within a namespace, at least!))
Example:
GLOBAL f32 g_globalVar;
extern int g_externVar;
class Foo
{
void func()
{
LOCAL\_PERSIST u64 s_localVar;
...
}
private:
char m_memberVar;
};
All enum items should use PascalCase (e.g. CursorMode
).
If a strong enum is preferred, please use one (e.g. enum class
).
Example:
enum class CursorMode
{
Normal,
Hidden,
Disabled,
};
If a weak enum is needed, please prefix the item with the name of the enum then an underscore.
Example (made up):
enum Flag : u32
{
Flag_1 = (1 << 0),
Flag_2 = (1 << 1),
Flag_3 = (1 << 2),
Flag_4 = (1 << 3),
Flag_5 = (1 << 4),
Flag_6 = (1 << 5),
Flag_7 = (1 << 6),
Flag_8 = (1 << 7),
Flag_A = Flag_1,
Flag_B = Flag_2,
Flag_C = Flag_3,
};
In Dunjun/Common.hpp
, there are some defines for static:
#define GLOBAL static
#define INTERNAL static
#define LOCAL_PERSIST static
Please using these rather than the keyword static to indicate which type of static is being used.
Example:
GLOBAL int g_thingy;
INTERNAL void doSomething()
{
LOCAL\_PERSIST char s\_buffer[10];
...
}
- TODO - todo
- NOTE - note to reader (can be used in conjunction with TODO)
- IMPORTANT - important (can be used in conjunction with TODO or NOTE)
- FIXME - fix as soon as possible (does not work as intended/not at all)
- HACK - don't use in production (similar to FIXME but still works)
Example:
// TODO(fred) IMPORTANT(fred): This is some example text for a todo that is
// important. It also spans multiple lines. This annotation was written
// by `fred` as indicated next to the annotation.