Add origin point to sprites, WASD controls camera, debug draw rects, todo list

This commit is contained in:
Joseph Ferano 2024-01-01 16:38:41 +07:00
parent 380361431f
commit ceca65fb46
4 changed files with 100 additions and 32 deletions

View File

@ -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];

4
lib.h
View File

@ -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;

83
main.c
View File

@ -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 {
@ -53,12 +57,12 @@ Assets Init() {
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();
{

21
tinyswords.todo Normal file
View File

@ -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