diff --git a/.gitignore b/.gitignore index 567609b..34b43b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,12 @@ build/ +.vscode/ +*.o +*.exe +*.out +*.log +.DS_Store + +star-invaders +*.kra +*.xcf +*.png \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 4001b84..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(SDL2_Example LANGUAGES C) - -# Set the C standard to C99 -set(CMAKE_C_STANDARD 99) -set(CMAKE_C_STANDARD_REQUIRED ON) - -# Find SDL2 -find_package(SDL2 REQUIRED) - -# Add your executable target -file(GLOB SOURCES "src/*.c") -add_executable(star-invaders ${SOURCES}) - -# Link the SDL2 libraries to your executable -target_link_libraries(star-invaders PRIVATE SDL2::SDL2) \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8118678 --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +# Simple Makefile using sdl-config for SDL flags +CC := gcc +SDL_CFLAGS := $(shell sdl2-config --cflags) +SDL_LIBS := $(shell sdl2-config --libs) +CFLAGS := -Wall -Wextra -std=c99 $(SDL_CFLAGS) +SRCDIR := src +SOURCES := $(wildcard $(SRCDIR)/*.c) +BUILD_DIR := build +OBJECTS := $(patsubst $(SRCDIR)/%.c,$(BUILD_DIR)/%.o,$(SOURCES)) +TARGET := star-invaders + +.PHONY: all clean + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + @echo " Linking $@" + @$(CC) $(OBJECTS) -o $@ $(SDL_LIBS) + +$(BUILD_DIR)/%.o: $(SRCDIR)/%.c | $(BUILD_DIR) + @echo " Compiling $<" + @$(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR): + @mkdir -p $(BUILD_DIR) + +clean: + @echo "Cleaning up" + @rm -rf $(BUILD_DIR) $(TARGET) diff --git a/res/background.bmp b/res/background.bmp new file mode 100644 index 0000000..c947ade Binary files /dev/null and b/res/background.bmp differ diff --git a/res/spaceship.png b/res/spaceship.png deleted file mode 100644 index 86950a8..0000000 Binary files a/res/spaceship.png and /dev/null differ diff --git a/src/bullet.c b/src/bullet.c index a876ed3..98049e5 100644 --- a/src/bullet.c +++ b/src/bullet.c @@ -1,6 +1,6 @@ #include "bullet.h" -void updateBullets(Bullet* bullets, int* bulletCount, SDL_Renderer* renderer) { +void updateBullets(Bullet *bullets, int *bulletCount, SDL_Renderer* renderer) { int bulletSpeed = 7; for (int i = 0; i < *bulletCount; i++) { @@ -20,7 +20,7 @@ void updateBullets(Bullet* bullets, int* bulletCount, SDL_Renderer* renderer) { } } -void fireBullet(Bullet* bullets, int* bulletCount, SDL_Rect* rect) { +void fireBullet(Bullet *bullets, int *bulletCount, SDL_Rect* rect) { if (*bulletCount < MAX_BULLETS) { bullets[*bulletCount].rect.x = rect->x + rect->w / 2 - 2; bullets[*bulletCount].rect.y = rect->y - 10; @@ -30,3 +30,13 @@ void fireBullet(Bullet* bullets, int* bulletCount, SDL_Rect* rect) { (*bulletCount)++; } } + +void cleanupUnrenderedBullets(Bullet* bullets, int* bulletCount) { + for (int i = 0; i < *bulletCount; i++){ + if(bullets[i].active == 0){ + memmove(&bullets[i], &bullets[i + 1], sizeof(Bullet) * (*bulletCount - i - 1)); + (*bulletCount)--; + i--; + } + } +} \ No newline at end of file diff --git a/src/bullet.h b/src/bullet.h index 4af7a1f..ea287b7 100644 --- a/src/bullet.h +++ b/src/bullet.h @@ -1,16 +1,17 @@ #ifndef BULLET_H #define BULLET_H -#include +#include -#define MAX_BULLETS 100 +#define MAX_BULLETS 5 typedef struct { - SDL_Rect rect; - int active; + SDL_Rect rect; + int active; } Bullet; -void updateBullets(Bullet* bullets, int* bulletCount, SDL_Renderer* renderer); -void fireBullet(Bullet* bullets, int* bulletCount, SDL_Rect* rect); +void updateBullets(Bullet *bullets, int *bulletCount, SDL_Renderer *renderer); +void fireBullet(Bullet *bullets, int *bulletCount, SDL_Rect *rect); +void cleanupUnrenderedBullets(Bullet* bullets, int* bulletCount); #endif diff --git a/src/main.c b/src/main.c index d8bdaa9..09f9c8f 100644 --- a/src/main.c +++ b/src/main.c @@ -1,121 +1,205 @@ -#include -#include -#include #include "bullet.h" #include "player.h" +#include +#include +#include +#include #define FPS 60 -#define FRAME_DELAY (1000 / FPS) // Milliseconds per frame +#define FRAME_DELAY (1000 / FPS) // Milliseconds per frame #define SCREEN_WIDTH 800 #define SCREEN_HEIGHT 600 -void handlePlayer(SDL_Renderer* renderer, Player* player, int speed) { - // Get current keyboard state - const Uint8* keys = SDL_GetKeyboardState(NULL); +void handlePlayer(SDL_Renderer *renderer, Player *player, int speed, const Uint8 *keys) { + if (keys[SDL_SCANCODE_LEFT] || keys[SDL_SCANCODE_A]) { + movePlayerLeft(player, speed); + } + if (keys[SDL_SCANCODE_RIGHT] || keys[SDL_SCANCODE_D]) { + movePlayerRight(player, speed, SCREEN_WIDTH); + } - if (keys[SDL_SCANCODE_LEFT] || keys[SDL_SCANCODE_A]) { - movePlayerLeft(player, speed); - } - if (keys[SDL_SCANCODE_RIGHT] || keys[SDL_SCANCODE_D]) { - movePlayerRight(player, speed, SCREEN_WIDTH); - } - - // Render player flipped vertically - renderPlayerFlipped(renderer, player, SDL_FLIP_VERTICAL); + // Render player flipped vertically + renderPlayerFlipped(renderer, player, SDL_FLIP_VERTICAL); } -int main(int argc, char* argv[]) { - if (SDL_Init(SDL_INIT_VIDEO) != 0) { - fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError()); - return EXIT_FAILURE; +int main(int argc, char *argv[]) { + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError()); + return EXIT_FAILURE; + } + + char *resLocation = "./res/"; + + for (int args = 1; args < argc; args++) { + if (strcmp(argv[args], "--help") == 0 || + strcmp(argv[args], "-h") == 0) { + printf("Star Invaders Help:\n"); + printf("Use arrow keys or A/D to move the spaceship left and right.\n"); + printf("Press SPACE to fire bullets.\n"); + printf("Press ESC or close the window to exit the game.\n"); + printf("Use --res-location or -rl to specify the resource location.\n"); + SDL_Quit(); + return EXIT_SUCCESS; + } else if (strcmp(argv[args], "--version") == 0 || + strcmp(argv[args], "-v") == 0) { + printf("Star Invaders Version 1.0.0\n"); + SDL_Quit(); + return EXIT_SUCCESS; + } else if (strcmp(argv[args], "--res-location") == 0 || + strcmp(argv[args], "-rl") == 0) { + resLocation = argv[args + 1]; + args++; + } else { + printf("Unknown argument: %s\n", argv[args]); + printf("Use --help or -h for usage information.\n"); + SDL_Quit(); + return EXIT_FAILURE; } + } + printf("Using resource location: %s\n", resLocation); - SDL_Window* window = SDL_CreateWindow("Star Invaders", - SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN); - if (!window) { - fprintf(stderr, "Could not create window: %s\n", SDL_GetError()); - SDL_Quit(); - return EXIT_FAILURE; - } + // Build full paths for assets + size_t pathLen; + char *spaceshipPath; + char *backgroundPath; + const char *shipFile = "spaceship.bmp"; + const char *bgFile = "background.bmp"; - SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); - if (!renderer) { - fprintf(stderr, "Could not create renderer: %s\n", SDL_GetError()); - SDL_DestroyWindow(window); - SDL_Quit(); - return EXIT_FAILURE; - } + pathLen = strlen(resLocation) + strlen(shipFile) + 2; + spaceshipPath = (char *)malloc(pathLen); + if (!spaceshipPath) { + fprintf(stderr, "Out of memory\n"); + SDL_Quit(); + return EXIT_FAILURE; + } + if (resLocation[strlen(resLocation) - 1] == '/') { + snprintf(spaceshipPath, pathLen, "%s%s", resLocation, shipFile); + } else { + snprintf(spaceshipPath, pathLen, "%s/%s", resLocation, shipFile); + } - // Rectangle position and size - SDL_Rect rect = {400, 500, 50, 50}; - int speed = 5; + pathLen = strlen(resLocation) + strlen(bgFile) + 2; + backgroundPath = (char *)malloc(pathLen); + if (!backgroundPath) { + free(spaceshipPath); + fprintf(stderr, "Out of memory\n"); + SDL_Quit(); + return EXIT_FAILURE; + } + if (resLocation[strlen(resLocation) - 1] == '/') { + snprintf(backgroundPath, pathLen, "%s%s", resLocation, bgFile); + } else { + snprintf(backgroundPath, pathLen, "%s/%s", resLocation, bgFile); + } - // Bullets array - Bullet bullets[MAX_BULLETS]; - int bulletCount = 0; - for (int i = 0; i < MAX_BULLETS; i++) { - bullets[i].active = 0; - } + SDL_Window *window = SDL_CreateWindow("Star Invaders", SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, + SCREEN_HEIGHT, SDL_WINDOW_SHOWN); + if (!window) { + fprintf(stderr, "Could not create window: %s\n", SDL_GetError()); + SDL_Quit(); + return EXIT_FAILURE; + } - // Create player - Player* player = createPlayer(renderer, "../res/spaceship.bmp", 400, 500); - if (!player) { - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); - SDL_Quit(); - return EXIT_FAILURE; - } - - // Main loop flag - int running = 1; - SDL_Event event; - Uint32 frameStart; - int frameTime; - int spacePressedLastFrame = 0; - - // Main loop - while (running) { - frameStart = SDL_GetTicks(); - - while (SDL_PollEvent(&event)) { - if (event.type == SDL_QUIT) { - running = 0; - } - } - - // Get current keyboard state for space key - const Uint8* keys = SDL_GetKeyboardState(NULL); - if (keys[SDL_SCANCODE_SPACE] && !spacePressedLastFrame) { - fireBullet(bullets, &bulletCount, &player->rect); - } - spacePressedLastFrame = keys[SDL_SCANCODE_SPACE]; - - // Clear screen with black - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderClear(renderer); - - // Update and draw bullets - updateBullets(bullets, &bulletCount, renderer); - - // Handle player movement and rendering - handlePlayer(renderer, player, speed); - - // Present the rendered frame - SDL_RenderPresent(renderer); - - // Cap framerate at 60 FPS - frameTime = SDL_GetTicks() - frameStart; - if (frameTime < FRAME_DELAY) { - SDL_Delay(FRAME_DELAY - frameTime); - } - } - - destroyPlayer(player); - SDL_DestroyRenderer(renderer); + SDL_Renderer *renderer = + SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + if (!renderer) { + fprintf(stderr, "Could not create renderer: %s\n", SDL_GetError()); SDL_DestroyWindow(window); SDL_Quit(); - return EXIT_SUCCESS; + return EXIT_FAILURE; + } + + int speed = 5; + + // Bullets array + Bullet bullets[MAX_BULLETS]; + int bulletCount = 0; + for (int i = 0; i < MAX_BULLETS; i++) { + bullets[i].active = 0; + } + + // Create player + Player *player = createPlayer(renderer, spaceshipPath, 400, 500); + if (!player) { + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + free(spaceshipPath); + free(backgroundPath); + SDL_Quit(); + return EXIT_FAILURE; + } + + // Load background + SDL_Texture *background = NULL; + SDL_Surface *bgSurface = SDL_LoadBMP(backgroundPath); + if (!bgSurface) { + fprintf(stderr, "Could not load background %s: %s\n", backgroundPath, SDL_GetError()); + } else { + background = SDL_CreateTextureFromSurface(renderer, bgSurface); + SDL_FreeSurface(bgSurface); + if (!background) { + fprintf(stderr, "Could not create background texture: %s\n", SDL_GetError()); + } + } + + // Main loop flag + int running = 1; + SDL_Event event; + Uint32 frameStart; + int frameTime; + int spacePressedLastFrame = 0; + + // Main loop + while (running) { + frameStart = SDL_GetTicks(); + + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + running = 0; + } + } + + // Get current keyboard state for space key + const Uint8 *keys = SDL_GetKeyboardState(NULL); + if (keys[SDL_SCANCODE_SPACE] && !spacePressedLastFrame) { + fireBullet(bullets, &bulletCount, &player->rect); + } + spacePressedLastFrame = keys[SDL_SCANCODE_SPACE]; + + // Clear screen with black + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + // Draw background if available + if (background) { + SDL_RenderCopy(renderer, background, NULL, NULL); + } + + // Update and draw bullets + updateBullets(bullets, &bulletCount, renderer); + cleanupUnrenderedBullets(bullets, &bulletCount); + + // Handle player movement and rendering + handlePlayer(renderer, player, speed, keys); + + // Present the rendered frame + SDL_RenderPresent(renderer); + + // Cap framerate at 60 FPS + frameTime = SDL_GetTicks() - frameStart; + if (frameTime < FRAME_DELAY) { + SDL_Delay(FRAME_DELAY - frameTime); + } + } + + destroyPlayer(player); + if (background) { + SDL_DestroyTexture(background); + } + free(spaceshipPath); + free(backgroundPath); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); + return EXIT_SUCCESS; } \ No newline at end of file diff --git a/src/player.c b/src/player.c index 2383669..4b3cb5a 100644 --- a/src/player.c +++ b/src/player.c @@ -2,56 +2,59 @@ #include #include -Player* createPlayer(SDL_Renderer* renderer, const char* imagePath, int x, int y) { - Player* player = (Player*)malloc(sizeof(Player)); - - SDL_Surface* surface = SDL_LoadBMP(imagePath); - if (!surface) { - fprintf(stderr, "Could not load image %s: %s\n", imagePath, SDL_GetError()); - free(player); - return NULL; - } - - player->texture = SDL_CreateTextureFromSurface(renderer, surface); - SDL_FreeSurface(surface); - - if (!player->texture) { - fprintf(stderr, "Could not create texture: %s\n", SDL_GetError()); - free(player); - return NULL; - } - - player->rect.x = x; - player->rect.y = y; - player->rect.w = 50; - player->rect.h = 50; - - return player; +Player *createPlayer(SDL_Renderer *renderer, const char *imagePath, int x, + int y) { + Player *player = (Player *)malloc(sizeof(Player)); + + SDL_Surface *surface = SDL_LoadBMP(imagePath); + if (!surface) { + fprintf(stderr, "Could not load image %s: %s\n", imagePath, SDL_GetError()); + free(player); + return NULL; + } + + player->texture = SDL_CreateTextureFromSurface(renderer, surface); + SDL_FreeSurface(surface); + + if (!player->texture) { + fprintf(stderr, "Could not create texture: %s\n", SDL_GetError()); + free(player); + return NULL; + } + + player->rect.x = x; + player->rect.y = y; + player->rect.w = 50; + player->rect.h = 50; + + return player; } -void renderPlayer(SDL_Renderer* renderer, Player* player) { - SDL_RenderCopy(renderer, player->texture, NULL, &player->rect); +void renderPlayer(SDL_Renderer *renderer, Player *player) { + SDL_RenderCopy(renderer, player->texture, NULL, &player->rect); } -void renderPlayerFlipped(SDL_Renderer* renderer, Player* player, SDL_RendererFlip flip) { - SDL_RenderCopyEx(renderer, player->texture, NULL, &player->rect, 0, NULL, flip); +void renderPlayerFlipped(SDL_Renderer *renderer, Player *player, + SDL_RendererFlip flip) { + SDL_RenderCopyEx(renderer, player->texture, NULL, &player->rect, 0, NULL, + flip); } -void movePlayerLeft(Player* player, int speed) { - if (player->rect.x - speed >= 0) { - player->rect.x -= speed; - } +void movePlayerLeft(Player *player, int speed) { + if (player->rect.x - speed >= 0) { + player->rect.x -= speed; + } } -void movePlayerRight(Player* player, int speed, int screenWidth) { - if (player->rect.x + player->rect.w + speed <= screenWidth) { - player->rect.x += speed; - } +void movePlayerRight(Player *player, int speed, int screenWidth) { + if (player->rect.x + player->rect.w + speed <= screenWidth) { + player->rect.x += speed; + } } -void destroyPlayer(Player* player) { - if (player) { - SDL_DestroyTexture(player->texture); - free(player); - } +void destroyPlayer(Player *player) { + if (player) { + SDL_DestroyTexture(player->texture); + free(player); + } } diff --git a/src/player.h b/src/player.h index e3c05b2..c55a0fe 100644 --- a/src/player.h +++ b/src/player.h @@ -1,18 +1,20 @@ #ifndef PLAYER_H #define PLAYER_H -#include +#include typedef struct { - SDL_Texture* texture; - SDL_Rect rect; + SDL_Texture *texture; + SDL_Rect rect; } Player; -Player* createPlayer(SDL_Renderer* renderer, const char* imagePath, int x, int y); -void renderPlayer(SDL_Renderer* renderer, Player* player); -void renderPlayerFlipped(SDL_Renderer* renderer, Player* player, SDL_RendererFlip flip); -void movePlayerLeft(Player* player, int speed); -void movePlayerRight(Player* player, int speed, int screenWidth); -void destroyPlayer(Player* player); +Player *createPlayer(SDL_Renderer *renderer, const char *imagePath, int x, + int y); +void renderPlayer(SDL_Renderer *renderer, Player *player); +void renderPlayerFlipped(SDL_Renderer *renderer, Player *player, + SDL_RendererFlip flip); +void movePlayerLeft(Player *player, int speed); +void movePlayerRight(Player *player, int speed, int screenWidth); +void destroyPlayer(Player *player); #endif