From 380361431f97633798036e0dc4430969166f8275 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Mon, 1 Jan 2024 13:01:35 +0700 Subject: [PATCH] Sprite anim looping, knight state management, attacking anim, direction flip --- game_data.h | 8 +++++ main.c | 101 ++++++++++++++++++++++++++++++++++------------------ sprites.c | 8 ++++- sprites.h | 8 +++-- 4 files changed, 86 insertions(+), 39 deletions(-) diff --git a/game_data.h b/game_data.h index da89716..eda31fb 100644 --- a/game_data.h +++ b/game_data.h @@ -20,48 +20,56 @@ const u16 cell_size = 192; SpriteAnimation knight_idle = { .name = "idle", .total_frames = 6, + .loop = true, .src_rect = { 0, cell_size * 0, 192, 192 }, }; SpriteAnimation knight_run = { .name = "run", .total_frames = 6, + .loop = true, .src_rect = { 0, cell_size * 1, 192, 192 }, }; SpriteAnimation knight_attack_side1 = { .name = "attack_side1", .total_frames = 6, + .loop = false, .src_rect = { 0, cell_size * 2, 192, 192 }, }; SpriteAnimation knight_attack_side2 = { .name = "attack_side2", .total_frames = 6, + .loop = false, .src_rect = { 0, cell_size * 3, 192, 192 }, }; SpriteAnimation knight_attack_front1 = { .name = "attack_front1", .total_frames = 6, + .loop = false, .src_rect = { 0, cell_size * 4, 192, 192 }, }; SpriteAnimation knight_attack_front2 = { .name = "attack_front2", .total_frames = 6, + .loop = false, .src_rect = { 0, cell_size * 5, 192, 192 }, }; SpriteAnimation knight_attack_back1 = { .name = "attack_back1", .total_frames = 6, + .loop = false, .src_rect = { 0, cell_size * 6, 192, 192 }, }; SpriteAnimation knight_attack_back2 = { .name = "attack_back2", .total_frames = 6, + .loop = false, .src_rect = { 0, cell_size * 7, 192, 192 }, }; diff --git a/main.c b/main.c index d759c31..dfbff27 100644 --- a/main.c +++ b/main.c @@ -12,11 +12,33 @@ #include "lib.h" #include "game_data.h" +typedef enum KnightState { + KNIGHT_IDLE = 0, + KNIGHT_RUNNING = 1, + KNIGHT_ATTACKING = 2, +} KnightState; + +typedef enum Direction { + DIR_UP = 0, + DIR_DOWN = 1, + DIR_LEFT = 2, + DIR_RIGHT = 3, + // DIR_UP_LEFT = 4, + // DIR_UP_RIGHT = 5, + // DIR_DOWN_LEFT = 6, + // DIR_DOWN_RIGHT = 7, +} Direction; + +typedef struct { + Vector2 position; + Vector2 velocity; + Direction look_dir; + KnightState state; +} Knight; + typedef struct { int frame_count; - int anim_frames; - bool is_attacking; - Vector2 knight_pos; + Knight knight; Rectangle *sprite_rects; SpriteAnimationPlayback *anim_playbacks; int anim_playbacks_count; @@ -44,10 +66,10 @@ Assets Init() { return assets; } -void Update(GameState *state, Camera2D cam, float dt) { +void Update(GameState *game, Camera2D cam, float dt) { (void)cam; - TickSpriteAnimations(&knight_anims[0], state->anim_playbacks, 1); + TickSpriteAnimations(&knight_anims[0], game->anim_playbacks, 1); float movement_speed = 250.0f * dt; Vector2 input_vel = {0}; @@ -63,29 +85,34 @@ void Update(GameState *state, Camera2D cam, float dt) { if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) { input_vel.y = 1; } - if (IsKeyPressed(KEY_SPACE)) { - state->is_attacking = true; + if (IsKeyPressed(KEY_SPACE) && game->knight.state != KNIGHT_ATTACKING) { + game->knight.state = KNIGHT_ATTACKING; + game->anim_playbacks[0].anim_id = ANIM_KNIGHT_ATTACK_SIDE1; + PlayAnimation(&game->anim_playbacks[0], game->anim_playbacks[0]); } - input_vel = Vector2Normalize(input_vel); - input_vel = Vector2Scale(input_vel, movement_speed); - state->knight_pos = Vector2Add(state->knight_pos, input_vel); - // if (state->is_attacking) { - // if (state->anim_frames - attacking_frames > 5) { - // state->is_attacking = false; - // state->knight_rect.y = 0; - // } else { - // state->knight_rect.y = 192 * 2; - // } - // } else { - if (input_vel.x != 0 || input_vel.y != 0) { - state->anim_playbacks[0].anim_id = ANIM_KNIGHT_RUN; - } else { - state->anim_playbacks[0].anim_id = ANIM_KNIGHT_IDLE; + if (game->knight.state == KNIGHT_ATTACKING) { + game->anim_playbacks[0].anim_id = ANIM_KNIGHT_ATTACK_SIDE1; + if (game->anim_playbacks[0].is_finished) { + game->knight.state = KNIGHT_IDLE; } - // } + } else { + if (input_vel.x != 0) { + game->knight.look_dir = input_vel.x == -1 ? DIR_LEFT : DIR_RIGHT; + } + game->knight.velocity = Vector2Normalize(input_vel); + game->knight.velocity = Vector2Scale(game->knight.velocity, movement_speed); + game->knight.position = Vector2Add(game->knight.position, game->knight.velocity); + if (input_vel.x != 0 || input_vel.y != 0) { + game->anim_playbacks[0].anim_id = ANIM_KNIGHT_RUN; + game->knight.state = KNIGHT_RUNNING; + } else { + game->anim_playbacks[0].anim_id = ANIM_KNIGHT_IDLE; + game->knight.state = KNIGHT_IDLE; + } + } } -void Draw(GameState *state, Assets assets, Camera2D cam, float dt) { +void Draw(GameState *game, Assets assets, Camera2D cam, float dt) { (void)cam; (void)dt; ClearBackground((Color){ 100, 149, 237, 255 }); @@ -112,13 +139,16 @@ void Draw(GameState *state, Assets assets, Camera2D cam, float dt) { DrawTextureRec(assets.textures[0], src_rect, pos, WHITE); } } - for (int i = 0; i < state->anim_playbacks_count; i++) { - SpriteAnimationPlayback *playback = &state->anim_playbacks[i]; + for (int i = 0; i < game->anim_playbacks_count; i++) { + SpriteAnimationPlayback *playback = &game->anim_playbacks[i]; SpriteAnimation *anim = &knight_anims[playback->anim_id]; Rectangle src_rect = anim->src_rect; src_rect.x = playback->current_frame * anim->src_rect.width; src_rect.y = anim->src_rect.y; - DrawTextureRec(assets.textures[1], src_rect, state->knight_pos, WHITE); + if (game->knight.look_dir == DIR_LEFT) { + src_rect.width = -abs((int)src_rect.width); + } + DrawTextureRec(assets.textures[1], src_rect, game->knight.position, WHITE); } } @@ -140,28 +170,29 @@ int main(void) { Camera2D cam = {0}; cam.zoom = 1.0f; - GameState state = {0}; - state.anim_playbacks = malloc(sizeof(SpriteAnimationPlayback) * MAX_ANIMATION_PLAYBACKS); - state.anim_playbacks_count = 1; + GameState game = {0}; + game.anim_playbacks = malloc(sizeof(SpriteAnimationPlayback) * MAX_ANIMATION_PLAYBACKS); + game.anim_playbacks_count = 1; // First one is idle - state.anim_playbacks[0] = (SpriteAnimationPlayback){0}; + game.anim_playbacks[0] = (SpriteAnimationPlayback){0}; + game.knight = (Knight){0}; // state.anim_playbacks[0].pos = (Position){ knight_idle.src_rect.x, knight_idle.src_rect.y }; Assets assets = Init(); - PlayAnimation(&state.anim_playbacks[0], state.anim_playbacks[0]); + PlayAnimation(&game.anim_playbacks[0], game.anim_playbacks[0]); // const int idle while (!WindowShouldClose()) { - state.frame_count++; + game.frame_count++; float dt = GetFrameTime(); - Update(&state, cam, dt); + Update(&game, cam, dt); BeginDrawing(); { BeginMode2D(cam); { - Draw(&state, assets, cam, dt); + Draw(&game, assets, cam, dt); } EndMode2D(); } diff --git a/sprites.c b/sprites.c index 8d230c0..951a3ac 100644 --- a/sprites.c +++ b/sprites.c @@ -4,6 +4,7 @@ void PlayAnimation(SpriteAnimationPlayback *playbacks, SpriteAnimationPlayback playback) { playback.time_elapsed = 0.0f; playback.current_frame = 0; + playback.is_finished = false; playbacks[0] = playback; } @@ -19,7 +20,12 @@ void TickSpriteAnimations(const SpriteAnimation *animations, playback->time_elapsed = 0.0f; playback->current_frame++; if (playback->current_frame >= animation->total_frames) { - playback->current_frame = 0; + if (animation->loop) { + playback->current_frame = 0; + } else { + playback->is_finished = true; + playback->current_frame--; + } } } } diff --git a/sprites.h b/sprites.h index 72b938f..cdd83f8 100644 --- a/sprites.h +++ b/sprites.h @@ -12,15 +12,17 @@ typedef struct { typedef struct { char* name; - u16 total_frames; + u8 total_frames; + bool loop; Rectangle src_rect; } SpriteAnimation; typedef struct { u16 anim_id; - u16 current_frame; + u8 current_frame; + bool is_finished; f32 time_elapsed; } SpriteAnimationPlayback; void PlayAnimation(SpriteAnimationPlayback *playbacks, SpriteAnimationPlayback playback); -void TickSpriteAnimations(const SpriteAnimation *animations, SpriteAnimationPlayback *playbacks, int len); \ No newline at end of file +void TickSpriteAnimations(const SpriteAnimation *animations, SpriteAnimationPlayback *playbacks, int len);