From 59b51c2bebea2fb41b5e945301aba96bc3fd5005 Mon Sep 17 00:00:00 2001 From: huaqo Date: Thu, 5 Mar 2026 11:13:55 +0100 Subject: [PATCH] feat: player can shoot --- .github/workflows/build-macos.yaml | 63 ------------- .gitignore | 4 - .vscode/c_cpp_properties.json | 16 ---- .vscode/settings.json | 9 -- Makefile | 19 ++-- README.md | 122 ------------------------- config/config.ini | 2 +- include/app.h | 4 +- src/appGame.c | 2 + src/appGameEnemies.c | 137 ++++++++++++++--------------- src/appGameProjectiles.c | 70 ++++++++++++++- 11 files changed, 150 insertions(+), 298 deletions(-) delete mode 100644 .github/workflows/build-macos.yaml delete mode 100644 .gitignore delete mode 100644 .vscode/c_cpp_properties.json delete mode 100644 .vscode/settings.json delete mode 100644 README.md diff --git a/.github/workflows/build-macos.yaml b/.github/workflows/build-macos.yaml deleted file mode 100644 index 2fae8c4..0000000 --- a/.github/workflows/build-macos.yaml +++ /dev/null @@ -1,63 +0,0 @@ -name: Build & Release on macOS - -# Run on *every push* to "main," and also build on PRs (but only create the release on push). -on: - push: - branches: - - main - pull_request: - branches: - - main - -permissions: - contents: write # needed so the workflow can create a tag & release - -jobs: - build-and-release-macos: - runs-on: macos-latest - steps: - - name: Check out source - uses: actions/checkout@v3 - - - name: Install Dependencies (Homebrew & raylib) - run: | - brew update - brew install raylib pkg-config - - - name: Build - # Your Makefile from the question - run: make build - - - name: Create Tag & GitHub Release - # Only create a release when it's a push (not a pull_request) - if: ${{ github.event_name == 'push' }} - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - # You need a unique tag each time to avoid "already_exists" errors. - # Here we'll name the tag like "build-123" using the run_number, - # but you could do something like a date-based tag. - tag_name: build-${{ github.run_number }} - - # The commit to tag. Usually, this is the push commit SHA: - commitish: ${{ github.sha }} - - # The release name can match the tag or be more descriptive - release_name: "Automated build #${{ github.run_number }}" - - # Adjust as needed; you could set these to false for a "final" release - draft: false - prerelease: true # Mark as "pre-release" so it's clearly automated - - - name: Upload Release Asset - if: ${{ github.event_name == 'push' }} - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: bin/osx/game - asset_name: game - asset_content_type: application/octet-stream diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 82cd32d..0000000 --- a/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -bin/ -.DS_STORE/ -.DS_STORE -*.swp diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index ed15a77..0000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "configurations": [ - { - "name": "Windows", - "includePath": [ - "${workspaceFolder}/include", - "${workspaceFolder}/external/engine", - "${workspaceFolder}/external/raygui", - "${workspaceFolder}/external/rini", - "C:/raylib/include" - ], - "cStandard": "c99", - } - ], - "version": 4 -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 3cd8cb3..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "files.associations": { - "asset.h": "c", - "stdlib.h": "c", - "view.h": "c", - "__node_handle": "c", - "font.h": "c" - } -} \ No newline at end of file diff --git a/Makefile b/Makefile index b668a54..9491e23 100644 --- a/Makefile +++ b/Makefile @@ -1,43 +1,50 @@ COMPILER = gcc +# COMPILER FLAGS C_FLAG_STD_C99 = -std=c99 # Use the C99 language standard C_FLAG_DEBUG_INFO = -g # Include debug information -# C_FLAG_HEADERS = -H # Prints paths of all headers +#C_FLAG_HEADERS = -H # Prints paths of all headers C_FLAG_ALL_WARNINGS = -Wall # Enable most common warning C_FLAG_PEDANTIC = -Wpedantic # Enforce ISO C standard strictly C_FLAG_SHADOW = -Wshadow # Warn if a local variable shadows another C_FLAG_STRICT_PROTOS = -Wstrict-prototypes # Warn if function declarations are missing parameter types C_FLAG_NO_UNKNOWN_PRAGMAS = -Wno-unknown-pragmas # Suppress warnings about unknown pragmas + C_FLAGS = \ $(C_FLAG_STD_C99) \ $(C_FLAG_DEBUG_INFO) \ - $(C_FLAG_HEADERS) \ + $(C_FLAG_HEADERS) \ $(C_FLAG_ALL_WARNINGS) \ $(C_FLAG_PEDANTIC) \ $(C_FLAG_SHADOW) \ - $(C_FLAG_STRICT_PROTOS) \ + $(C_FLAG_STRICT_PROTOS) \ $(C_FLAG_NO_UNKNOWN_PRAGMAS) +# INCLUDE FLGAS INCLUDE_FLAGS = -Iinclude -EXTERNAL_RAYGUI = -Iexternal/raygui +# EXTERNAL FLAGS +EXTERNAL_RAYGUI = -Iexternal/raygui EXTERNAL_RINI = -Iexternal/rini EXTERNAL_FLAGS = \ $(EXTERNAL_RINI) \ $(EXTERNAL_RAYGUI) +# CROSS PLATTFORM ifeq ($(OS), Windows_NT) SRC = $(wildcard src\*.c) TARGET = bin\win\game.exe RAYLIB_FLAGS = -I%RAYLIB% -L%RAYLIB% -lraylib -lopengl32 -lgdi32 -lwinmm else SRC = $(wildcard src/*.c) - TARGET = bin/osx/game + TARGET = bin/unix/game RAYLIB_FLAGS = $(shell pkg-config --libs --cflags raylib) -lm endif -$(shell mkdir -p bin/osx bin/win) +# CREATE BIN DIR +$(shell mkdir -p bin/unix bin/win) +# COMMANDS build: $(SRC) $(COMPILER) $(SRC) -o $(TARGET) $(C_FLAGS) $(INCLUDE_FLAGS) $(EXTERNAL_FLAGS) $(RAYLIB_FLAGS) diff --git a/README.md b/README.md deleted file mode 100644 index 7e433d5..0000000 --- a/README.md +++ /dev/null @@ -1,122 +0,0 @@ -## Requirements - -Make 4.4.1 -GCC 14.2 -RAYLIB 5.5 -pkgconf(MACOS) - -This document outlines the coding style and conventions to be followed. - -## 1. **File Structure** - -- Header files should be wrapped with include guards to avoid multiple inclusions: - - ```c - #ifndef PHYSICS_H - #define PHYSICS_H - ... - #endif // PHYSICS_H - ``` - -## 2. **Naming Conventions** - -- **Functions:** Function names should use `CamelCase` starting with a upercase letter. - -`UpdatePhysicsDirection`, `UpdatePhysicsVelocity` - -- **Structs:** Struct names should use `CamelCase` starting with an uppercase letter. - -`Physics` - -- **Variables:** Use `CamelCase` starting with a lowerase letter for local and parameter variables. - -`vector`, `newSpeed` - -## 3. **Function Design** - -- Functions should be named descriptively, indicating the purpose or action performed. - -`UpdatePhysicsDirection`, `UpdatePhysicsVelocity` - -- Functions should take pointers when modifying variables outside their scope. - -`void UpdatePhysicsDirection(Vector2 *direction, Vector2 vector)` - -- Ensure function parameters have clear names to indicate their role. - -`UpdatePhysicsVelocity(Vector2 *velocity, Vector2 *direction, float *speed)` - -- Functions should be concise and focused on a single task. Avoid functions with multiple responsibilities. - -## 4. **Struct Design** - - - Prefer composition, where structs are composed of other structs or primitive data types. This allows for more flexible and modular designs. - - ```c - typedef struct { - Vector2 position; - Vector2 direction; - Vector2 velocity; - float speed; - } Physics; - ``` - - Here, instead of trying to create a hierarchy of structs, we compose a Physics struct with relevant fields like `position`, `direction`, and `velocity`. - -## 5. **Indentation & Formatting** - -- **Indentation:** Use 1 tab for indentation. Never use spaces. - -- **Spacing:** Place a single space after keywords like `if`, `for`, and `while`, and around operators (`=`, `+`, `-`, etc.) for readability. - - Example: `*velocity = Vector2Scale(*direction, *speed * GetFrameTime());` - -- **Braces:** Use braces `{}` even for single-line blocks for consistency and future-proofing. - - ```c - if (condition) { - do_something(); - } - ``` - -## 6. **Pointer Usage** - -- Use pointers when passing large structures or when modifying variables outside the scope of the function. - -`Vector2 *position`, `float *speed` - -- Avoid unnecessary dereferencing and use `*` clearly to indicate pointer dereferencing. - -`*position = Vector2Add(*position, *velocity);` - -## 7. **Consistency in Function Calls** - -- When calling functions, parameters should be passed clearly, and care should be taken to avoid modifying data unintentionally unless needed. - - ```c - UpdatePhysicsDirection(&physics->direction, direction); - UpdatePhysicsVelocity(&physics->velocity, &physics->direction, &physics->speed); - UpdatePhysicsPosition(&physics->position, &physics->velocity); - ``` - -## 8. **Comments and Documentation** - -- Strive for clarity through descriptive naming and simple logic. -- Add comments to explain non-obvious logic, design decisions, or complex algorithms. -- Do not state the obvious; let the code speak for itself where possible. - -## 9. **End of File** - -- Always ensure that header files end with the appropriate closing include guard and a new line after the last line of code: - - ```c - #endif // PHYSICS_H - - ``` - -## 10. **General Rules** - -- **Modular Design**: Break code into small, focused functions and modules with clear interfaces. -- **Refactoring**: Regularly refactor code to maintain simplicity and performance -- **Don't Repeat Yourself**: Reuse code by creating helper functions to avoid duplication -- **Avoid magic numbers:** Use constants or defines instead of hardcoded values. -- **Code readability:** Prioritize code readability and maintainability over shortness or cleverness. diff --git a/config/config.ini b/config/config.ini index e5989a0..ab1b3e7 100644 --- a/config/config.ini +++ b/config/config.ini @@ -1,6 +1,6 @@ startView = 1 ; LOGO = 0, MENU = 1, GAMEPLAY = 2, SETTINGS = 3 -windowTitle = The Last Pirate +windowTitle = Sinbad windowWidth = 1280 ; in Pixel windowHeight = 720 ; in Pixel diff --git a/include/app.h b/include/app.h index f7fa9a3..06cbea5 100644 --- a/include/app.h +++ b/include/app.h @@ -147,11 +147,13 @@ typedef struct { Physics physics; } Islands; -#define MAX_PROJECTILES 10 +#define MAX_PROJECTILES 100 typedef struct { + int count; Physics physics[MAX_PROJECTILES]; bool active[MAX_PROJECTILES]; float radius[MAX_PROJECTILES]; + Color color[MAX_PROJECTILES]; } Projectiles; typedef struct { diff --git a/src/appGame.c b/src/appGame.c index 0c25625..15ba635 100644 --- a/src/appGame.c +++ b/src/appGame.c @@ -68,6 +68,7 @@ void UpdateGame(App *app) { UpdateBirds(&g->birds); UpdateEnemies(&g->enemies); UpdateIslands(&g->islands); + UpdateProjectiles(&g->projectiles); } void RenderComponents(App *app) { @@ -77,6 +78,7 @@ void RenderComponents(App *app) { RenderEnemies(&g->enemies); RenderBirds(&g->birds); RenderIslands(&g->islands); + RenderProjectiles(&g->projectiles); } void RenderGame(App *app) { diff --git a/src/appGameEnemies.c b/src/appGameEnemies.c index ec52555..91c436b 100644 --- a/src/appGameEnemies.c +++ b/src/appGameEnemies.c @@ -1,90 +1,81 @@ #include "app.h" - - const TextureAsset enemiesTextureAssets[ENEMIES_TEX_COUNT] = { - {"assets/ship_start.png", 16.0f, 16.0f, 90.0f} -}; + {"assets/ship_start.png", 16.0f, 16.0f, 90.0f}}; -Enemies CreateEnemies(void){ - Enemies enemies = {.count = MAX_ENEMIES}; - TextureAsset textureAsset = enemiesTextureAssets[BOAT]; - Texture2D texture = LoadTexture(textureAsset.path); - float frameWidth = textureAsset.frameWidth; - float rotation = textureAsset.rotation; +Enemies CreateEnemies(void) { + Enemies enemies = {.count = MAX_ENEMIES}; + TextureAsset textureAsset = enemiesTextureAssets[BOAT]; + Texture2D texture = LoadTexture(textureAsset.path); + float frameWidth = textureAsset.frameWidth; + float rotation = textureAsset.rotation; - for (int i = 0; i < enemies.count; i++) - { - enemies.sprite[i] = (Sprite){ - .texture = texture, - .frameSize = {frameWidth, frameWidth}, - .sourceRec = {0.0f, 0.0f, frameWidth, frameWidth}, - .destRec = {GetScreenWidth()/2, 0.0f, frameWidth, frameWidth}, - .origin = {frameWidth / 2, frameWidth / 2}, - .rotation = rotation, - .color = WHITE - }; + for (int i = 0; i < enemies.count; i++) { + enemies.sprite[i] = (Sprite){ + .texture = texture, + .frameSize = {frameWidth, frameWidth}, + .sourceRec = {0.0f, 0.0f, frameWidth, frameWidth}, + .destRec = {GetScreenWidth() / 2, 0.0f, frameWidth, frameWidth}, + .origin = {frameWidth / 2, frameWidth / 2}, + .rotation = rotation, + .color = WHITE}; - enemies.animation[i] = (Animation){ - .state = 1, - .currentFrame = 0, - .maxFrame = 2, - .framesCounter = 0, - .framesSpeed = 2.0f, - .animTimer = 0.0f - }; + enemies.animation[i] = (Animation){.state = 1, + .currentFrame = 0, + .maxFrame = 2, + .framesCounter = 0, + .framesSpeed = 2.0f, + .animTimer = 0.0f}; - Rectangle cameraRec = GetCameraRectangle(); + Rectangle cameraRec = GetCameraRectangle(); - enemies.physics[i] = (Physics){ - .position = GetPositionOutsideRectangle(cameraRec, 100, 1000), - .direction = (Vector2){0.0f, 0.0f}, - .speed = 5.0f - }; + enemies.physics[i] = + (Physics){.position = GetPositionOutsideRectangle(cameraRec, 100, 1000), + .direction = (Vector2){0.0f, 0.0f}, + .speed = 5.0f}; - enemies.arrived[i] = true; - enemies.destPos[i] = (Vector2){0.0f, 0.0f}; + enemies.arrived[i] = true; + enemies.destPos[i] = (Vector2){0.0f, 0.0f}; + } - } - - return enemies; + return enemies; } -void UpdateEnemies(Enemies *enemies){ - Camera2D *camera = GetCamera(); - Rectangle cameraRec = GetCameraRectangle(); +void UpdateEnemies(Enemies *enemies) { + Camera2D *camera = GetCamera(); + Rectangle cameraRec = GetCameraRectangle(); - for (int i = 0; i < enemies->count; i++) - { - if(enemies->arrived[i]) - { - enemies->destPos[i] = GetPositionOutsideRectangle(cameraRec, 100, 1000); - enemies->arrived[i] = false; - } - if(CheckCollisionPointCircle(enemies->physics[i].position, enemies->destPos[i], 10.0F)) - { - enemies->arrived[i] = true; - } - if(GetDistanceBetweenTwoVectors(enemies->physics[i].position, camera->target) > 1000){ - enemies->physics[i].position = GetPositionOutsideRectangle(cameraRec, 100, 1000); - } - Vector2 dir = GetDirectionBetweenTwoVectors(enemies->physics[i].position, enemies->destPos[i]); - UpdatePhysics(&enemies->physics[i], dir); - UpdateSpriteDestRec(&enemies->sprite[i], &enemies->physics[i].position); - float rotation = Vector2ToRotation(dir); - UpdateSpriteRotation(&enemies->sprite[i], rotation + 90.0f); - UpdateAnimation(&enemies->animation[i], GetFrameTime()); - UpdateSpriteSourceRec(&enemies->sprite[i], &(Vector2){enemies->sprite[i].frameSize.x * enemies->animation[i].currentFrame, enemies->sprite[i].frameSize.y}); - } + for (int i = 0; i < enemies->count; i++) { + if (enemies->arrived[i]) { + enemies->destPos[i] = GetPositionOutsideRectangle(cameraRec, 100, 1000); + enemies->arrived[i] = false; + } + if (CheckCollisionPointCircle(enemies->physics[i].position, + enemies->destPos[i], 10.0F)) { + enemies->arrived[i] = true; + } + if (GetDistanceBetweenTwoVectors(enemies->physics[i].position, + camera->target) > 1000) { + enemies->physics[i].position = + GetPositionOutsideRectangle(cameraRec, 100, 1000); + } + Vector2 dir = GetDirectionBetweenTwoVectors(enemies->physics[i].position, + enemies->destPos[i]); + UpdatePhysics(&enemies->physics[i], dir); + UpdateSpriteDestRec(&enemies->sprite[i], &enemies->physics[i].position); + float rotation = Vector2ToRotation(dir); + UpdateSpriteRotation(&enemies->sprite[i], rotation + 90.0f); + UpdateAnimation(&enemies->animation[i], GetFrameTime()); + UpdateSpriteSourceRec(&enemies->sprite[i], + &(Vector2){enemies->sprite[i].frameSize.x * + enemies->animation[i].currentFrame, + enemies->sprite[i].frameSize.y}); + } } -void RenderEnemies(Enemies *enemies){ - - for (int i = 0; i < enemies->count; i++) - { - RenderSprite(&enemies->sprite[i]); - } +void RenderEnemies(Enemies *enemies) { + for (int i = 0; i < enemies->count; i++) { + RenderSprite(&enemies->sprite[i]); + } } - - diff --git a/src/appGameProjectiles.c b/src/appGameProjectiles.c index c202aac..c71b472 100644 --- a/src/appGameProjectiles.c +++ b/src/appGameProjectiles.c @@ -1,7 +1,71 @@ #include "app.h" +#include +#include -Projectiles CreateProjectiles(void) {} +Projectiles CreateProjectiles(void) { + Projectiles projectiles = {.count = MAX_PROJECTILES}; -void UpdateProjectiles(Projectiles *projectiles) {} + for (int i = 0; i < projectiles.count; i++) { + projectiles.physics[i] = + (Physics){(Vector2){0.0f, 0.0f}, (Vector2){0.0f, 0.0f}, + (Vector2){0.0f, 0.0f}, 50.0f}; + projectiles.radius[i] = 1.0f; + projectiles.active[i] = false; + projectiles.color[i] = GRAY; + } -void RenderProjectiles(Projectiles *projectiles) {} + return projectiles; +} + +void UpdateProjectiles(Projectiles *projectiles) { + + static float lastShotTime = 0.0f; + const float reloadTime = 1.0f; + float currentTime = GetTime(); + + if (IsKeyDown(KEY_Q) && (currentTime - lastShotTime >= reloadTime)) { + for (int i = 0; i < projectiles->count; i++) { + if (!projectiles->active[i]) { + projectiles->active[i] = true; + Player *player = GetPlayer(); + projectiles->physics[i].position = player->physics.position; + projectiles->physics[i].direction = + Vector2Rotate(player->physics.direction, -90.0f * DEG2RAD); + lastShotTime = currentTime; + break; + } + } + } + + if (IsKeyDown(KEY_E) && (currentTime - lastShotTime >= reloadTime)) { + for (int i = 0; i < projectiles->count; i++) { + if (!projectiles->active[i]) { + projectiles->active[i] = true; + Player *player = GetPlayer(); + projectiles->physics[i].position = player->physics.position; + projectiles->physics[i].direction = + Vector2Rotate(player->physics.direction, 90.0f * DEG2RAD); + lastShotTime = currentTime; + break; + } + } + } + + for (int i = 0; i < projectiles->count; i++) { + if (projectiles->active[i]) { + UpdatePhysics(&projectiles->physics[i], + projectiles->physics[i].direction); + } + } +} + +void RenderProjectiles(Projectiles *projectiles) { + for (int i = 0; i < projectiles->count; i++) { + printf("Projectile Active: %d", projectiles->active[i]); + if (projectiles->active[i] == true) { + DrawCircle(projectiles->physics[i].position.x, + projectiles->physics[i].position.y, projectiles->radius[i], + projectiles->color[i]); + } + } +}