Tilemaps can have two objects placed on it, 'p_foreground' and 'p_vanishing' whose placement form a virtual perspective plane, which causes sprites to scale as they move up and down the screen between them, creating the illusion of depth on the screen
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
#ifndef _SDL_GAMECONTROLLERDB_H_
|
#ifndef _SDL_GAMECONTROLLERDB_H_
|
||||||
#define _SDL_GAMECONTROLLERDB_H_
|
#define _SDL_GAMECONTROLLERDB_H_
|
||||||
|
|
||||||
// Taken from https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt on Wed May 13 08:00:23 AM EDT 2026
|
// Taken from https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt on Wed May 13 09:55:53 AM EDT 2026
|
||||||
|
|
||||||
#define AKGL_SDL_GAMECONTROLLER_DB_LEN 2228
|
#define AKGL_SDL_GAMECONTROLLER_DB_LEN 2228
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ typedef struct akgl_Actor {
|
|||||||
SDL_Time logictimer;
|
SDL_Time logictimer;
|
||||||
float32_t x;
|
float32_t x;
|
||||||
float32_t y;
|
float32_t y;
|
||||||
|
float32_t scale;
|
||||||
struct akgl_Actor *children[AKGL_ACTOR_MAX_CHILDREN];
|
struct akgl_Actor *children[AKGL_ACTOR_MAX_CHILDREN];
|
||||||
struct akgl_Actor *parent;
|
struct akgl_Actor *parent;
|
||||||
akerr_ErrorContext AKERR_NOIGNORE *(*updatefunc)(struct akgl_Actor *obj);
|
akerr_ErrorContext AKERR_NOIGNORE *(*updatefunc)(struct akgl_Actor *obj);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ typedef struct {
|
|||||||
#define AKGL_ITERATOR_OP_RENDER 1 << 1 // 2
|
#define AKGL_ITERATOR_OP_RENDER 1 << 1 // 2
|
||||||
#define AKGL_ITERATOR_OP_RELEASE 1 << 2 // 4
|
#define AKGL_ITERATOR_OP_RELEASE 1 << 2 // 4
|
||||||
#define AKGL_ITERATOR_OP_LAYERMASK 1 << 3 // 8
|
#define AKGL_ITERATOR_OP_LAYERMASK 1 << 3 // 8
|
||||||
#define AKGL_ITERATOR_OP_UNDEFINED_4 1 << 4 // 16
|
#define AKGL_ITERATOR_OP_TILEMAPSCALE 1 << 4 // 16
|
||||||
#define AKGL_ITERATOR_OP_UNDEFINED_5 1 << 5 // 32
|
#define AKGL_ITERATOR_OP_UNDEFINED_5 1 << 5 // 32
|
||||||
#define AKGL_ITERATOR_OP_UNDEFINED_6 1 << 6 // 64
|
#define AKGL_ITERATOR_OP_UNDEFINED_6 1 << 6 // 64
|
||||||
#define AKGL_ITERATOR_OP_UNDEFINED_7 1 << 7 // 128
|
#define AKGL_ITERATOR_OP_UNDEFINED_7 1 << 7 // 128
|
||||||
|
|||||||
@@ -87,6 +87,12 @@ typedef struct {
|
|||||||
int numlayers;
|
int numlayers;
|
||||||
int orientation; // 0 = orthogonal, 1 = isometric
|
int orientation; // 0 = orthogonal, 1 = isometric
|
||||||
int numtilesets;
|
int numtilesets;
|
||||||
|
int p_foreground_y;
|
||||||
|
int p_vanishing_y;
|
||||||
|
int p_foreground_h;
|
||||||
|
int p_vanishing_h;
|
||||||
|
float p_scale;
|
||||||
|
float p_rate;
|
||||||
akgl_Tileset tilesets[AKGL_TILEMAP_MAX_TILESETS];
|
akgl_Tileset tilesets[AKGL_TILEMAP_MAX_TILESETS];
|
||||||
akgl_TilemapLayer layers[AKGL_TILEMAP_MAX_LAYERS];
|
akgl_TilemapLayer layers[AKGL_TILEMAP_MAX_LAYERS];
|
||||||
} akgl_Tilemap;
|
} akgl_Tilemap;
|
||||||
@@ -109,6 +115,6 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_layer_tile(akgl_Tilemap *de
|
|||||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_layers(akgl_Tilemap *dest, json_t *root);
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_layers(akgl_Tilemap *dest, json_t *root);
|
||||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_tilesets_each(json_t *tileset, akgl_Tilemap *dest, int tsidx);
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_tilesets_each(json_t *tileset, akgl_Tilemap *dest, int tsidx);
|
||||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_tilesets(akgl_Tilemap *dest, json_t *root);
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_tilesets(akgl_Tilemap *dest, json_t *root);
|
||||||
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_scale_actor(akgl_Tilemap *map, akgl_Actor *actor);
|
||||||
|
|
||||||
#endif //_TILEMAP_H_
|
#endif //_TILEMAP_H_
|
||||||
|
|||||||
@@ -254,8 +254,8 @@ akerr_ErrorContext *akgl_actor_render(akgl_Actor *obj, SDL_Renderer *renderer)
|
|||||||
dest.x = (obj->x - camera.x);
|
dest.x = (obj->x - camera.x);
|
||||||
dest.y = (obj->y - camera.y);
|
dest.y = (obj->y - camera.y);
|
||||||
}
|
}
|
||||||
dest.w = curSprite->width;
|
dest.w = curSprite->width * obj->scale;
|
||||||
dest.h = curSprite->width;
|
dest.h = curSprite->width * obj->scale;
|
||||||
|
|
||||||
SDL_RenderTexture(renderer, curSprite->sheet->texture, &src, &dest);
|
SDL_RenderTexture(renderer, curSprite->sheet->texture, &src, &dest);
|
||||||
SUCCEED_RETURN(errctx);
|
SUCCEED_RETURN(errctx);
|
||||||
@@ -300,6 +300,11 @@ void akgl_registry_iterate_actor(void *userdata, SDL_PropertiesID registry, cons
|
|||||||
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_UPDATE) ) {
|
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_UPDATE) ) {
|
||||||
CATCH(errctx, obj->updatefunc(obj));
|
CATCH(errctx, obj->updatefunc(obj));
|
||||||
}
|
}
|
||||||
|
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_TILEMAPSCALE) ) {
|
||||||
|
CATCH(errctx, akgl_tilemap_scale_actor(&gamemap, obj));
|
||||||
|
} else {
|
||||||
|
obj->scale = 1.0;
|
||||||
|
}
|
||||||
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_RENDER) ) {
|
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_RENDER) ) {
|
||||||
CATCH(errctx, obj->renderfunc(obj, renderer));
|
CATCH(errctx, obj->renderfunc(obj, renderer));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -277,7 +277,17 @@ akerr_ErrorContext *akgl_tilemap_load_layer_objects(akgl_Tilemap *dest, json_t *
|
|||||||
CATCH(errctx, akgl_get_json_string_value((json_t *)layerdatavalue, "type", &tmpstr));
|
CATCH(errctx, akgl_get_json_string_value((json_t *)layerdatavalue, "type", &tmpstr));
|
||||||
if ( strcmp(tmpstr->data, "actor") == 0 ) {
|
if ( strcmp(tmpstr->data, "actor") == 0 ) {
|
||||||
CATCH(errctx, akgl_tilemap_load_layer_object_actor(curobj, layerdatavalue, layerid));
|
CATCH(errctx, akgl_tilemap_load_layer_object_actor(curobj, layerdatavalue, layerid));
|
||||||
|
} else if ( strcmp(tmpstr->data, "perspective") == 0 ) {
|
||||||
|
curobj->visible = false;
|
||||||
|
if ( strcmp((char *)curobj->name, "p_foreground") == 0 ) {
|
||||||
|
dest->p_foreground_y = curobj->y;
|
||||||
|
CATCH(errctx, akgl_get_json_integer_value((json_t *)layerdatavalue, "height", &dest->p_foreground_h));
|
||||||
|
} else if ( strcmp((char *)curobj->name, "p_vanishing") == 0 ) {
|
||||||
|
dest->p_vanishing_y = curobj->y;
|
||||||
|
CATCH(errctx, akgl_get_json_integer_value((json_t *)layerdatavalue, "height", &dest->p_vanishing_h));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
layerdatavalue = NULL;
|
layerdatavalue = NULL;
|
||||||
}
|
}
|
||||||
} CLEANUP {
|
} CLEANUP {
|
||||||
@@ -436,6 +446,21 @@ akerr_ErrorContext *akgl_tilemap_load(char *fname, akgl_Tilemap *dest)
|
|||||||
|
|
||||||
CATCH(errctx, akgl_tilemap_load_layers((akgl_Tilemap *)dest, (json_t *)json));
|
CATCH(errctx, akgl_tilemap_load_layers((akgl_Tilemap *)dest, (json_t *)json));
|
||||||
CATCH(errctx, akgl_tilemap_load_tilesets((akgl_Tilemap *)dest, (json_t *)json));
|
CATCH(errctx, akgl_tilemap_load_tilesets((akgl_Tilemap *)dest, (json_t *)json));
|
||||||
|
|
||||||
|
if ( dest->p_foreground_y && dest->p_vanishing_y ) {
|
||||||
|
// How much bigger is the foreground vs the vanishing point?
|
||||||
|
// if vanishing is height 16, and foreground is height 32, that is a 2x scale difference
|
||||||
|
dest->p_scale = (dest->p_foreground_h / dest->p_vanishing_h);
|
||||||
|
SDL_Log("Map perspective scale is (%f/%f) = %f", dest->p_foreground_h, dest->p_vanishing_h, dest->p_scale);
|
||||||
|
// Sprites are always size 1.0 at the foreground, so how much do we need to
|
||||||
|
// scale them for every pixel above foreground_y before they reach vanishing_y?
|
||||||
|
// If vanishing is at 320 and foreground is at 640, that is a 320 line difference
|
||||||
|
// If our scaling rate is 2x, then our rate is ((1.0 - (1.0 / 2.0)) / 320.0), or
|
||||||
|
// 0.0015625% scale per pixel.
|
||||||
|
// At position 640,
|
||||||
|
dest->p_rate = (1.0 / (dest->p_foreground_y - dest->p_vanishing_y)) / dest->p_scale;
|
||||||
|
SDL_Log("Map perspective rate is %f", dest->p_rate);
|
||||||
|
}
|
||||||
} CLEANUP {
|
} CLEANUP {
|
||||||
//IGNORE(akgl_heap_release_string(tmpstr));
|
//IGNORE(akgl_heap_release_string(tmpstr));
|
||||||
} PROCESS(errctx) {
|
} PROCESS(errctx) {
|
||||||
@@ -613,3 +638,25 @@ akerr_ErrorContext *akgl_tilemap_draw_tileset(SDL_Renderer *renderer, akgl_Tilem
|
|||||||
}
|
}
|
||||||
SUCCEED_RETURN(errctx);
|
SUCCEED_RETURN(errctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_scale_actor(akgl_Tilemap *map, akgl_Actor *actor)
|
||||||
|
{
|
||||||
|
PREPARE_ERROR(e);
|
||||||
|
|
||||||
|
FAIL_ZERO_RETURN(e, map, AKERR_NULLPOINTER, "NULL map");
|
||||||
|
FAIL_ZERO_RETURN(e, actor, AKERR_NULLPOINTER, "NULL actor");
|
||||||
|
|
||||||
|
SDL_Log("Map foreground is at %d, vanishes at %d, actor %p is at %f",
|
||||||
|
map->p_foreground_y,
|
||||||
|
map->p_vanishing_y,
|
||||||
|
actor,
|
||||||
|
actor->y);
|
||||||
|
if ( actor->y <= map->p_vanishing_y ) {
|
||||||
|
actor->scale = 1.0 / map->p_scale;
|
||||||
|
} else if ( actor->y >= map->p_foreground_y ) {
|
||||||
|
actor->scale = 1.0;
|
||||||
|
} else {
|
||||||
|
actor->scale = 1.0 - (map->p_rate * (map->p_foreground_y - actor->y));
|
||||||
|
}
|
||||||
|
SDL_Log("Actor %p scaled to %f", actor, actor->scale);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user