From ceca65fb46809796b915cd07876fe7575cc24295 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Mon, 1 Jan 2024 16:38:41 +0700 Subject: [PATCH] Add origin point to sprites, WASD controls camera, debug draw rects, todo list --- game_data.h | 20 +++++++----- lib.h | 4 +-- main.c | 87 +++++++++++++++++++++++++++++++++++++------------ tinyswords.todo | 21 ++++++++++++ 4 files changed, 100 insertions(+), 32 deletions(-) create mode 100644 tinyswords.todo diff --git a/game_data.h b/game_data.h index eda31fb..a1f7fc1 100644 --- a/game_data.h +++ b/game_data.h @@ -9,6 +9,7 @@ #define ANIM_KNIGHT_ATTACK_BACK1 6 #define ANIM_KNIGHT_ATTACK_BACK2 7 +const u16 cell_size = 192; SpriteSheet knight = { .name = "blue_knight", .texture = {0}, @@ -16,61 +17,62 @@ SpriteSheet knight = { .size = { 1152, 1536 }, }; -const u16 cell_size = 192; +const Vector2 knight_origin = {cell_size / 2, cell_size / 2}; + SpriteAnimation knight_idle = { .name = "idle", .total_frames = 6, .loop = true, - .src_rect = { 0, cell_size * 0, 192, 192 }, + .src_rect = { 0, cell_size * 0, cell_size, cell_size }, }; SpriteAnimation knight_run = { .name = "run", .total_frames = 6, .loop = true, - .src_rect = { 0, cell_size * 1, 192, 192 }, + .src_rect = { 0, cell_size * 1, cell_size, cell_size }, }; SpriteAnimation knight_attack_side1 = { .name = "attack_side1", .total_frames = 6, .loop = false, - .src_rect = { 0, cell_size * 2, 192, 192 }, + .src_rect = { 0, cell_size * 2, cell_size, cell_size }, }; SpriteAnimation knight_attack_side2 = { .name = "attack_side2", .total_frames = 6, .loop = false, - .src_rect = { 0, cell_size * 3, 192, 192 }, + .src_rect = { 0, cell_size * 3, cell_size, cell_size }, }; SpriteAnimation knight_attack_front1 = { .name = "attack_front1", .total_frames = 6, .loop = false, - .src_rect = { 0, cell_size * 4, 192, 192 }, + .src_rect = { 0, cell_size * 4, cell_size, cell_size }, }; SpriteAnimation knight_attack_front2 = { .name = "attack_front2", .total_frames = 6, .loop = false, - .src_rect = { 0, cell_size * 5, 192, 192 }, + .src_rect = { 0, cell_size * 5, cell_size, cell_size }, }; SpriteAnimation knight_attack_back1 = { .name = "attack_back1", .total_frames = 6, .loop = false, - .src_rect = { 0, cell_size * 6, 192, 192 }, + .src_rect = { 0, cell_size * 6, cell_size, cell_size }, }; SpriteAnimation knight_attack_back2 = { .name = "attack_back2", .total_frames = 6, .loop = false, - .src_rect = { 0, cell_size * 7, 192, 192 }, + .src_rect = { 0, cell_size * 7, cell_size, cell_size }, }; SpriteAnimation knight_anims[8]; diff --git a/lib.h b/lib.h index f326b3e..48ab81e 100644 --- a/lib.h +++ b/lib.h @@ -18,7 +18,7 @@ typedef char byte; typedef ptrdiff_t size; typedef size_t usize; -typedef Vector2 Position; +typedef Vector2 Point; typedef struct Size { float width; @@ -26,7 +26,7 @@ typedef struct Size { } Size; typedef struct Rect { - Position position; + Point position; Size size; } Rect; diff --git a/main.c b/main.c index dfbff27..bace31e 100644 --- a/main.c +++ b/main.c @@ -9,9 +9,10 @@ #define MAX_ANIMATION_PLAYBACKS 64 #include "sprites.h" -#include "lib.h" #include "game_data.h" +#define DEBUG_MODE_ENABLED + typedef enum KnightState { KNIGHT_IDLE = 0, KNIGHT_RUNNING = 1, @@ -30,7 +31,8 @@ typedef enum Direction { } Direction; typedef struct { - Vector2 position; + Point position; + Point origin; Vector2 velocity; Direction look_dir; KnightState state; @@ -39,9 +41,11 @@ typedef struct { typedef struct { int frame_count; Knight knight; - Rectangle *sprite_rects; - SpriteAnimationPlayback *anim_playbacks; + // Rectangle* sprite_rects; + Point camera_position; + SpriteAnimationPlayback* anim_playbacks; int anim_playbacks_count; + bool debug_mode; } GameState; typedef struct { @@ -49,16 +53,16 @@ typedef struct { } Assets; Assets Init() { - knight_anims[ANIM_KNIGHT_IDLE] = knight_idle; - knight_anims[ANIM_KNIGHT_RUN] = knight_run; + knight_anims[ANIM_KNIGHT_IDLE] = knight_idle; + knight_anims[ANIM_KNIGHT_RUN] = knight_run; knight_anims[ANIM_KNIGHT_ATTACK_SIDE1] = knight_attack_side1; knight_anims[ANIM_KNIGHT_ATTACK_SIDE2] = knight_attack_side2; - knight_anims[ANIM_KNIGHT_ATTACK_TOP1 ] = knight_attack_front1; - knight_anims[ANIM_KNIGHT_ATTACK_TOP2 ] = knight_attack_front2; + knight_anims[ANIM_KNIGHT_ATTACK_TOP1] = knight_attack_front1; + knight_anims[ANIM_KNIGHT_ATTACK_TOP2] = knight_attack_front2; knight_anims[ANIM_KNIGHT_ATTACK_BACK1] = knight_attack_back1; knight_anims[ANIM_KNIGHT_ATTACK_BACK2] = knight_attack_back2; - Assets assets = { 0 }; + Assets assets = {0}; assets.textures = malloc(sizeof(Texture2D) * TEXTURES_BUF_SIZE); assets.textures[0] = LoadTexture("assets/Terrain/Ground/Tilemap_Flat.png"); assets.textures[1] = @@ -66,30 +70,49 @@ Assets Init() { return assets; } -void Update(GameState *game, Camera2D cam, float dt) { - (void)cam; +void Update(GameState *game, Camera2D *cam, float dt) { TickSpriteAnimations(&knight_anims[0], game->anim_playbacks, 1); - float movement_speed = 250.0f * dt; + const float movement_speed = 250.0f * dt; Vector2 input_vel = {0}; - if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) { + if (IsKeyDown(KEY_RIGHT)) { input_vel.x = 1; } - if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) { + if (IsKeyDown(KEY_LEFT)) { input_vel.x = -1; } - if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) { + if (IsKeyDown(KEY_UP)) { input_vel.y = -1; } - if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) { + if (IsKeyDown(KEY_DOWN)) { input_vel.y = 1; } + const float cam_move_speed = 1050.0f * dt; + Vector2 cam_vel = {0}; + if (IsKeyDown(KEY_D)) { + cam_vel.x = -1; + } + if (IsKeyDown(KEY_A)) { + cam_vel.x = 1; + } + if (IsKeyDown(KEY_W)) { + cam_vel.y = 1; + } + if (IsKeyDown(KEY_S)) { + cam_vel.y = -1; + } + cam_vel = Vector2Normalize(cam_vel); + game->camera_position = Vector2Scale(cam_vel, cam_move_speed); + cam->offset = Vector2Add(cam->offset, game->camera_position); 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]); } + if (IsKeyPressed(KEY_F1)) { + game->debug_mode = !game->debug_mode; + } if (game->knight.state == KNIGHT_ATTACKING) { game->anim_playbacks[0].anim_id = ANIM_KNIGHT_ATTACK_SIDE1; if (game->anim_playbacks[0].is_finished) { @@ -112,10 +135,10 @@ void Update(GameState *game, Camera2D cam, float dt) { } } -void Draw(GameState *game, Assets assets, Camera2D cam, float dt) { +void Draw(const GameState *game, Assets assets, Camera2D cam, float dt) { (void)cam; (void)dt; - ClearBackground((Color){ 100, 149, 237, 255 }); + ClearBackground((Color){100, 149, 237, 255}); int size = 32; int topx = 300; @@ -137,6 +160,17 @@ void Draw(GameState *game, Assets assets, Camera2D cam, float dt) { Vector2 pos = {32 * col + topx, 32 * row + topy}; Rectangle src_rect = {32 * atlas_col, 32 * atlas_row, 32, 32}; DrawTextureRec(assets.textures[0], src_rect, pos, WHITE); +#ifdef DEBUG_MODE_ENABLED + if (game->debug_mode) { + Rectangle debug_frame = { + pos.x, + pos.y, + src_rect.width, + src_rect.height, + }; + DrawRectangleLinesEx(debug_frame, 0.5f, RED); + } +#endif } } for (int i = 0; i < game->anim_playbacks_count; i++) { @@ -148,7 +182,19 @@ void Draw(GameState *game, Assets assets, Camera2D cam, float dt) { 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); + Vector2 pos = Vector2Subtract(game->knight.position, knight_origin); + DrawTextureRec(assets.textures[1], src_rect, pos, WHITE); +#ifdef DEBUG_MODE_ENABLED + if (game->debug_mode) { + Rectangle debug_frame = { + pos.x, + pos.y, + anim->src_rect.width, + anim->src_rect.height, + }; + DrawRectangleLinesEx(debug_frame, 2.0f, RED); + } +#endif } } @@ -176,7 +222,6 @@ int main(void) { // First one is idle 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(); @@ -186,7 +231,7 @@ int main(void) { game.frame_count++; float dt = GetFrameTime(); - Update(&game, cam, dt); + Update(&game, &cam, dt); BeginDrawing(); { diff --git a/tinyswords.todo b/tinyswords.todo new file mode 100644 index 0000000..2b5feb1 --- /dev/null +++ b/tinyswords.todo @@ -0,0 +1,21 @@ +#-*- mode: org -*- +#+TODO: TODO(t) INPROGRESS(i) BUG(b) | DONE(d) +#+STARTUP: show2levels + +* DONE Import assets and draw a sprite to the world +* DONE Layout a basic map with tiles +* DONE Extract Init/Update/Draw to own functions with state in a struct +* DONE Knight idle animation +* DONE Configure Makefile to handle deps and updates +* DONE Knight state to handle attacking +* DONE Animation flipping +* DONE Debug mode to show sprite boundaries +* DONE Sprite position needs to be set to the center +* DONE Movement keys to move the camera +* TODO Left click on knight to select, right click to move +* TODO Handle multiple knights on the map at the same time +* TODO Ability to attack an entity, like a dummy +* TODO State to handle attacking when you right click a target +* TODO Select multiple units and make them all move +* TODO Flocking/Steering behaviors so many knights move in formation +* TODO Steering behavior so knights surround a target with spacing