├── .gitignore ├── assets ├── laser.png ├── player.png ├── laser-01.png ├── laser-02.png ├── asteroid-01.png ├── asteroid-02.png ├── background.png ├── explosion.png ├── lasers │ ├── 11.png │ ├── 12.png │ ├── 13.png │ ├── 14.png │ ├── 15.png │ ├── 16.png │ ├── 17.png │ ├── 18.png │ ├── 19.png │ └── 20.png ├── enemy-blue-01.png ├── enemy-blue-02.png ├── enemy-red-01.png ├── enemy-red-02.png ├── enemy-brown-01.png ├── enemy-brown-02.png ├── enemy-green-01.png ├── enemy-green-02.png ├── enemy-orange-01.png ├── enemy-orange-02.png ├── enemy-purple-01.png ├── enemy-purple-02.png ├── enemy-yellow-01.png ├── enemy-yellow-02.png └── explosions │ ├── explosion-01.png │ ├── explosion-02.png │ ├── explosion-03.png │ ├── explosion-04.png │ ├── explosion-05.png │ ├── explosion-06.png │ └── explosion-07.png ├── include ├── collision_detection.h ├── render.h ├── input_handler.h ├── sandbox.h ├── update.h └── setup.h ├── .vscode ├── tasks.json └── launch.json ├── Makefile ├── src ├── update.c ├── main.c ├── input_handler.c ├── render.c ├── setup.c ├── collision_detection.c └── sandbox.c ├── LICENSE.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /assets/laser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/laser.png -------------------------------------------------------------------------------- /assets/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/player.png -------------------------------------------------------------------------------- /assets/laser-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/laser-01.png -------------------------------------------------------------------------------- /assets/laser-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/laser-02.png -------------------------------------------------------------------------------- /assets/asteroid-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/asteroid-01.png -------------------------------------------------------------------------------- /assets/asteroid-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/asteroid-02.png -------------------------------------------------------------------------------- /assets/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/background.png -------------------------------------------------------------------------------- /assets/explosion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/explosion.png -------------------------------------------------------------------------------- /assets/lasers/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/lasers/11.png -------------------------------------------------------------------------------- /assets/lasers/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/lasers/12.png -------------------------------------------------------------------------------- /assets/lasers/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/lasers/13.png -------------------------------------------------------------------------------- /assets/lasers/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/lasers/14.png -------------------------------------------------------------------------------- /assets/lasers/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/lasers/15.png -------------------------------------------------------------------------------- /assets/lasers/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/lasers/16.png -------------------------------------------------------------------------------- /assets/lasers/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/lasers/17.png -------------------------------------------------------------------------------- /assets/lasers/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/lasers/18.png -------------------------------------------------------------------------------- /assets/lasers/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/lasers/19.png -------------------------------------------------------------------------------- /assets/lasers/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/lasers/20.png -------------------------------------------------------------------------------- /assets/enemy-blue-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-blue-01.png -------------------------------------------------------------------------------- /assets/enemy-blue-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-blue-02.png -------------------------------------------------------------------------------- /assets/enemy-red-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-red-01.png -------------------------------------------------------------------------------- /assets/enemy-red-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-red-02.png -------------------------------------------------------------------------------- /assets/enemy-brown-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-brown-01.png -------------------------------------------------------------------------------- /assets/enemy-brown-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-brown-02.png -------------------------------------------------------------------------------- /assets/enemy-green-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-green-01.png -------------------------------------------------------------------------------- /assets/enemy-green-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-green-02.png -------------------------------------------------------------------------------- /assets/enemy-orange-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-orange-01.png -------------------------------------------------------------------------------- /assets/enemy-orange-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-orange-02.png -------------------------------------------------------------------------------- /assets/enemy-purple-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-purple-01.png -------------------------------------------------------------------------------- /assets/enemy-purple-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-purple-02.png -------------------------------------------------------------------------------- /assets/enemy-yellow-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-yellow-01.png -------------------------------------------------------------------------------- /assets/enemy-yellow-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/enemy-yellow-02.png -------------------------------------------------------------------------------- /assets/explosions/explosion-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/explosions/explosion-01.png -------------------------------------------------------------------------------- /assets/explosions/explosion-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/explosions/explosion-02.png -------------------------------------------------------------------------------- /assets/explosions/explosion-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/explosions/explosion-03.png -------------------------------------------------------------------------------- /assets/explosions/explosion-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/explosions/explosion-04.png -------------------------------------------------------------------------------- /assets/explosions/explosion-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/explosions/explosion-05.png -------------------------------------------------------------------------------- /assets/explosions/explosion-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/explosions/explosion-06.png -------------------------------------------------------------------------------- /assets/explosions/explosion-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cristianscheid/space-crusher/HEAD/assets/explosions/explosion-07.png -------------------------------------------------------------------------------- /include/collision_detection.h: -------------------------------------------------------------------------------- 1 | #ifndef COLLISION_DETECTION_H 2 | #define COLLISION_DETECTION_H 3 | 4 | #include "setup.h" 5 | 6 | void detect_collision(GameObjects *go, GameControls *gc); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /include/render.h: -------------------------------------------------------------------------------- 1 | #ifndef RENDER_H 2 | #define RENDER_H 3 | 4 | #include 5 | #include "setup.h" 6 | 7 | void render(SDL_Renderer *renderer, GameObjects *game_objects); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/input_handler.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUT_HANDLER_H 2 | #define INPUT_HANDLER_H 3 | 4 | #include 5 | #include "setup.h" 6 | 7 | void process_input(SDL_Event *event, GameControls *game_controls); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/sandbox.h: -------------------------------------------------------------------------------- 1 | #ifndef SANDBOX_H 2 | #define SANDBOX_H 3 | 4 | #include "setup.h" 5 | 6 | void sandbox_init(GameObjects *go, Textures *t); 7 | void sandbox_update(GameObjects *go, Textures *t, GameControls *gc); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/update.h: -------------------------------------------------------------------------------- 1 | #ifndef UPDATE_H 2 | #define UPDATE_H 3 | 4 | #include "setup.h" 5 | 6 | void update_game_objects(GameObjects *game_objects, Textures *textures, GameControls *game_controls); 7 | 8 | void update_game_objects(GameObjects *game_objects, Textures *textures, GameControls *game_controls); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "type": "shell", 7 | "command": "make", 8 | "args": [], 9 | "group": { 10 | "kind": "build", 11 | "isDefault": true 12 | }, 13 | "problemMatcher": ["$gcc"] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Compiler and flags 2 | CC = gcc 3 | CFLAGS = -Wall -g -std=c11 -Iinclude 4 | LDFLAGS = -lSDL2 -lSDL2_image 5 | 6 | # Directories for source and object files 7 | SRCDIR = src 8 | OBJDIR = build 9 | 10 | # Source and object files 11 | SRCS = $(wildcard $(SRCDIR)/*.c) 12 | OBJS = $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SRCS)) 13 | 14 | # Executable target 15 | TARGET = $(OBJDIR)/space-crusher 16 | 17 | # Rule to build the target executable 18 | $(TARGET): $(OBJS) 19 | $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS) 20 | 21 | # Rule to compile .c files to .o files 22 | $(OBJDIR)/%.o: $(SRCDIR)/%.c 23 | @mkdir -p $(OBJDIR) 24 | $(CC) $(CFLAGS) -c $< -o $@ 25 | 26 | # Clean up object files and the build directory 27 | clean: 28 | rm -rf $(OBJDIR) 29 | -------------------------------------------------------------------------------- /src/update.c: -------------------------------------------------------------------------------- 1 | #include "update.h" 2 | #include 3 | #include 4 | #include "sandbox.h" 5 | 6 | void update_game_objects(GameObjects *game_objects, Textures *textures, GameControls *game_controls) 7 | { 8 | 9 | // Get delta_time factor converted to seconds to be used to update objects 10 | game_controls->delta_time = (SDL_GetTicks() - game_controls->last_frame_time) / 1000.0; 11 | // Store the milliseconds of the current frame to be used in the next one 12 | game_controls->last_frame_time = SDL_GetTicks(); 13 | game_controls->float_main_count += game_controls->delta_time; 14 | game_controls->int_main_count = game_controls->float_main_count; 15 | printf("%d - %.6f\n", game_controls->int_main_count, game_controls->float_main_count); 16 | 17 | sandbox_update(game_objects, textures, game_controls); 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Debug Space Crusher", 6 | "type": "cppdbg", 7 | "request": "launch", 8 | "program": "${workspaceFolder}/build/space-crusher", 9 | "cwd": "${workspaceFolder}", 10 | "stopAtEntry": false, 11 | "preLaunchTask": "build", 12 | "MIMode": "gdb", 13 | "miDebuggerPath": "/usr/bin/gdb", 14 | "setupCommands": [ 15 | { 16 | "text": "-enable-pretty-printing" 17 | } 18 | ] 19 | }, 20 | { 21 | "name": "Run Space Crusher", 22 | "type": "cppdbg", 23 | "request": "launch", 24 | "program": "${workspaceFolder}/build/space-crusher", 25 | "cwd": "${workspaceFolder}", 26 | "preLaunchTask": "build", 27 | "MIMode": "gdb", 28 | "miDebuggerPath": "/usr/bin/gdb", 29 | "noDebug": true 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Cristian Scheid 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 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "setup.h" 5 | #include "input_handler.h" 6 | #include "update.h" 7 | #include "render.h" 8 | #include "collision_detection.h" 9 | 10 | int main(int argc, char *args[]) 11 | { 12 | if (!initialize_sdl()) 13 | { 14 | return EXIT_FAILURE; 15 | } 16 | 17 | SDL_Window *window = create_window(); 18 | if (!window) 19 | { 20 | SDL_Quit(); 21 | return EXIT_FAILURE; 22 | } 23 | 24 | SDL_Renderer *renderer = create_renderer(window); 25 | if (!renderer) 26 | { 27 | SDL_DestroyWindow(window); 28 | SDL_Quit(); 29 | return EXIT_FAILURE; 30 | } 31 | 32 | Surfaces *surfaces = create_surfaces(); 33 | if (!surfaces) 34 | { 35 | SDL_DestroyRenderer(renderer); 36 | SDL_DestroyWindow(window); 37 | SDL_Quit(); 38 | return EXIT_FAILURE; 39 | } 40 | 41 | Textures *textures = create_textures(renderer, surfaces); 42 | if (!textures) 43 | { 44 | SDL_DestroyRenderer(renderer); 45 | SDL_DestroyWindow(window); 46 | SDL_Quit(); 47 | return EXIT_FAILURE; 48 | } 49 | 50 | SDL_Event event; 51 | GameObjects game_objects; 52 | GameControls game_controls = {0}; 53 | game_controls.game_is_running = true; 54 | 55 | while (game_controls.game_is_running) 56 | { 57 | process_input(&event, &game_controls); 58 | update_game_objects(&game_objects, textures, &game_controls); 59 | detect_collision(&game_objects, &game_controls); 60 | render(renderer, &game_objects); 61 | } 62 | 63 | destroy_textures(textures); 64 | SDL_DestroyRenderer(renderer); 65 | SDL_DestroyWindow(window); 66 | SDL_Quit(); 67 | return EXIT_SUCCESS; 68 | } 69 | -------------------------------------------------------------------------------- /src/input_handler.c: -------------------------------------------------------------------------------- 1 | #include "input_handler.h" 2 | #include 3 | 4 | void process_input(SDL_Event *event, GameControls *game_controls) 5 | { 6 | while (SDL_PollEvent(event)) 7 | { 8 | switch (event->type) 9 | { 10 | case SDL_KEYDOWN: 11 | switch (event->key.keysym.sym) 12 | { 13 | case SDLK_UP: 14 | game_controls->move_up = true; 15 | break; 16 | case SDLK_DOWN: 17 | game_controls->move_down = true; 18 | break; 19 | case SDLK_LEFT: 20 | game_controls->move_left = true; 21 | break; 22 | case SDLK_RIGHT: 23 | game_controls->move_right = true; 24 | break; 25 | case SDLK_SPACE: 26 | game_controls->shoot_laser = true; 27 | break; 28 | default: 29 | break; 30 | } 31 | break; 32 | case SDL_KEYUP: 33 | switch (event->key.keysym.sym) 34 | { 35 | case SDLK_UP: 36 | game_controls->move_up = false; 37 | break; 38 | case SDLK_DOWN: 39 | game_controls->move_down = false; 40 | break; 41 | case SDLK_LEFT: 42 | game_controls->move_left = false; 43 | break; 44 | case SDLK_RIGHT: 45 | game_controls->move_right = false; 46 | break; 47 | case SDLK_SPACE: 48 | game_controls->shoot_laser = false; 49 | break; 50 | default: 51 | break; 52 | } 53 | break; 54 | case SDL_QUIT: 55 | game_controls->game_is_running = false; 56 | break; 57 | default: 58 | break; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /include/setup.h: -------------------------------------------------------------------------------- 1 | #ifndef SETUP_H 2 | #define SETUP_H 3 | 4 | #include 5 | #include 6 | 7 | #define WINDOW_WIDTH 800 8 | #define WINDOW_HEIGHT 720 9 | 10 | typedef struct 11 | { 12 | SDL_Surface *background_sfc; 13 | SDL_Surface *player_sfc; 14 | SDL_Surface *enemy_sfcs[14]; 15 | SDL_Surface *asteroid_sfcs[2]; 16 | SDL_Surface *player_laser_sfc; 17 | SDL_Surface *enemy_laser_sfc; 18 | SDL_Surface *explosion_sfc; 19 | } Surfaces; 20 | 21 | typedef struct 22 | { 23 | SDL_Texture *background_tex; 24 | SDL_Texture *player_tex; 25 | SDL_Texture *enemy_texs[14]; 26 | SDL_Texture *asteroid_texs[2]; 27 | SDL_Texture *player_laser_tex; 28 | SDL_Texture *enemy_laser_tex; 29 | SDL_Texture *explosion_tex; 30 | } Textures; 31 | 32 | typedef struct 33 | { 34 | SDL_Rect rect; 35 | SDL_Texture *tex; 36 | float x; 37 | float y; 38 | float vel_x; 39 | float vel_y; 40 | int health; 41 | bool is_visible; 42 | float display_time; 43 | } GameObject; 44 | 45 | typedef struct 46 | { 47 | GameObject background[2]; 48 | GameObject player; 49 | GameObject enemies[10]; 50 | GameObject asteroids[10]; 51 | GameObject player_lasers[14]; 52 | GameObject enemy_lasers[14]; 53 | GameObject explosions[10]; 54 | bool game_is_running; 55 | } GameObjects; 56 | 57 | typedef struct 58 | { 59 | bool move_up; 60 | bool move_down; 61 | bool move_left; 62 | bool move_right; 63 | bool shoot_laser; 64 | int player_laser_count; 65 | int enemy_laser_count; 66 | int explosion_count; 67 | bool game_is_running; 68 | float delta_time; 69 | int last_frame_time; 70 | int int_main_count; 71 | float float_main_count; 72 | int flag; 73 | } GameControls; 74 | 75 | bool initialize_sdl(void); 76 | SDL_Window *create_window(void); 77 | SDL_Renderer *create_renderer(SDL_Window *window); 78 | Surfaces *create_surfaces(); 79 | Textures *create_textures(SDL_Renderer *renderer, Surfaces *surfaces); 80 | void free_surfaces(Surfaces *surfaces); 81 | void destroy_textures(Textures *textures); 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /src/render.c: -------------------------------------------------------------------------------- 1 | #include "render.h" 2 | 3 | void render(SDL_Renderer *renderer, GameObjects *game_objects) 4 | { 5 | // Clear the renderer 6 | SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); 7 | SDL_RenderClear(renderer); 8 | 9 | // Draw background 10 | for (int i = 0; i < sizeof(game_objects->background) / sizeof(game_objects->background[0]); i++) 11 | { 12 | if (game_objects->background[i].is_visible) 13 | { 14 | SDL_RenderCopy(renderer, game_objects->background[i].tex, NULL, &game_objects->background[i].rect); 15 | } 16 | } 17 | 18 | // Draw player lasers 19 | for (int i = 0; i < sizeof(game_objects->player_lasers) / sizeof(game_objects->player_lasers[0]); i++) 20 | { 21 | if (game_objects->player_lasers[i].is_visible) 22 | { 23 | SDL_RenderCopy(renderer, game_objects->player_lasers[i].tex, NULL, &game_objects->player_lasers[i].rect); 24 | } 25 | } 26 | 27 | // Draw player 28 | SDL_RenderCopy(renderer, game_objects->player.tex, NULL, &game_objects->player.rect); 29 | 30 | // Draw enemy lasers 31 | for (int i = 0; i < sizeof(game_objects->enemy_lasers) / sizeof(game_objects->enemy_lasers[0]); i++) 32 | { 33 | if (game_objects->enemy_lasers[i].is_visible) 34 | { 35 | SDL_RenderCopy(renderer, game_objects->enemy_lasers[i].tex, NULL, &game_objects->enemy_lasers[i].rect); 36 | } 37 | } 38 | 39 | // Draw enemies 40 | for (int i = 0; i < sizeof(game_objects->enemies) / sizeof(game_objects->enemies[0]); i++) 41 | { 42 | if (game_objects->enemies[i].is_visible) 43 | { 44 | SDL_RenderCopy(renderer, game_objects->enemies[i].tex, NULL, &game_objects->enemies[i].rect); 45 | } 46 | } 47 | 48 | // Draw asteroids 49 | for (int i = 0; i < sizeof(game_objects->asteroids) / sizeof(game_objects->asteroids[0]); i++) 50 | { 51 | if (game_objects->asteroids[i].is_visible) 52 | { 53 | SDL_RenderCopy(renderer, game_objects->asteroids[i].tex, NULL, &game_objects->asteroids[i].rect); 54 | } 55 | } 56 | 57 | // Draw explosions 58 | for (int i = 0; i < sizeof(game_objects->explosions) / sizeof(game_objects->explosions[0]); i++) 59 | { 60 | if (game_objects->explosions[i].is_visible) 61 | { 62 | SDL_RenderCopy(renderer, game_objects->explosions[i].tex, NULL, &game_objects->explosions[i].rect); 63 | } 64 | } 65 | 66 | SDL_Rect rect; 67 | rect.w = 25; 68 | rect.h = 25; 69 | 70 | // Draw player health bar 71 | for (int i = 0; i < game_objects->player.health; i++) 72 | { 73 | rect.x = WINDOW_WIDTH - 30; 74 | rect.y = WINDOW_HEIGHT - 30 - (30 * i); 75 | SDL_SetRenderDrawColor(renderer, 0, 100, 0, 255); 76 | SDL_RenderFillRect(renderer, &rect); 77 | } 78 | 79 | // Present the renderer 80 | SDL_RenderPresent(renderer); 81 | } 82 | -------------------------------------------------------------------------------- /src/setup.c: -------------------------------------------------------------------------------- 1 | #include "setup.h" 2 | #include 3 | #include 4 | 5 | bool initialize_sdl(void) 6 | { 7 | if (SDL_Init(SDL_INIT_EVERYTHING) != 0) 8 | { 9 | fprintf(stderr, "Error initializing SDL: %s\n", SDL_GetError()); 10 | return false; 11 | } 12 | return true; 13 | } 14 | 15 | SDL_Window *create_window(void) 16 | { 17 | SDL_Window *window = SDL_CreateWindow( 18 | "Space Crusher", 19 | SDL_WINDOWPOS_CENTERED, 20 | SDL_WINDOWPOS_CENTERED, 21 | WINDOW_WIDTH, 22 | WINDOW_HEIGHT, 23 | 0); 24 | if (!window) 25 | { 26 | fprintf(stderr, "Error creating SDL Window: %s\n", SDL_GetError()); 27 | } 28 | return window; 29 | } 30 | 31 | SDL_Renderer *create_renderer(SDL_Window *window) 32 | { 33 | SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0); 34 | if (!renderer) 35 | { 36 | fprintf(stderr, "Error creating SDL Renderer: %s\n", SDL_GetError()); 37 | } 38 | return renderer; 39 | } 40 | 41 | Surfaces *create_surfaces() 42 | { 43 | Surfaces *surfaces = malloc(sizeof(Surfaces)); 44 | if (!surfaces) 45 | return NULL; 46 | 47 | surfaces->background_sfc = IMG_Load("assets/background.png"); 48 | surfaces->player_sfc = IMG_Load("assets/player.png"); 49 | surfaces->enemy_sfcs[0] = IMG_Load("assets/enemy-blue-01.png"); 50 | surfaces->enemy_sfcs[1] = IMG_Load("assets/enemy-blue-02.png"); 51 | surfaces->enemy_sfcs[2] = IMG_Load("assets/enemy-brown-01.png"); 52 | surfaces->enemy_sfcs[3] = IMG_Load("assets/enemy-brown-02.png"); 53 | surfaces->enemy_sfcs[4] = IMG_Load("assets/enemy-green-01.png"); 54 | surfaces->enemy_sfcs[5] = IMG_Load("assets/enemy-green-02.png"); 55 | surfaces->enemy_sfcs[6] = IMG_Load("assets/enemy-orange-01.png"); 56 | surfaces->enemy_sfcs[7] = IMG_Load("assets/enemy-orange-02.png"); 57 | surfaces->enemy_sfcs[8] = IMG_Load("assets/enemy-purple-01.png"); 58 | surfaces->enemy_sfcs[9] = IMG_Load("assets/enemy-purple-02.png"); 59 | surfaces->enemy_sfcs[10] = IMG_Load("assets/enemy-red-01.png"); 60 | surfaces->enemy_sfcs[11] = IMG_Load("assets/enemy-red-02.png"); 61 | surfaces->enemy_sfcs[12] = IMG_Load("assets/enemy-yellow-01.png"); 62 | surfaces->enemy_sfcs[13] = IMG_Load("assets/enemy-yellow-02.png"); 63 | surfaces->asteroid_sfcs[0] = IMG_Load("assets/asteroid-01.png"); 64 | surfaces->asteroid_sfcs[1] = IMG_Load("assets/asteroid-02.png"); 65 | surfaces->player_laser_sfc = IMG_Load("assets/laser-01.png"); 66 | surfaces->enemy_laser_sfc = IMG_Load("assets/laser-02.png"); 67 | surfaces->explosion_sfc = IMG_Load("assets/explosion.png"); 68 | 69 | return surfaces; 70 | } 71 | 72 | Textures *create_textures(SDL_Renderer *renderer, Surfaces *surfaces) 73 | { 74 | Textures *textures = malloc(sizeof(Textures)); 75 | if (!textures) 76 | return NULL; 77 | 78 | textures->background_tex = SDL_CreateTextureFromSurface(renderer, surfaces->background_sfc); 79 | textures->player_tex = SDL_CreateTextureFromSurface(renderer, surfaces->player_sfc); 80 | for (int i = 0; i < 14; i++) 81 | { 82 | textures->enemy_texs[i] = SDL_CreateTextureFromSurface(renderer, surfaces->enemy_sfcs[i]); 83 | } 84 | for (int i = 0; i < 2; i++) 85 | { 86 | textures->asteroid_texs[i] = SDL_CreateTextureFromSurface(renderer, surfaces->asteroid_sfcs[i]); 87 | } 88 | textures->player_laser_tex = SDL_CreateTextureFromSurface(renderer, surfaces->player_laser_sfc); 89 | textures->enemy_laser_tex = SDL_CreateTextureFromSurface(renderer, surfaces->enemy_laser_sfc); 90 | textures->explosion_tex = SDL_CreateTextureFromSurface(renderer, surfaces->explosion_sfc); 91 | 92 | free_surfaces(surfaces); 93 | 94 | return textures; 95 | } 96 | 97 | void free_surfaces(Surfaces *surfaces) 98 | { 99 | SDL_FreeSurface(surfaces->background_sfc); 100 | SDL_FreeSurface(surfaces->player_sfc); 101 | for (int i = 0; i < 14; i++) 102 | { 103 | SDL_FreeSurface(surfaces->enemy_sfcs[i]); 104 | } 105 | for (int i = 0; i < 2; i++) 106 | { 107 | SDL_FreeSurface(surfaces->asteroid_sfcs[i]); 108 | } 109 | SDL_FreeSurface(surfaces->player_laser_sfc); 110 | SDL_FreeSurface(surfaces->enemy_laser_sfc); 111 | SDL_FreeSurface(surfaces->explosion_sfc); 112 | free(surfaces); 113 | } 114 | 115 | void destroy_textures(Textures *textures) 116 | { 117 | SDL_DestroyTexture(textures->background_tex); 118 | SDL_DestroyTexture(textures->player_tex); 119 | for (int i = 0; i < 14; i++) 120 | { 121 | SDL_DestroyTexture(textures->enemy_texs[i]); 122 | } 123 | for (int i = 0; i < 2; i++) 124 | { 125 | SDL_DestroyTexture(textures->asteroid_texs[i]); 126 | } 127 | SDL_DestroyTexture(textures->player_laser_tex); 128 | SDL_DestroyTexture(textures->enemy_laser_tex); 129 | SDL_DestroyTexture(textures->explosion_tex); 130 | free(textures); 131 | } 132 | -------------------------------------------------------------------------------- /src/collision_detection.c: -------------------------------------------------------------------------------- 1 | #include "collision_detection.h" 2 | 3 | typedef enum 4 | { 5 | ENEMY, 6 | ASTEROID 7 | } GameObjectType; 8 | 9 | void set_explosion(GameObjects *go, GameControls *gc, int go_index, GameObjectType object_type) 10 | { 11 | if (object_type == ENEMY) 12 | { 13 | go->explosions[gc->explosion_count].rect.x = go->enemies[go_index].rect.x + (go->enemies[go_index].rect.w / 2) - (go->explosions[gc->explosion_count].rect.w / 2); 14 | go->explosions[gc->explosion_count].rect.y = go->enemies[go_index].rect.y + (go->enemies[go_index].rect.h / 2) - (go->explosions[gc->explosion_count].rect.h / 2); 15 | } 16 | else if (object_type == ASTEROID) 17 | { 18 | go->explosions[gc->explosion_count].rect.x = go->asteroids[go_index].rect.x + (go->asteroids[go_index].rect.w / 2) - (go->explosions[gc->explosion_count].rect.w / 2); 19 | go->explosions[gc->explosion_count].rect.y = go->asteroids[go_index].rect.y + (go->asteroids[go_index].rect.h / 2) - (go->explosions[gc->explosion_count].rect.h / 2); 20 | } 21 | go->explosions[gc->explosion_count].is_visible = true; 22 | go->explosions[gc->explosion_count].display_time = 0; 23 | if (gc->explosion_count < (sizeof(go->explosions) / sizeof(go->explosions[0])) - 1) 24 | { 25 | gc->explosion_count++; 26 | } 27 | else 28 | { 29 | gc->explosion_count = 0; 30 | } 31 | } 32 | 33 | void detect_collision(GameObjects *go, GameControls *gc) 34 | { 35 | // Player Laser X Enemy 36 | for (int i = 0; i < sizeof(go->player_lasers) / sizeof(go->player_lasers[0]); i++) 37 | { 38 | for (int j = 0; j < sizeof(go->enemies) / sizeof(go->enemies[0]); j++) 39 | { 40 | if (go->player_lasers[i].is_visible && go->enemies[j].is_visible && go->player_lasers[i].rect.x > go->enemies[j].rect.x - go->player_lasers[i].rect.w && go->player_lasers[i].rect.x < go->enemies[j].rect.x + go->enemies[j].rect.w && go->player_lasers[i].rect.y < go->enemies[j].rect.y + go->enemies[j].rect.h) 41 | { 42 | // Set explosion 43 | set_explosion(go, gc, j, ENEMY); 44 | // Reset laser 45 | go->player_lasers[i].is_visible = false; 46 | // Reset enemy 47 | go->enemies[j].y = -150; 48 | } 49 | } 50 | } 51 | 52 | // Enemy Laser X Player 53 | for (int i = 0; i < sizeof(go->enemy_lasers) / sizeof(go->enemy_lasers[0]); i++) 54 | { 55 | if (go->enemy_lasers[i].is_visible && go->enemy_lasers[i].rect.x > go->player.rect.x - go->enemy_lasers[i].rect.w && go->enemy_lasers[i].rect.x < go->player.rect.x + go->player.rect.w && go->enemy_lasers[i].rect.y + go->enemy_lasers[i].rect.h > go->player.rect.y && go->enemy_lasers[i].rect.y < go->player.rect.y + go->player.rect.h) 56 | { 57 | go->player.health--; 58 | // Reset laser 59 | go->enemy_lasers[i].is_visible = false; 60 | } 61 | } 62 | 63 | // Player Laser X Asteroid 64 | for (int i = 0; i < sizeof(go->player_lasers) / sizeof(go->player_lasers[0]); i++) 65 | { 66 | for (int j = 0; j < sizeof(go->asteroids) / sizeof(go->asteroids[0]); j++) 67 | { 68 | if (go->player_lasers[i].is_visible && go->asteroids[j].is_visible && go->player_lasers[i].rect.x > go->asteroids[j].rect.x - go->player_lasers[i].rect.w && go->player_lasers[i].rect.x < go->asteroids[j].rect.x + go->asteroids[j].rect.w && go->player_lasers[i].rect.y < go->asteroids[j].rect.y + go->asteroids[j].rect.h) 69 | { 70 | // Set explosion 71 | set_explosion(go, gc, j, ASTEROID); 72 | // Reset laser 73 | go->player_lasers[i].is_visible = false; 74 | // Reset asteroid 75 | go->asteroids[j].y = -150; 76 | } 77 | } 78 | } 79 | 80 | // Player X Enemy 81 | for (int i = 0; i < sizeof(go->enemies) / sizeof(go->enemies[0]); i++) 82 | { 83 | if (go->enemies[i].is_visible && go->player.rect.x > go->enemies[i].rect.x - go->player.rect.w && go->player.rect.x < go->enemies[i].rect.x + go->enemies[i].rect.w && go->player.rect.y < go->enemies[i].rect.y + go->enemies[i].rect.h && go->player.rect.y > go->enemies[i].rect.y - go->player.rect.h) 84 | { 85 | go->enemies[i].y = -150; 86 | } 87 | } 88 | 89 | // Player X Asteroid 90 | for (int i = 0; i < sizeof(go->asteroids) / sizeof(go->asteroids[0]); i++) 91 | { 92 | if (go->asteroids[i].is_visible && go->player.rect.x > go->asteroids[i].rect.x - go->player.rect.w && go->player.rect.x < go->asteroids[i].rect.x + go->asteroids[i].rect.w && go->player.rect.y < go->asteroids[i].rect.y + go->asteroids[i].rect.h && go->player.rect.y > go->asteroids[i].rect.y - go->player.rect.h) 93 | { 94 | go->asteroids[i].y = -150; 95 | } 96 | } 97 | 98 | // Set duration explosion sprites remain visible 99 | for (int i = 0; i < sizeof(go->explosions) / sizeof(go->explosions[0]); i++) 100 | { 101 | if (go->explosions[i].is_visible) 102 | { 103 | if (go->explosions[i].display_time < 10) 104 | { 105 | // count increases as a function of delta time 106 | go->explosions[i].display_time += 100 * gc->delta_time; 107 | } 108 | else 109 | { 110 | go->explosions[i].is_visible = false; 111 | go->explosions[i].display_time = 0; 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Space Crusher 2 | 3 | ## Project Status 4 | 5 | Development is currently on hold due to time constraints. However, plans for future updates remain in place, including new levels, a main menu, refined gameplay mechanics, and more dynamic enemy and asteroid movements to elevate the gameplay experience. 6 | 7 | ## Description 8 | 9 | Space Crusher is a 2D space shooter game being developed from scratch using the C programming language and the SDL (Simple DirectMedia Layer) library. In this game, players control a spaceship, navigating through space while dodging asteroids and battling against various enemies. 10 | 11 | ## Features 12 | 13 | - Spaceship movement and shooting based on player input. 14 | - Collision detection for the spaceship, enemies, bullets, and asteroids. 15 | - Health bar decrease upon collisions with enemy bullets. 16 | - Sandbox level for testing and demonstration purposes. 17 | 18 | ## Built With 19 | 20 | ![C][c-badge] 21 | ![SDL][sdl-badge] 22 | 23 | ## Visuals 24 | 25 | https://github.com/user-attachments/assets/ca299c9f-9e42-453f-a0e4-ba1ce25b53a2 26 | 27 | ## Installation 28 | 29 | To get started with this project, follow the steps below: 30 | 31 | 1. **Install build tools and SDL libraries** 32 | 33 | - Debian/Ubuntu: 34 | 35 | ``` 36 | sudo apt install gcc make libsdl2-dev libsdl2-image-dev 37 | ``` 38 | 39 | - Fedora/RHEL/CentOS: 40 | 41 | ``` 42 | sudo dnf install gcc make SDL2-devel SDL2_image-devel 43 | ``` 44 | 45 | - OpenSUSE: 46 | 47 | ``` 48 | sudo zypper install gcc make SDL2-devel SDL2_image-devel 49 | ``` 50 | 51 | - Arch Linux: 52 | 53 | ``` 54 | sudo pacman -S gcc make sdl2 sdl2_image 55 | ``` 56 | 57 | - If your Linux distribution is not listed, you can find instructions for installing the SDL libraries from source [here](https://lazyfoo.net/tutorials/SDL/01_hello_SDL/linux/index.php). 58 | 59 | 2. **Clone the repository** 60 | 61 | ``` 62 | git clone https://github.com/cristianscheid/space-crusher.git 63 | cd space-crusher 64 | ``` 65 | 66 | 3. **Build the project** 67 | 68 | ``` 69 | make 70 | ``` 71 | 72 | 4. **Run the executable** 73 | 74 | ``` 75 | ./build/space-crusher 76 | ``` 77 | 78 | ## Usage 79 | 80 | Once the game is running, you can control the spaceship using the arrow keys to move and the spacebar to shoot. To exit the game, simply close the window. 81 | 82 | ### Running and Debugging with Visual Studio Code 83 | 84 | To run or debug the project with Visual Studio Code, follow these steps: 85 | 86 | - Open the `space-crusher` project folder in Visual Studio Code. 87 | 88 | - Install the `C/C++` extension by Microsoft from the Extensions tab (Ctrl+Shift+X). 89 | 90 | - Go to the Run and Debug tab (Ctrl+Shift+D). 91 | 92 | - Select "Debug Space Crusher" or "Run Space Crusher" from the dropdown at the top, next to the play icon. 93 | 94 | - Click the play icon to start. If you're debugging, remember to set breakpoints. 95 | 96 | ## Acknowledgment 97 | 98 | Special thanks to the asset creators at [OpenGameArt](https://opengameart.org) for their contributions to this project. Below is a list of the assets used: 99 | 100 | - Spaceships: 101 | 102 | - https://opengameart.org/content/2d-spaceship-pack 103 | 104 | - Background: 105 | 106 | - https://opengameart.org/content/space-background-6 107 | 108 | - Laser: 109 | 110 | - https://opengameart.org/content/assets-free-laser-bullets-pack-2020 111 | 112 | - Explosion: 113 | 114 | - https://opengameart.org/content/blasteroids-art-pack-cc-by-30 115 | 116 | - Asteroids: 117 | 118 | - https://opengameart.org/content/asteroids-set-01 119 | - https://opengameart.org/content/asteroids-set-02 120 | 121 | ## License 122 | 123 | Distributed under the MIT License. See LICENSE.txt for more information. 124 | 125 | 126 | 127 | [c-badge]: https://img.shields.io/badge/C-C11-gray?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OCA0OCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyI+PHBhdGggZD0iTTI0IDBhMi41NiAyLjU2IDAgMCAwLTEuMjU0LjMyNkwzLjU0IDExLjEwN2MtLjc3Ni40MzUtMS4yNTQgMS4yNDEtMS4yNTQgMi4xMTJ2MjEuNTYyYTIuNDMgMi40MyAwIDAgMCAxLjI1NCAyLjExMmwxOS4yMDUgMTAuNzgxYy43NzUuNDM1IDEuNzMzLjQzNSAyLjUwOSAwTDQ0LjQ2IDM2Ljg5MmMuNzc2LS40MzUgMS4yNTQtMS4yNDEgMS4yNTQtMi4xMTJWMTMuMjE5YTIuNDIzIDIuNDIzIDAgMCAwLS4wMjItLjEyOWMtLjAzMi0uNDk0LS4xNDgtMS4wMDYtLjUzNi0xLjM5M2EyLjQyMyAyLjQyMyAwIDAgMC0uNjk2LS41ODlMMjUuMjU0LjMyNkMyNC44NjcuMTA4IDI0LjQzMyAwIDI0IDB6bTAgOGExNi4wMTEgMTYuMDExIDAgMCAxIDExLjMxMiA0LjY4OCAxNi4wMTEgMTYuMDExIDAgMCAxIDEuOTg3IDIuNDI0IDE2LjAxMSAxNi4wMTEgMCAwIDEgLjQ1NS43NjNMMzAuODMgMTkuODNsLS4xOTYtLjMwNC0uNDYtLjYxNi0uNTE4LS41NjctLjU2Ny0uNTE4LS42MTYtLjQ2LS42NjEtLjQwMmE3Ljk4IDcuOTggMCAwIDAtLjcwMS0uMzM1bC0uNzMyLS4yNjgtLjc2OC0uMjAxYTcuOTkgNy45OSAwIDAgMC0uNzk1LS4xMjFBOC4wNyA4LjA3IDAgMCAwIDI0IDE2bC0uODE3LjA0LS43OTUuMTIxYTcuOTggNy45OCAwIDAgMC0uNzY4LjIwMWwtLjczMi4yNjgtLjcwMS4zMzUtLjY2MS40MDItLjYxNi40NmMtLjE5OC4xNjMtLjM4Ni4zMzctLjU2Ny41MThsLS41MTguNTY3LS40Ni42MTYtLjQwMi42NjFhNy45OCA3Ljk4IDAgMCAwLS4zMzUuNzAxbC0uMjY4LjczMi0uMjAxLjc2OGE3Ljk5IDcuOTkgMCAwIDAtLjEyMS43OTVBOC4wNyA4LjA3IDAgMCAwIDE2IDI0bC4wNC44MTcuMTIxLjc5NWE3Ljk4IDcuOTggMCAwIDAgLjIwMS43NjhsLjI2OC43MzIuMzM1LjcwMS40MDIuNjYxLjQ2LjYxNmMuMTYzLjE5OC4zMzcuMzg2LjUxOC41NjdsLjU2Ny41MTguNjE2LjQ2LjY2MS40MDJhNy45OCA3Ljk4IDAgMCAwIC43MDEuMzM1bC43MzIuMjY4Ljc2OC4yMDFhNy45OSA3Ljk5IDAgMCAwIC43OTUuMTIxQTguMDcgOC4wNyAwIDAgMCAyNCAzMmwuODE3LS4wNC43OTUtLjEyMWE3Ljk4IDcuOTggMCAwIDAgLjc2OC0uMjAxbC43MzItLjI2OC43MDEtLjMzNS42NjEtLjQwMi42MTYtLjQ2Yy4xOTgtLjE2My4zODYtLjMzNy41NjctLjUxOGwuNTE4LS41NjcuNDYtLjYxNi4yNjMtLjQyNCA2Ljk5NSAzLjg0OGExNi4wMTEgMTYuMDExIDAgMCAxLS41OTQuOTkxIDE2LjAxMSAxNi4wMTEgMCAwIDEtMTAuMTc5IDYuODA0IDE2LjAxMSAxNi4wMTEgMCAwIDEtMTIuMDA5LTIuMzkzIDE2LjAxMSAxNi4wMTEgMCAwIDEtNi44MDQtMTAuMTc5QTE2LjAxMSAxNi4wMTEgMCAwIDEgMTAuNyAxNS4xMWExNi4wMTEgMTYuMDExIDAgMCAxIDEwLjE3OS02LjgwNEExNi4wMTEgMTYuMDExIDAgMCAxIDI0IDh6IiBmaWxsPSIjZmZmIi8+PC9zdmc+ 128 | [sdl-badge]: https://img.shields.io/badge/SDL-2.0-gray?style=for-the-badge&logo=data:image/png;base64,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 129 | -------------------------------------------------------------------------------- /src/sandbox.c: -------------------------------------------------------------------------------- 1 | #include "sandbox.h" 2 | #include 3 | #include 4 | 5 | bool first_call = true; 6 | 7 | void sandbox_init(GameObjects *go, Textures *t) 8 | { 9 | // Background 10 | int background_width, background_height; 11 | SDL_QueryTexture(t->background_tex, NULL, NULL, &background_width, &background_height); 12 | go->background[0].tex = go->background[1].tex = t->background_tex; 13 | go->background[0].x = go->background[1].x = 0; 14 | go->background[0].y = WINDOW_HEIGHT - background_height; 15 | go->background[1].y = -background_height; 16 | go->background[0].rect.w = go->background[1].rect.w = background_width; 17 | go->background[0].rect.h = go->background[1].rect.h = background_height; 18 | go->background[0].vel_y = go->background[1].vel_y = 700; 19 | go->background[0].is_visible = true; 20 | go->background[1].is_visible = false; 21 | 22 | // Player 23 | go->player.tex = t->player_tex; 24 | SDL_QueryTexture(go->player.tex, NULL, NULL, &go->player.rect.w, &go->player.rect.h); 25 | go->player.x = (WINDOW_WIDTH / 2) - (go->player.rect.w / 2); 26 | go->player.y = 500; 27 | go->player.vel_x = 300; 28 | go->player.vel_y = 300; 29 | go->player.health = 5; 30 | 31 | // Enemies 32 | for (int i = 0; i < sizeof(go->enemies) / sizeof(go->enemies[0]); i++) 33 | { 34 | // Generate random index (j) to choose random sprite 35 | int j = rand() % (sizeof(t->enemy_texs) / sizeof(t->enemy_texs[0])); 36 | go->enemies[i].tex = t->enemy_texs[j]; 37 | SDL_QueryTexture(go->enemies[i].tex, NULL, NULL, &go->enemies[i].rect.w, &go->enemies[i].rect.h); 38 | go->enemies[i].x = i * 100; 39 | go->enemies[i].y = 150; 40 | go->enemies[i].is_visible = false; 41 | } 42 | 43 | // Asteroids 44 | for (int i = 0; i < sizeof(go->asteroids) / sizeof(go->asteroids[0]); i++) 45 | { 46 | // Generate random index (j) to choose random sprite 47 | int j = rand() % ((sizeof(t->asteroid_texs) / sizeof(t->asteroid_texs[0]))); 48 | go->asteroids[i].tex = t->asteroid_texs[j]; 49 | SDL_QueryTexture(go->asteroids[i].tex, NULL, NULL, &go->asteroids[i].rect.w, &go->asteroids[i].rect.h); 50 | go->asteroids[i].x = i * 100; 51 | go->asteroids[i].y = 0; 52 | go->asteroids[i].is_visible = false; 53 | } 54 | 55 | // Player laser 56 | int player_laser_width, player_laser_height; 57 | SDL_QueryTexture(t->player_laser_tex, NULL, NULL, &player_laser_width, &player_laser_height); 58 | for (int i = 0; i < sizeof(go->player_lasers) / sizeof(go->player_lasers[0]); i++) 59 | { 60 | go->player_lasers[i].tex = t->player_laser_tex; 61 | go->player_lasers[i].rect.w = player_laser_width; 62 | go->player_lasers[i].rect.h = player_laser_height; 63 | go->player_lasers[i].vel_y = 800; 64 | go->player_lasers[i].is_visible = false; 65 | } 66 | 67 | // Enemy laser 68 | int enemy_laser_width, enemy_laser_height; 69 | SDL_QueryTexture(t->enemy_laser_tex, NULL, NULL, &enemy_laser_width, &enemy_laser_height); 70 | for (int i = 0; i < sizeof(go->enemy_lasers) / sizeof(go->enemy_lasers[0]); i++) 71 | { 72 | go->enemy_lasers[i].tex = t->enemy_laser_tex; 73 | go->enemy_lasers[i].rect.w = enemy_laser_width; 74 | go->enemy_lasers[i].rect.h = enemy_laser_height; 75 | go->enemy_lasers[i].vel_y = 100; 76 | go->enemy_lasers[i].is_visible = false; 77 | } 78 | 79 | // Explosion 80 | int explosion_img_width, explosion_img_height; 81 | SDL_QueryTexture(t->explosion_tex, NULL, NULL, &explosion_img_width, &explosion_img_height); 82 | for (int i = 0; i < sizeof(go->explosions) / sizeof(go->explosions[0]); i++) 83 | { 84 | go->explosions[i].tex = t->explosion_tex; 85 | go->explosions[i].rect.w = explosion_img_width / 1.5; 86 | go->explosions[i].rect.h = explosion_img_height / 1.5; 87 | go->explosions[i].is_visible = false; 88 | } 89 | } 90 | 91 | void sandbox_update(GameObjects *go, Textures *t, GameControls *gc) 92 | { 93 | 94 | if (first_call) 95 | { 96 | sandbox_init(go, t); 97 | first_call = false; 98 | } 99 | 100 | // Move Background 101 | for (int i = 0; i < sizeof(go->background) / sizeof(go->background[0]); i++) 102 | { 103 | bool j = !i; 104 | if (go->background[i].is_visible && go->background[i].y < WINDOW_HEIGHT) 105 | { 106 | go->background[i].y += go->background[i].vel_y * gc->delta_time; 107 | // Set SDL_Rect coordinates 108 | go->background[i].rect.x = go->background[i].x; 109 | go->background[i].rect.y = go->background[i].y; 110 | if (go->background[i].y > 0) 111 | { 112 | go->background[j].is_visible = true; 113 | } 114 | } 115 | else 116 | { 117 | go->background[i].is_visible = false; 118 | go->background[i].y = -go->background[i].rect.h; 119 | } 120 | } 121 | 122 | // Move player 123 | if (gc->move_up && !(gc->move_down) && go->player.y > 0) 124 | { 125 | go->player.y -= go->player.vel_y * gc->delta_time; 126 | } 127 | if (gc->move_down && !(gc->move_up) && go->player.y < WINDOW_HEIGHT - go->player.rect.h) 128 | { 129 | go->player.y += go->player.vel_y * gc->delta_time; 130 | } 131 | if (gc->move_left && !(gc->move_right) && go->player.x > 0) 132 | { 133 | go->player.x -= go->player.vel_x * gc->delta_time; 134 | } 135 | if (gc->move_right && !(gc->move_left) && go->player.x < WINDOW_WIDTH - go->player.rect.w) 136 | { 137 | go->player.x += go->player.vel_x * gc->delta_time; 138 | } 139 | // Set SDL_Rect coordinates 140 | go->player.rect.x = go->player.x; 141 | go->player.rect.y = go->player.y; 142 | 143 | // Move enemies 144 | for (int i = 0; i < sizeof(go->enemies) / sizeof(go->enemies[0]); i++) 145 | { 146 | go->enemies[i].y += go->enemies[i].vel_y * gc->delta_time; 147 | if (go->enemies[i].y >= 0 - go->enemies[i].rect.h && go->enemies[i].y < WINDOW_HEIGHT) 148 | { 149 | go->enemies[i].is_visible = true; 150 | // Set SDL_Rect coordinates 151 | go->enemies[i].rect.x = go->enemies[i].x; 152 | go->enemies[i].rect.y = go->enemies[i].y; 153 | } 154 | else 155 | { 156 | go->enemies[i].is_visible = false; 157 | } 158 | } 159 | 160 | // Move asteroids 161 | for (int i = 0; i < sizeof(go->asteroids) / sizeof(go->asteroids[0]); i++) 162 | { 163 | go->asteroids[i].y += go->asteroids[i].vel_y * gc->delta_time; 164 | if (go->asteroids[i].y >= 0 - go->asteroids[i].rect.h && go->asteroids[i].y < WINDOW_HEIGHT) 165 | { 166 | go->asteroids[i].is_visible = true; 167 | // Set SDL_Rect coordinates 168 | go->asteroids[i].rect.x = go->asteroids[i].x; 169 | go->asteroids[i].rect.y = go->asteroids[i].y; 170 | } 171 | else 172 | { 173 | go->asteroids[i].is_visible = false; 174 | } 175 | } 176 | 177 | // Start player laser (if space was pressed) 178 | if (gc->shoot_laser) 179 | { 180 | go->player_lasers[gc->player_laser_count].x = go->player.x + (go->player.rect.w / 2) - (go->player_lasers[gc->player_laser_count].rect.w / 2); 181 | go->player_lasers[gc->player_laser_count].y = go->player.y; 182 | go->player_lasers[gc->player_laser_count].is_visible = true; 183 | if (gc->player_laser_count < (sizeof(go->player_lasers) / sizeof(go->player_lasers[0])) - 1) 184 | { 185 | gc->player_laser_count++; 186 | } 187 | else 188 | { 189 | gc->player_laser_count = 0; 190 | } 191 | gc->shoot_laser = false; 192 | } 193 | 194 | // Move player lasers 195 | for (int i = 0; i < sizeof(go->player_lasers) / sizeof(go->player_lasers[0]); i++) 196 | { 197 | if (go->player_lasers[i].is_visible) 198 | { 199 | if (go->player_lasers[i].y > 0 - go->player_lasers[i].rect.h && go->player_lasers[i].y < WINDOW_HEIGHT) 200 | { 201 | go->player_lasers[i].y -= go->player_lasers[i].vel_y * gc->delta_time; 202 | // Set SDL_Rect coordinates 203 | go->player_lasers[i].rect.x = go->player_lasers[i].x; 204 | go->player_lasers[i].rect.y = go->player_lasers[i].y; 205 | } 206 | else 207 | { 208 | go->player_lasers[i].is_visible = false; 209 | } 210 | } 211 | } 212 | 213 | // Move enemy lasers 214 | for (int i = 0; i < sizeof(go->enemies) / sizeof(go->enemies[0]); i++) 215 | { 216 | if (gc->int_main_count == 1 + i && gc->flag == i) 217 | { 218 | go->enemy_lasers[i].x = go->enemies[i].x + (go->enemies[i].rect.w / 2) - (go->enemy_lasers[i].rect.w / 2); 219 | go->enemy_lasers[i].y = go->enemies[i].y + go->enemies[i].rect.h - go->enemy_lasers[i].rect.h; 220 | go->enemy_lasers[i].is_visible = true; 221 | gc->flag++; 222 | } 223 | } 224 | for (int i = 0; i < sizeof(go->enemy_lasers) / sizeof(go->enemy_lasers[0]); i++) 225 | { 226 | if (go->enemy_lasers[i].is_visible) 227 | { 228 | if (go->enemy_lasers[i].y > 0 - go->enemy_lasers[i].rect.h && go->enemy_lasers[i].y < WINDOW_HEIGHT) 229 | { 230 | go->enemy_lasers[i].y += go->enemy_lasers[i].vel_y * gc->delta_time; 231 | // Set SDL_Rect coordinates 232 | go->enemy_lasers[i].rect.x = go->enemy_lasers[i].x; 233 | go->enemy_lasers[i].rect.y = go->enemy_lasers[i].y; 234 | } 235 | else 236 | { 237 | go->enemy_lasers[i].is_visible = false; 238 | } 239 | } 240 | } 241 | } 242 | --------------------------------------------------------------------------------