We call this using the
SDL.INIT_VIDEO flag to initialize the video subsystem. The
events subsystem is also initialized automatically.
Shuts down the initialized subsystems.
SDL.CreateWindow() && SDL.DestroyWindow()
There are a number of flags available for creating a window, but at this stage we'll only use
SDL.WINDOW_SHOWN which makes the window visible.
According to the documentation this particular flag isn't necessary, but I've put it here anyway for learning purposes.
SDL.CreateRenderer() && SDL.DestroyRenderer()
A Renderer is a rendering context for the life of the game. You only need ONE renderer for all graphics in your game.
SDL.CreateRenderer() accepts a number of flags to configure the renderer you want to create. At this point in my learning, I do not enable vsync so I can see the impact of using an enforced frame rate in my game loop.
SDL.GetPerformanceCounter() && SDL.GetPerformanceFrequency()
Used together, these functions allow us to get timestamps for the start and end of our game loop. These timestamps are used to enforce a frame rate, making things like physics easier to manage.
This frame rate timing is also used to modify movement. The "delta time" modifier ensures movement speed will be independent of frame rate speed. This is covered in other videos on the Handmade Games channel.
This function returns an array of bytes that tells us which keys are currently pressed on the keyboard.
We can then use the keyboard state to handle things like character movement.
Keyboard events like
KEYDOWN are queued.
SDL.PollEvent() gets the latest event and uses the data to populate the given
For now, we're just handling QUIT events, but in the future we'll handle others like
pause game, etc.
In a future 'update and render' section of our game loop, we'll be drawing a scene in the background that won't be presented to the screen until it is finished (at the end our loop).
This function replaces or "flips" the old scene from the previous frame with the new one we just drew in the present frame.
SDL.RenderDrawColor() && SDL.RenderClear()
SDL.RenderClear() will clear the background scene to get it ready for the next drawing. The old scene will be cleared to whatever color is set by
Many code examples you'll find (like the one here) will demonstrate using
SDL.RenderPresent(). This is because it draws the entire scene using `SDL.RenderCopy()** in a step distinct from the update portion of the code. We won't be doing that. Instead, we'll be updating and rendering our scene as close together as possible. This means we clear our background scene after the presentation, making it ready for our new scene at the beginning of our next frame.
For explanations of keywords, etc. look at comments in
Not to be confused with
#assert() which is a compile-time assertion,
assert() exits the program and displays the given error string in the console when the given expression is false.
defer statement defers the execution of a statement until the end of the scope it is in.
println() prints a line to the console.
Before the game loop starts, I initialize variables for my timestamps, any event, and the keyboard state.
game.perf_frequency = f64(SDL.GetPerformanceFrequency())
start : f64
end : f64
event : SDL.Event
state : [^]u8
Before doing anything else, we get the
start time for the loop, and only after all the work is done do we get the
In between our
end points we perform the following operations in order:
- Get our current keyboard state
- Handle any input events
- Update and Render
Updates and Rendering should only happen after current keyboard state and events are known. These variables will drive how we update our game state.
Finally, as mentioned above, updates and rendering should happen at the same time. Separating these operations arbitrarily has a big performance cost.
In the next video, I'll cover rendering our main player entity.
Subscribe to Handmade Games if you're interested in learning how to program games from scratch using SDL2 and the Odin programming language.