summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoredGuy <osome3717@gmail.com>2025-08-26 12:33:32 +0300
committerBoredGuy <osome3717@gmail.com>2025-08-26 12:33:32 +0300
commit87d07175058ee4ae18fce608de81c68d7d9bb178 (patch)
tree1eb459ff40aded29f6433bcd413d47ff870fd4e0
parent978c543891af8dbe9e95b27c4e2c46645d45138c (diff)
Player Improvements
-rw-r--r--include/assets.h1
-rw-r--r--include/game.h28
-rw-r--r--include/player_data.h31
-rw-r--r--include/utils.h4
-rw-r--r--src/assets.c21
-rw-r--r--src/game.c42
-rw-r--r--src/main.c6
-rw-r--r--src/player.c111
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];
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);
}