diff options
author | BoredGuy <osome3717@gmail.com> | 2025-08-26 12:33:32 +0300 |
---|---|---|
committer | BoredGuy <osome3717@gmail.com> | 2025-08-26 12:33:32 +0300 |
commit | 87d07175058ee4ae18fce608de81c68d7d9bb178 (patch) | |
tree | 1eb459ff40aded29f6433bcd413d47ff870fd4e0 | |
parent | 978c543891af8dbe9e95b27c4e2c46645d45138c (diff) |
Player Improvements
-rw-r--r-- | include/assets.h | 1 | ||||
-rw-r--r-- | include/game.h | 28 | ||||
-rw-r--r-- | include/player_data.h | 31 | ||||
-rw-r--r-- | include/utils.h | 4 | ||||
-rw-r--r-- | src/assets.c | 21 | ||||
-rw-r--r-- | src/game.c | 42 | ||||
-rw-r--r-- | src/main.c | 6 | ||||
-rw-r--r-- | src/player.c | 111 |
8 files changed, 214 insertions, 30 deletions
diff --git a/include/assets.h b/include/assets.h index 61b198e..6761d51 100644 --- a/include/assets.h +++ b/include/assets.h @@ -16,4 +16,5 @@ typedef struct Asset { void LoadAssets(); Asset* GetMatchingAssetWithType(const char* targetName, AssetType targetType); +Asset* GetMatchingAssetExitOnFail(const char* targetName, AssetType targetType); void UnloadAssets(); diff --git a/include/game.h b/include/game.h index ec44b3e..99529bf 100644 --- a/include/game.h +++ b/include/game.h @@ -37,6 +37,9 @@ typedef struct Sprite { DrawLayer layer; Rectangle destRect; //Destination rectangle relative to player position + bool flipX; + bool flipY; + int numAnimations; //Zero for static spritesx Animation animations[MAX_ANIMATIONS]; int currentAnimation; @@ -64,6 +67,9 @@ typedef struct Entity { //Debug information Color physicsColliderColor; #endif + + //Human entity information + int bodySpriteIndex; } Entity; typedef struct Game { @@ -77,15 +83,37 @@ typedef struct Game { #endif } Game; +//Entity Stuff void AddEntity(Entity* e); void AddWall(float xpos, float ypos, float width, float height); +//Game Stuff void InitGame(); void UpdateGame(float deltaTime); void DrawGame(); +//Sprite Stuff void UpdateCurrentSpriteAnimation(Sprite* sprite, float dt); void DrawEntitySprite(const Entity* e, int spriteIndex); +Rectangle GetSrcRectFromIndex +( + Texture texture, + int framesX, + int framesY, + int index +); + +typedef struct { + Texture texture; + int framesX; + int framesY; + int numFrames; + bool isLooping; + int* indices; + float* frameTimes; +} AnimationFromIndicesParams; + +Animation AnimationFromIndices(AnimationFromIndicesParams params); #ifdef BEATEMUP_DEBUG void DebugHighlights(const Entity* e); diff --git a/include/player_data.h b/include/player_data.h new file mode 100644 index 0000000..d9d45a1 --- /dev/null +++ b/include/player_data.h @@ -0,0 +1,31 @@ +#ifndef PLAYER_DATA_H_ +#define PLAYER_DATA_H_ + +#include "game.h" + +#define PLAYER_SPEED 300.0f + +const Rectangle shadowDestRect = (Rectangle) { + .x = -30, + .y = 100, + .width = 140, + .height = 40 +}; + +const Rectangle physicsCollider = (Rectangle) { + .x = NO_OFFSET, + .y = NO_OFFSET, + .width = 100, + .height = 100 +}; + +const Rectangle bodyDestRect = (Rectangle) { + .x = -160, + .y = -280, + .width = 400, + .height = 400 +}; + +#define IDLE_FTIME 0.1f + +#endif // PLAYER_DATA_H_ diff --git a/include/utils.h b/include/utils.h index 0ba8c32..3381828 100644 --- a/include/utils.h +++ b/include/utils.h @@ -16,10 +16,12 @@ static inline bool SameEntity(const Entity* a, const Entity* b) { return a->id == b->id; } -static inline void AddSpriteToEntity(Entity* e, Sprite s) { +static inline int AddSpriteToEntity(Entity* e, Sprite s) { if (e->numSprites < MAX_SPRITE_COUNT) { e->sprites[e->numSprites++] = s; } + + return e->numSprites - 1; } static inline bool IsAnimated(const Sprite* s) { 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]; @@ -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; +} @@ -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); } |