├── LICENSE ├── Makefile ├── README.md └── src ├── constants.h └── main.c /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Gustavo Pezzi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | gcc -Wall -std=c99 ./src/*.c `sdl2-config --libs --cflags` -lm -o game 3 | 4 | run: 5 | ./game 6 | 7 | clean: 8 | rm game -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Simple Game Loop Written in C & SDL. 2 | 3 | This is an incredibly naive SDL game loop that contains a setup, input, update, and render function. 4 | 5 | This code was used as a companion to [this Youtube video](https://youtu.be/XfZ6WrV5Z7Y). 6 | 7 | For more information, visit: 8 | [https://pikuma.com](https://pikuma.com) -------------------------------------------------------------------------------- /src/constants.h: -------------------------------------------------------------------------------- 1 | #ifndef CONSTANTS_H 2 | #define CONSTANTS_H 3 | 4 | #define WINDOW_WIDTH 800 5 | #define WINDOW_HEIGHT 600 6 | 7 | #define FPS 30 8 | #define FRAME_TARGET_TIME (1000 / FPS) 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "./constants.h" 5 | 6 | /////////////////////////////////////////////////////////////////////////////// 7 | // Global variables 8 | /////////////////////////////////////////////////////////////////////////////// 9 | int game_is_running = false; 10 | int last_frame_time = 0; 11 | SDL_Window *window = NULL; 12 | SDL_Renderer *renderer = NULL; 13 | 14 | /////////////////////////////////////////////////////////////////////////////// 15 | // Declare two game objects for the ball and the paddle 16 | /////////////////////////////////////////////////////////////////////////////// 17 | struct game_object { 18 | float x; 19 | float y; 20 | float width; 21 | float height; 22 | float vel_x; 23 | float vel_y; 24 | } ball, paddle; 25 | 26 | /////////////////////////////////////////////////////////////////////////////// 27 | // Function to initialize our SDL window 28 | /////////////////////////////////////////////////////////////////////////////// 29 | int initialize_window(void) { 30 | if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { 31 | fprintf(stderr, "Error initializing SDL.\n"); 32 | return false; 33 | } 34 | window = SDL_CreateWindow( 35 | "A simple game loop using C & SDL", 36 | SDL_WINDOWPOS_CENTERED, 37 | SDL_WINDOWPOS_CENTERED, 38 | WINDOW_WIDTH, 39 | WINDOW_HEIGHT, 40 | 0 41 | ); 42 | if (!window) { 43 | fprintf(stderr, "Error creating SDL Window.\n"); 44 | return false; 45 | } 46 | renderer = SDL_CreateRenderer(window, -1, 0); 47 | if (!renderer) { 48 | fprintf(stderr, "Error creating SDL Renderer.\n"); 49 | return false; 50 | } 51 | return true; 52 | } 53 | 54 | /////////////////////////////////////////////////////////////////////////////// 55 | // Function to poll SDL events and process keyboard input 56 | /////////////////////////////////////////////////////////////////////////////// 57 | void process_input(void) { 58 | SDL_Event event; 59 | while (SDL_PollEvent(&event)) { 60 | switch (event.type) { 61 | case SDL_QUIT: 62 | game_is_running = false; 63 | break; 64 | case SDL_KEYDOWN: 65 | if (event.key.keysym.sym == SDLK_ESCAPE) { 66 | game_is_running = false; 67 | } 68 | break; 69 | } 70 | } 71 | } 72 | 73 | /////////////////////////////////////////////////////////////////////////////// 74 | // Setup function that runs once at the beginning of our program 75 | /////////////////////////////////////////////////////////////////////////////// 76 | void setup(void) { 77 | // Initialize the ball object moving down at a constant velocity 78 | ball.x = 10; 79 | ball.y = 20; 80 | ball.width = 20; 81 | ball.height = 20; 82 | ball.vel_x = 180; 83 | ball.vel_y = 140; 84 | } 85 | 86 | /////////////////////////////////////////////////////////////////////////////// 87 | // Update function with a fixed time step 88 | /////////////////////////////////////////////////////////////////////////////// 89 | void update(void) { 90 | // Get delta_time factor converted to seconds to be used to update objects 91 | float delta_time = (SDL_GetTicks() - last_frame_time) / 1000.0; 92 | 93 | // Store the milliseconds of the current frame to be used in the next one 94 | last_frame_time = SDL_GetTicks(); 95 | 96 | // Move ball as a function of delta time 97 | ball.x += ball.vel_x * delta_time; 98 | ball.y += ball.vel_y * delta_time; 99 | 100 | // Check for ball collision with the window borders 101 | if (ball.x < 0) { 102 | ball.x = 0; 103 | ball.vel_x = -ball.vel_x; 104 | } 105 | if (ball.x + ball.height > WINDOW_WIDTH) { 106 | ball.x = WINDOW_WIDTH - ball.width; 107 | ball.vel_x = -ball.vel_x; 108 | } 109 | if (ball.y < 0) { 110 | ball.y = 0; 111 | ball.vel_y = -ball.vel_y; 112 | } 113 | if (ball.y + ball.height > WINDOW_HEIGHT) { 114 | ball.y = WINDOW_HEIGHT - ball.height; 115 | ball.vel_y = -ball.vel_y; 116 | } 117 | } 118 | 119 | /////////////////////////////////////////////////////////////////////////////// 120 | // Render function to draw game objects in the SDL window 121 | /////////////////////////////////////////////////////////////////////////////// 122 | void render(void) { 123 | SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); 124 | SDL_RenderClear(renderer); 125 | 126 | // Draw a rectangle for the ball object 127 | SDL_Rect ball_rect = { 128 | (int)ball.x, 129 | (int)ball.y, 130 | (int)ball.width, 131 | (int)ball.height 132 | }; 133 | SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); 134 | SDL_RenderFillRect(renderer, &ball_rect); 135 | 136 | SDL_RenderPresent(renderer); 137 | } 138 | 139 | /////////////////////////////////////////////////////////////////////////////// 140 | // Function to destroy SDL window and renderer 141 | /////////////////////////////////////////////////////////////////////////////// 142 | void destroy_window(void) { 143 | SDL_DestroyRenderer(renderer); 144 | SDL_DestroyWindow(window); 145 | SDL_Quit(); 146 | } 147 | 148 | /////////////////////////////////////////////////////////////////////////////// 149 | // Main function 150 | /////////////////////////////////////////////////////////////////////////////// 151 | int main(int argc, char* args[]) { 152 | game_is_running = initialize_window(); 153 | 154 | setup(); 155 | 156 | while (game_is_running) { 157 | process_input(); 158 | update(); 159 | render(); 160 | } 161 | 162 | destroy_window(); 163 | 164 | return 0; 165 | } 166 | --------------------------------------------------------------------------------