From 87d07175058ee4ae18fce608de81c68d7d9bb178 Mon Sep 17 00:00:00 2001 From: BoredGuy Date: Tue, 26 Aug 2025 12:33:32 +0300 Subject: Player Improvements --- src/assets.c | 21 +++++++++++ src/game.c | 42 ++++++++++++++++++++++ src/main.c | 6 ++-- src/player.c | 111 +++++++++++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 151 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/assets.c b/src/assets.c index b08201a..f6d4792 100644 --- a/src/assets.c +++ b/src/assets.c @@ -19,6 +19,11 @@ Asset assets[] = { .type = Texture_Asset, .name = "human-shadow", .filePath = "assets/art/characters/shadow.png" + }, + { + .type = Texture_Asset, + .name = "player-body", + .filePath = "assets/art/characters/player.png" } }; @@ -32,6 +37,11 @@ void LoadAssets() { switch (c->type) { case Texture_Asset: c->texture = LoadTexture(c->filePath); + + if (c->texture.id == 0) { + TraceLog(LOG_ERROR, "Failed to load texture %s, exitting!", c->filePath); + exit(EXIT_FAILURE); + } break; default: @@ -51,6 +61,17 @@ Asset* GetMatchingAssetWithType(const char* targetName, AssetType targetType) { return NULL; } +Asset* GetMatchingAssetExitOnFail(const char* targetName, AssetType targetType) { + Asset* matchingAsset = GetMatchingAssetWithType(targetName, targetType); + + if (!matchingAsset) { + TraceLog(LOG_ERROR, "Failed to load asset %s, exitting!", targetName); + exit(EXIT_FAILURE); + } + + return matchingAsset; +} + void UnloadAssets() { for (size_t i = 0; i < ASSET_COUNT; i++) { Asset* c = &assets[i]; diff --git a/src/game.c b/src/game.c index 4a10830..d6e8ce3 100644 --- a/src/game.c +++ b/src/game.c @@ -87,6 +87,12 @@ void DrawEntitySprite(const Entity* e, int spriteIndex) { float rotation = 0.0f; Rectangle destRect = GetSpriteDrawDestinationRectGlobal(e, spriteIndex); + if (drawnSprite->flipX) + srcRect.width = -srcRect.width; + + if (drawnSprite->flipY) + srcRect.height = -srcRect.width; + DrawTexturePro(drawnSprite->texture, srcRect, destRect, origin, rotation, WHITE); } @@ -193,3 +199,39 @@ void UpdateCurrentSpriteAnimation(Sprite* sprite, float dt) { } } } + +Rectangle GetSrcRectFromIndex(Texture texture, int framesX, int framesY, int index) { + const float frameWidth = (float)texture.width / framesX; + const float frameHeight = (float)texture.height / framesY; + + return (Rectangle) { + .x = (index % framesY) * frameWidth, + .y = (index / framesY) * frameHeight, + .width = frameWidth, + .height = frameHeight + }; +} + +Animation AnimationFromIndices(AnimationFromIndicesParams params) { + int numFrames = params.numFrames; + bool isLooping = params.isLooping; + Texture texture = params.texture; + int framesX = params.framesX; + int framesY = params.framesY; + int* indices = params.indices; + float* frameTimes = params.frameTimes; + + Animation animation = (Animation) { + .numFrames = numFrames, + .isLooping = isLooping, + + .currentFrame = 0 + }; + + for (int i = 0; i < numFrames; i++) { + animation.srcRects[i] = GetSrcRectFromIndex(texture, framesX, framesY, indices[i]); + animation.frameTimes[i] = frameTimes[i]; + } + + return animation; +} diff --git a/src/main.c b/src/main.c index 317b51c..f5be59f 100644 --- a/src/main.c +++ b/src/main.c @@ -7,14 +7,14 @@ int main() { InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "My BeatEmup"); - SetTargetFPS(60); + SetTargetFPS(120); LoadAssets(); InitGame(); AddBackground("bar-background"); - AddPlayer(0, 0); - AddWall(100, 100, 1000, 100); + AddPlayer(0, 400); + AddWall(0, 160, 1000000, 100); while(!WindowShouldClose()) { UpdateGame(GetFrameTime()); diff --git a/src/player.c b/src/player.c index 9340ffd..ca5d3c0 100644 --- a/src/player.c +++ b/src/player.c @@ -3,27 +3,22 @@ #include "constants.h" #include "game.h" #include "player.h" +#include "player_data.h" #include "physics.h" #include "assets.h" #include "utils.h" extern Game game; -#define PLAYER_SPEED 300.0f - -const Rectangle shadowDestRect = (Rectangle) { - .x = 0, - .y = 100, - .width = 100, - .height = 40 -}; +static void AddPlayerSprites(Entity* player); +static inline Sprite* GetBodySprite(Entity* player) { + return &player->sprites[player->bodySpriteIndex]; +} -const Rectangle physicsCollider = (Rectangle) { - .x = 0, - .y = 0, - .width = 100, - .height = 100 -}; +typedef enum PlayerStates { + PLAYER_IDLE = 0, + PLAYER_WALKING = 1, +} PlayerStates; Vector2 GetMovementDirection() { Vector2 movementDirection = {0.0f, 0.0f}; @@ -51,13 +46,33 @@ void CameraFollow(const Entity* player) { (Vector2) {fmaxf(WINDOW_WIDTH / 2.0f, player->position.x), 0.0f}; } +void UpdateAnimationState(Entity* player) { + Sprite* bodySprite = GetBodySprite(player); + + if (Vector2Length(player->velocity) > 0.0) + bodySprite->currentAnimation = PLAYER_WALKING; + else + bodySprite->currentAnimation = PLAYER_IDLE; +} + +void UpdateBodyFacing(Entity* player) { + Sprite* bodySprite = GetBodySprite(player); + + if (player->velocity.x < 0) + bodySprite->flipX = true; + else if (player->velocity.x > 0) + bodySprite->flipX = false; +} + void UpdatePlayer(Entity* player, float deltaTime) { player->velocity = Vector2Scale(GetMovementDirection(), PLAYER_SPEED); + UpdateAnimationState(player); + UpdateBodyFacing(player); MoveAndSlide(player, deltaTime); - CameraFollow(player); + UpdateCurrentSpriteAnimation(GetBodySprite(player), deltaTime); } void AddPlayer(float xpos, float ypos) { @@ -73,18 +88,62 @@ void AddPlayer(float xpos, float ypos) { player.physicsColliderColor = RED; #endif - Asset* shadowTexture = GetMatchingAssetWithType("human-shadow", Texture_Asset); + AddPlayerSprites(&player); + AddEntity(&player); +} - if (shadowTexture == NULL) { - TraceLog(LOG_ERROR, "Failed to find texture asset human-shadow, exitting!"); - exit(EXIT_FAILURE); - } +static void AddPlayerSprites(Entity* player) { + Asset* shadowTexture = GetMatchingAssetExitOnFail("human-shadow", Texture_Asset); - AddSpriteToEntity(&player, (Sprite){ - .texture = shadowTexture->texture, - .layer = Foreground_Layer, - .destRect = shadowDestRect - }); + Sprite shadowSprite = (Sprite) { + .texture = shadowTexture->texture, + .layer = Foreground_Layer, + .destRect = shadowDestRect, - AddEntity(&player); + .numAnimations = 0, //Not an animated sprite + }; + AddSpriteToEntity(player, shadowSprite); + + Asset* bodyTexture = GetMatchingAssetExitOnFail("player-body", Texture_Asset); + + Sprite bodySprite = (Sprite) { + .texture = bodyTexture->texture, + .layer = Foreground_Layer, + + .destRect = bodyDestRect, + .numAnimations = 0 + }; + + //The body texture devided into a 10x10 grid + //with one cell representing a frame of animation + Animation idleAnimation = + AnimationFromIndices((AnimationFromIndicesParams){ + .texture = bodyTexture->texture, + .isLooping = true, + .numFrames = 4, + + .framesX = 10, + .framesY = 10, + + .indices = (int[]) {0, 1, 2, 3}, + .frameTimes = (float[]) {0.1f, 0.1f, 0.1f, 0.1f} + }); + bodySprite.animations[PLAYER_IDLE] = idleAnimation; + + Animation walkingAnimation = + AnimationFromIndices((AnimationFromIndicesParams){ + .texture = bodyTexture->texture, + .isLooping = true, + .numFrames = 7, + + .framesX = 10, + .framesY = 10, + + .indices = (int[]) {10, 11, 12, 13, 14, 15, 16, 17}, + .frameTimes = (float[]) {0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f} + }); + bodySprite.animations[PLAYER_WALKING] = walkingAnimation; + + bodySprite.numAnimations = 2; + player->bodySpriteIndex = AddSpriteToEntity(player, bodySprite); } -- cgit v1.2.3