Implement sprite rendering anchor

main
En Yi 2024-08-05 21:50:01 +08:00
parent 2dbc1f19ab
commit 657110a66d
6 changed files with 98 additions and 86 deletions

View File

@ -192,10 +192,25 @@ typedef struct Sprite {
} Sprite_t;
typedef unsigned int (*sprite_transition_func_t)(Entity_t *ent); // Transition requires knowledge of the entity
typedef enum AnchorPoint {
AP_TOP_LEFT,
AP_TOP_CENTER,
AP_TOP_RIGHT,
AP_MID_LEFT,
AP_MID_CENTER,
AP_MID_RIGHT,
AP_BOT_LEFT,
AP_BOT_CENTER,
AP_BOT_RIGHT,
} AnchorPoint_t;
typedef struct _SpriteRenderInfo
{
Sprite_t* sprite;
Vector2 offset;
Vector2 src_anchor;
AnchorPoint_t dest_anchor;
} SpriteRenderInfo_t;
typedef struct _CSprite_t {

View File

@ -1,6 +1,7 @@
#include "assets.h"
#include "assert.h"
#include "engine_conf.h"
#include "raymath.h"
#define RRES_RAYLIB_IMPLEMENTATION
#include "rres.h"
@ -551,15 +552,20 @@ void draw_sprite_pro(Sprite_t* spr, int frame_num, Vector2 pos, float rotation,
spr->frame_size.x * ((flip & 1) ? -1 : 1),
spr->frame_size.y * ((flip & 2) ? -1 : 1),
};
Rectangle dest = {
.x = pos.x,
.y = pos.y,
.width = spr->frame_size.x * scale.x,
.height = spr->frame_size.y * scale.y
};
// The anchor here is only for rotation and scaling.
// Translational anchor is expected to be accounted for
// So need to offset render position with anchor position
Vector2 anchor = spr->anchor;
anchor.x *= scale.x;
anchor.y *= scale.y;
Rectangle dest = {
.x = pos.x + anchor.x,
.y = pos.y + anchor.y,
.width = spr->frame_size.x * scale.x,
.height = spr->frame_size.y * scale.y
};
DrawTexturePro(
*spr->texture,
rec,
@ -568,3 +574,54 @@ void draw_sprite_pro(Sprite_t* spr, int frame_num, Vector2 pos, float rotation,
rotation, colour
);
}
Vector2 shift_bbox(Vector2 bbox, Vector2 new_bbox, AnchorPoint_t anchor)
{
Vector2 p1 = get_anchor_offset(bbox, anchor);
Vector2 p2 = get_anchor_offset(new_bbox, anchor);
return Vector2Subtract(p1, p2);
}
Vector2 get_anchor_offset(Vector2 bbox, AnchorPoint_t anchor)
{
Vector2 offset = {0};
switch (anchor)
{
case AP_TOP_LEFT:
break;
case AP_TOP_CENTER:
offset.x = bbox.x / 2;
break;
case AP_TOP_RIGHT:
offset.x = bbox.x;
break;
case AP_MID_LEFT:
offset.x = 0;
offset.y = bbox.y / 2;
break;
case AP_MID_CENTER:
offset.x = bbox.x / 2;
offset.y = bbox.y / 2;
break;
case AP_MID_RIGHT:
offset.x = bbox.x;
offset.y = bbox.y / 2;
break;
case AP_BOT_LEFT:
offset.x = 0;
offset.y = bbox.y;
break;
case AP_BOT_CENTER:
offset.x = bbox.x / 2;
offset.y = bbox.y;
break;
case AP_BOT_RIGHT:
offset.x = bbox.x;
offset.y = bbox.y;
break;
}
return offset;
}

View File

@ -83,6 +83,8 @@ LevelPack_t* get_level_pack(Assets_t* assets, const char* name);
void draw_sprite(Sprite_t* spr, int frame_num, Vector2 pos, float rotation, bool flip_x);
void draw_sprite_pro(Sprite_t* spr, int frame_num, Vector2 pos, float rotation, uint8_t flip, Vector2 scale, Color colour);
Vector2 get_anchor_offset(Vector2 bbox, AnchorPoint_t anchor);
Vector2 shift_bbox(Vector2 bbox, Vector2 new_bbox, AnchorPoint_t anchor);
typedef struct SFX
{

View File

@ -220,6 +220,7 @@ static void render_editor_game_scene(Scene_t* scene)
int y = tile_y * TILE_SIZE;
//if (!tilemap.tiles[i].moveable)
//{
// // Draw water tile
@ -432,7 +433,17 @@ static void render_editor_game_scene(Scene_t* scene)
const SpriteRenderInfo_t spr = p_cspr->sprites[p_cspr->current_idx];
if (spr.sprite != NULL)
{
Vector2 pos = Vector2Add(p_ent->position, spr.offset);
Vector2 pos = p_ent->position;
if (p_bbox != NULL)
{
pos = Vector2Add(
pos,
get_anchor_offset(p_bbox->size, spr.dest_anchor)
);
pos = Vector2Subtract(pos, spr.src_anchor);
}
pos = Vector2Add(pos, spr.offset);
draw_sprite(spr.sprite, p_cspr->current_frame, pos, 0.0f, p_cspr->flip_x);
}
}

View File

@ -12,17 +12,6 @@ bool check_in_water(const ParticleEmitter_t* emitter, float delta_time);
static const Vector2 GRAVITY = {0, GRAV_ACCEL};
static const Vector2 UPTHRUST = {0, -GRAV_ACCEL * 1.1};
typedef enum AnchorPoint {
AP_TOP_LEFT,
AP_TOP_CENTER,
AP_TOP_RIGHT,
AP_MID_LEFT,
AP_MID_CENTER,
AP_MID_RIGHT,
AP_BOT_LEFT,
AP_BOT_CENTER,
AP_BOT_RIGHT,
} AnchorPoint_t;
static inline unsigned int get_tile_idx(int x, int y, TileGrid_t gridmap)
{
@ -160,73 +149,6 @@ collision_end:
return overlap_mode > 0;
}
static Vector2 shift_bbox(Vector2 bbox, Vector2 new_bbox, AnchorPoint_t anchor)
{
Vector2 p1;
Vector2 p2;
Vector2 offset = {0};
switch (anchor)
{
case AP_TOP_LEFT:
// When resizing bbox, it is implicitly assumed that to be already in topleft
// due to the coordindate system (+ve towards right and downwards)
// So do nothing
return offset;
case AP_TOP_CENTER:
p1.x = bbox.x / 2;
p1.y = 0;
p2.x = new_bbox.x / 2;
p2.y = 0;
break;
case AP_TOP_RIGHT:
p1.x = bbox.x;
p1.y = 0;
p2.x = new_bbox.x;
p2.y = 0;
break;
case AP_MID_LEFT:
p1.x = 0;
p1.y = bbox.y / 2;
p2.x = 0;
p2.y = new_bbox.y / 2;
break;
case AP_MID_CENTER:
p1.x = bbox.x / 2;
p1.y = bbox.y / 2;
p2.x = new_bbox.x / 2;
p2.y = new_bbox.y / 2;
break;
case AP_MID_RIGHT:
p1.x = bbox.x;
p1.y = bbox.y / 2;
p2.x = new_bbox.x;
p2.y = new_bbox.y / 2;
break;
case AP_BOT_LEFT:
p1.x = 0;
p1.y = bbox.y;
p2.x = 0;
p2.y = new_bbox.y;
break;
case AP_BOT_CENTER:
p1.x = bbox.x / 2;
p1.y = bbox.y;
p2.x = new_bbox.x / 2;
p2.y = new_bbox.y;
break;
case AP_BOT_RIGHT:
p1.x = bbox.x;
p1.y = bbox.y;
p2.x = new_bbox.x;
p2.y = new_bbox.y;
break;
}
offset.x = p1.x - p2.x;
offset.y = p1.y - p2.y;
return offset;
}
void destroy_entity(Scene_t* scene, TileGrid_t* tilemap, Entity_t* p_ent)
{
Vector2 half_size = {0,0};

View File

@ -172,8 +172,13 @@ static bool init_player_file(FILE* in_file, Assets_t* assets)
return false;
}
Sprite_t* spr = get_sprite(assets, name);
spr->anchor = Vector2Scale(spr->frame_size, 0.5f);
player_sprite_map[i].sprite = spr;
player_sprite_map[i].offset = offset;
//player_sprite_map[i].offset = offset;
player_sprite_map[i].offset = (Vector2){0};
player_sprite_map[i].src_anchor = spr->frame_size;
player_sprite_map[i].src_anchor.x /= 2.0f;
player_sprite_map[i].dest_anchor = AP_BOT_CENTER;
i++;
}
already_init = true;