From 4dadeb807d4332d885be6a22e426dcd670ee06dc Mon Sep 17 00:00:00 2001 From: Vincent Yang Date: Sun, 4 Jan 2026 19:42:22 +0800 Subject: [PATCH] Update --- .gitignore | 3 +- Makefile | 4 +- res/bullet.bmp | Bin 0 -> 1175702 bytes src/bullet.c | 47 +++++---- src/bullet.h | 5 +- src/game.h | 25 +++++ src/main.c | 280 ++++++++++++++++++++++++++++++++----------------- src/player.c | 51 +++++---- src/player.h | 12 ++- 9 files changed, 279 insertions(+), 148 deletions(-) create mode 100644 res/bullet.bmp create mode 100644 src/game.h diff --git a/.gitignore b/.gitignore index 34b43b3..66c7095 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ build/ star-invaders *.kra *.xcf -*.png \ No newline at end of file +*.png +*.*~ \ No newline at end of file diff --git a/Makefile b/Makefile index 8118678..31a8d6d 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # Simple Makefile using sdl-config for SDL flags -CC := gcc +CC := clang SDL_CFLAGS := $(shell sdl2-config --cflags) SDL_LIBS := $(shell sdl2-config --libs) -CFLAGS := -Wall -Wextra -std=c99 $(SDL_CFLAGS) +CFLAGS := -Wall -Wextra -std=c99 -g $(SDL_CFLAGS) SRCDIR := src SOURCES := $(wildcard $(SRCDIR)/*.c) BUILD_DIR := build diff --git a/res/bullet.bmp b/res/bullet.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d312f733f34c906da44606f4cc6fb0e1e04b8ec2 GIT binary patch literal 1175702 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 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FpSAf&T@K CFrG93 literal 0 HcmV?d00001 diff --git a/src/bullet.c b/src/bullet.c index 98049e5..8b9959c 100644 --- a/src/bullet.c +++ b/src/bullet.c @@ -1,9 +1,21 @@ #include "bullet.h" +#include "game.h" +#include +#include +#include + +void initBullet(Bullet *bullet, int x, int y) { + bullet->rect.x = x; + bullet->rect.y = y; + bullet->rect.w = 50; // Bullet width + bullet->rect.h = 50; // Bullet height + bullet->active = 0; +} void updateBullets(Bullet *bullets, int *bulletCount, SDL_Renderer* renderer) { int bulletSpeed = 7; - for (int i = 0; i < *bulletCount; i++) { + for (int i = 0; i < MAX_BULLETS; i++) { if (bullets[i].active) { // Move bullet upward bullets[i].rect.y -= bulletSpeed; @@ -11,32 +23,31 @@ void updateBullets(Bullet *bullets, int *bulletCount, SDL_Renderer* renderer) { // Deactivate if bullet goes off screen if (bullets[i].rect.y < 0) { bullets[i].active = 0; + (*bulletCount)--; } else { - // Draw bullet - SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); - SDL_RenderFillRect(renderer, &bullets[i].rect); + // Draw bullet using global textures + SDL_RenderCopy(renderer, textures.bulletTexture, NULL, &bullets[i].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; - bullets[*bulletCount].rect.w = 4; - bullets[*bulletCount].rect.h = 10; - bullets[*bulletCount].active = 1; - (*bulletCount)++; + for (int i = 0; i < MAX_BULLETS; i++) { + if (!bullets[i].active) { + bullets[i].rect.x = rect->x; + bullets[i].rect.y = rect->y; + bullets[i].active = 1; + (*bulletCount)++; + break; + } } } -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--; - } +void cleanupBullets(Bullet *bullets, int *bulletCount) { + // Deactivate all bullets and reset count + for (int i = 0; i < MAX_BULLETS; i++) { + bullets[i].active = 0; } + *bulletCount = 0; } \ No newline at end of file diff --git a/src/bullet.h b/src/bullet.h index ea287b7..fb1e0e6 100644 --- a/src/bullet.h +++ b/src/bullet.h @@ -10,8 +10,11 @@ typedef struct { int active; } Bullet; +/* Initialize an existing Bullet struct */ +void initBullet(Bullet *bullet, int x, int y); + void updateBullets(Bullet *bullets, int *bulletCount, SDL_Renderer *renderer); void fireBullet(Bullet *bullets, int *bulletCount, SDL_Rect *rect); -void cleanupUnrenderedBullets(Bullet* bullets, int* bulletCount); +void cleanupBullets(Bullet *bullets, int *bulletCount); #endif diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..a27aacb --- /dev/null +++ b/src/game.h @@ -0,0 +1,25 @@ +#ifndef GAME_H +#define GAME_H + +#include + +#define FPS 60 +#define FRAME_DELAY (1000 / FPS) // Milliseconds per frame +#define SCREEN_WIDTH 800 +#define SCREEN_HEIGHT 600 + +typedef struct { + char *spaceshipPath; + char *backgroundPath; + char *bulletPath; +} AssetPaths; + +typedef struct { + SDL_Texture *bulletTexture; + SDL_Texture *playerTexture; + SDL_Texture *backgroundTexture; +} Textures; + +extern Textures textures; + +#endif /* GAME_H */ \ No newline at end of file diff --git a/src/main.c b/src/main.c index 09f9c8f..e929cf7 100644 --- a/src/main.c +++ b/src/main.c @@ -1,25 +1,150 @@ #include "bullet.h" +#include "game.h" #include "player.h" #include #include #include #include -#define FPS 60 -#define FRAME_DELAY (1000 / FPS) // Milliseconds per frame -#define SCREEN_WIDTH 800 -#define SCREEN_HEIGHT 600 +Textures textures = {0}; // global textures storage (initialized to NULL pointers) -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); +int loadTextures(SDL_Renderer *renderer, AssetPaths *paths) { + SDL_Surface *bulletSurface = SDL_LoadBMP(paths->bulletPath); + if (!bulletSurface) { + fprintf(stderr, "Could not load bullet image: %s\n", SDL_GetError()); + return 0; } - // Render player flipped vertically - renderPlayerFlipped(renderer, player, SDL_FLIP_VERTICAL); + textures.bulletTexture = SDL_CreateTextureFromSurface(renderer, bulletSurface); + SDL_FreeSurface(bulletSurface); + if (!textures.bulletTexture) { + fprintf(stderr, "Could not create bullet texture: %s\n", SDL_GetError()); + return 0; + } + + SDL_Surface *playerSurface = SDL_LoadBMP(paths->spaceshipPath); + if (!playerSurface) { + fprintf(stderr, "Could not load player image: %s\n", SDL_GetError()); + SDL_DestroyTexture(textures.bulletTexture); + textures.bulletTexture = NULL; + return 0; + } + + textures.playerTexture = SDL_CreateTextureFromSurface(renderer, playerSurface); + SDL_FreeSurface(playerSurface); + if (!textures.playerTexture) { + fprintf(stderr, "Could not create player texture: %s\n", SDL_GetError()); + SDL_DestroyTexture(textures.bulletTexture); + textures.bulletTexture = NULL; + return 0; + } + + /* Load background (non-fatal) */ + SDL_Surface *bgSurface = SDL_LoadBMP(paths->backgroundPath); + if (!bgSurface) { + fprintf(stderr, "Could not load background %s: %s\n", paths->backgroundPath, SDL_GetError()); + textures.backgroundTexture = NULL; + } else { + textures.backgroundTexture = SDL_CreateTextureFromSurface(renderer, bgSurface); + SDL_FreeSurface(bgSurface); + if (!textures.backgroundTexture) { + fprintf(stderr, "Could not create background texture: %s\n", SDL_GetError()); + textures.backgroundTexture = NULL; + } + } + + return 1; +} + +/* + * Parse command-line arguments. Returns: + * 0 -> continue normally + * 1 -> printed help/version, should exit success + * -1 -> error in args, should exit failure + */ +static int handleArguments(int argc, char *argv[], char **resLocation) { + 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"); + return 1; + } else if (strcmp(argv[args], "--version") == 0 || strcmp(argv[args], "-v") == 0) { + printf("Star Invaders Version 1.0.0\n"); + return 1; + } else if (strcmp(argv[args], "--res-location") == 0 || strcmp(argv[args], "-rl") == 0) { + if (args + 1 >= argc) { + fprintf(stderr, "Missing value for %s\n", argv[args]); + printf("Use --help or -h for usage information.\n"); + return -1; + } + *resLocation = argv[++args]; + } else { + printf("Unknown argument: %s\n", argv[args]); + printf("Use --help or -h for usage information.\n"); + return -1; + } + } + return 0; +} + +AssetPaths *getResources(const char *resLocation) { + AssetPaths *paths = (AssetPaths *)malloc(sizeof(AssetPaths)); + if (!paths) { + fprintf(stderr, "Out of memory\n"); + return NULL; + } + + size_t pathLen; + const char *shipFile = "spaceship.bmp"; + const char *bgFile = "background.bmp"; + const char *bulletFile = "bullet.bmp"; + + pathLen = strlen(resLocation) + strlen(shipFile) + 2; + paths->spaceshipPath = (char *)malloc(pathLen); + if (!paths->spaceshipPath) { + free(paths); + fprintf(stderr, "Out of memory\n"); + return NULL; + } + if (resLocation[strlen(resLocation) - 1] == '/') { + snprintf(paths->spaceshipPath, pathLen, "%s%s", resLocation, shipFile); + } else { + snprintf(paths->spaceshipPath, pathLen, "%s/%s", resLocation, shipFile); + } + + pathLen = strlen(resLocation) + strlen(bgFile) + 2; + paths->backgroundPath = (char *)malloc(pathLen); + if (!paths->backgroundPath) { + free(paths->spaceshipPath); + free(paths); + fprintf(stderr, "Out of memory\n"); + return NULL; + } + if (resLocation[strlen(resLocation) - 1] == '/') { + snprintf(paths->backgroundPath, pathLen, "%s%s", resLocation, bgFile); + } else { + snprintf(paths->backgroundPath, pathLen, "%s/%s", resLocation, bgFile); + } + + pathLen = strlen(resLocation) + strlen(bulletFile) + 2; + paths->bulletPath = (char *)malloc(pathLen); + if (!paths->bulletPath) { + free(paths->backgroundPath); + free(paths->spaceshipPath); + free(paths); + fprintf(stderr, "Out of memory\n"); + return NULL; + } + if (resLocation[strlen(resLocation) - 1] == '/') { + snprintf(paths->bulletPath, pathLen, "%s%s", resLocation, bulletFile); + } else { + snprintf(paths->bulletPath, pathLen, "%s/%s", resLocation, bulletFile); + } + + return paths; } int main(int argc, char *argv[]) { @@ -29,74 +154,31 @@ int main(int argc, char *argv[]) { } 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); - - // Build full paths for assets - size_t pathLen; - char *spaceshipPath; - char *backgroundPath; - const char *shipFile = "spaceship.bmp"; - const char *bgFile = "background.bmp"; - - pathLen = strlen(resLocation) + strlen(shipFile) + 2; - spaceshipPath = (char *)malloc(pathLen); - if (!spaceshipPath) { - fprintf(stderr, "Out of memory\n"); + int argResult = handleArguments(argc, argv, &resLocation); + if (argResult == 1) { + SDL_Quit(); + return EXIT_SUCCESS; + } else if (argResult == -1) { 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); - } - pathLen = strlen(resLocation) + strlen(bgFile) + 2; - backgroundPath = (char *)malloc(pathLen); - if (!backgroundPath) { - free(spaceshipPath); - fprintf(stderr, "Out of memory\n"); + AssetPaths *paths = getResources(resLocation); + if (!paths) { + fprintf(stderr, "Could not load resources\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); - } 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()); + free(paths->backgroundPath); + free(paths->bulletPath); + free(paths->spaceshipPath); + free(paths); SDL_Quit(); return EXIT_FAILURE; } @@ -106,42 +188,46 @@ int main(int argc, char *argv[]) { if (!renderer) { fprintf(stderr, "Could not create renderer: %s\n", SDL_GetError()); SDL_DestroyWindow(window); + free(paths->backgroundPath); + free(paths->bulletPath); + free(paths->spaceshipPath); + free(paths); SDL_Quit(); return EXIT_FAILURE; } - int speed = 5; + if (!loadTextures(renderer, paths)) { + fprintf(stderr, "Could not create game textures: %s\n", SDL_GetError()); + free(paths->backgroundPath); + free(paths->bulletPath); + free(paths->spaceshipPath); + free(paths); + SDL_Quit(); + return EXIT_FAILURE; + } // Bullets array - Bullet bullets[MAX_BULLETS]; int bulletCount = 0; + Bullet bullets[MAX_BULLETS]; for (int i = 0; i < MAX_BULLETS; i++) { - bullets[i].active = 0; + initBullet(&bullets[i], 0, 0); } // Create player - Player *player = createPlayer(renderer, spaceshipPath, 400, 500); + Player *player = createPlayer(400, 500); if (!player) { SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); - free(spaceshipPath); - free(backgroundPath); + free(paths->spaceshipPath); + free(paths->backgroundPath); + free(paths); + if (textures.bulletTexture) SDL_DestroyTexture(textures.bulletTexture); + if (textures.playerTexture) SDL_DestroyTexture(textures.playerTexture); 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()); - } - } + /* background is loaded into textures.backgroundTexture by loadTextures */ // Main loop flag int running = 1; @@ -171,16 +257,16 @@ int main(int argc, char *argv[]) { SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); // Draw background if available - if (background) { - SDL_RenderCopy(renderer, background, NULL, NULL); + if (textures.backgroundTexture) { + SDL_RenderCopy(renderer, textures.backgroundTexture, NULL, NULL); } // Update and draw bullets updateBullets(bullets, &bulletCount, renderer); - cleanupUnrenderedBullets(bullets, &bulletCount); + // cleanupUnrenderedBullets(bullets, &bulletCount); // removed // Handle player movement and rendering - handlePlayer(renderer, player, speed, keys); + handlePlayer(renderer, player, playerSpeed, keys); // Present the rendered frame SDL_RenderPresent(renderer); @@ -193,11 +279,17 @@ int main(int argc, char *argv[]) { } destroyPlayer(player); - if (background) { - SDL_DestroyTexture(background); - } - free(spaceshipPath); - free(backgroundPath); + + // Cleanup bullets (deactivate all) + cleanupBullets(bullets, &bulletCount); + + if (textures.bulletTexture) SDL_DestroyTexture(textures.bulletTexture); + if (textures.playerTexture) SDL_DestroyTexture(textures.playerTexture); + if (textures.backgroundTexture) SDL_DestroyTexture(textures.backgroundTexture); + + free(paths->spaceshipPath); + free(paths->backgroundPath); + free(paths); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); diff --git a/src/player.c b/src/player.c index 4b3cb5a..e22f94d 100644 --- a/src/player.c +++ b/src/player.c @@ -1,27 +1,25 @@ #include "player.h" +#include "game.h" #include #include -Player *createPlayer(SDL_Renderer *renderer, const char *imagePath, int x, - int y) { +int playerSpeed = 5; + +void handlePlayer(SDL_Renderer *renderer, Player *player, int playerSpeed, const Uint8 *keys) { + if (keys[SDL_SCANCODE_LEFT] || keys[SDL_SCANCODE_A]) { + movePlayerLeft(player, playerSpeed); + } + if (keys[SDL_SCANCODE_RIGHT] || keys[SDL_SCANCODE_D]) { + movePlayerRight(player, playerSpeed, SCREEN_WIDTH); + } + + // Render player flipped vertically + renderPlayerFlipped(renderer, player, SDL_FLIP_VERTICAL); +} + +Player *createPlayer(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; @@ -31,30 +29,29 @@ Player *createPlayer(SDL_Renderer *renderer, const char *imagePath, int x, } void renderPlayer(SDL_Renderer *renderer, Player *player) { - SDL_RenderCopy(renderer, player->texture, NULL, &player->rect); + SDL_RenderCopy(renderer, textures.playerTexture, NULL, &player->rect); } void renderPlayerFlipped(SDL_Renderer *renderer, Player *player, SDL_RendererFlip flip) { - SDL_RenderCopyEx(renderer, player->texture, NULL, &player->rect, 0, NULL, + SDL_RenderCopyEx(renderer, textures.playerTexture, 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 playerSpeed) { + if (player->rect.x - playerSpeed >= 0) { + player->rect.x -= playerSpeed; } } -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 playerSpeed, int screenWidth) { + if (player->rect.x + player->rect.w + playerSpeed <= screenWidth) { + player->rect.x += playerSpeed; } } void destroyPlayer(Player *player) { if (player) { - SDL_DestroyTexture(player->texture); free(player); } } diff --git a/src/player.h b/src/player.h index c55a0fe..2da2628 100644 --- a/src/player.h +++ b/src/player.h @@ -4,17 +4,19 @@ #include typedef struct { - SDL_Texture *texture; SDL_Rect rect; } Player; -Player *createPlayer(SDL_Renderer *renderer, const char *imagePath, int x, - int y); +extern int playerSpeed; + +void handlePlayer(SDL_Renderer *renderer, Player *player, int playerSpeed, const Uint8 *keys); + +Player *createPlayer(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 movePlayerLeft(Player *player, int playerSpeed); +void movePlayerRight(Player *player, int playerSpeed, int screenWidth); void destroyPlayer(Player *player); #endif