More rendering subsystem breakout, added a physics subsystem, everything now fires from akgl_game_update() for the user

This commit is contained in:
2026-05-25 21:29:18 -04:00
parent 6314ad7f26
commit d87c5d2c20
13 changed files with 276 additions and 176 deletions

View File

@@ -3,6 +3,7 @@
#include <string.h>
#include <akerror.h>
#include <akgl/physics.h>
#include <akgl/game.h>
#include <akgl/sprite.h>
#include <akgl/actor.h>
@@ -112,27 +113,13 @@ akerr_ErrorContext *akgl_actor_logic_changeframe(akgl_Actor *obj, akgl_Sprite *c
SUCCEED_RETURN(errctx);
}
// raises AKGL_ERR_LOGICINTERRUPT if we don't want the physics object to process us
akerr_ErrorContext *akgl_actor_logic_movement(akgl_Actor *obj, SDL_Time curtime)
{
PREPARE_ERROR(errctx);
FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "Null actor reference");
if ( obj->parent != NULL ) {
// Children don't move independently of their parents, they just have an offset
SUCCEED_RETURN(errctx);
} else {
if ( AKGL_BITMASK_HAS(obj->state, AKGL_ACTOR_STATE_MOVING_LEFT) ) {
obj->x -= obj->basechar->vx;
}
if ( AKGL_BITMASK_HAS(obj->state, AKGL_ACTOR_STATE_MOVING_RIGHT) ) {
obj->x += obj->basechar->vx;
}
if ( AKGL_BITMASK_HAS(obj->state, AKGL_ACTOR_STATE_MOVING_UP) ) {
obj->y -= obj->basechar->vy;
}
if ( AKGL_BITMASK_HAS(obj->state, AKGL_ACTOR_STATE_MOVING_DOWN) ) {
obj->y += obj->basechar->vy;
}
}
// Effectively a NOOP, this is handled by the physics engine now
// These functions are still present in case the library user wants per-actor behavior
SUCCEED_RETURN(errctx);
}
@@ -145,21 +132,11 @@ akerr_ErrorContext *akgl_actor_update(akgl_Actor *obj)
FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "NULL actor reference");
FAIL_ZERO_RETURN(errctx, obj->basechar, AKERR_NULLPOINTER, "Actor has NULL base character reference");
ATTEMPT {
SDL_GetCurrentTime(&curtime);
CATCH(errctx, obj->facefunc(obj));
// is it time to apply movement logic?
if ( (curtime - obj->logictimer) >= obj->basechar->movementspeed ) {
CATCH(errctx, obj->movementlogicfunc(obj, curtime));
obj->logictimer = curtime;
}
} CLEANUP {
} PROCESS(errctx) {
} FINISH(errctx, false);
SDL_GetCurrentTime(&curtime);
PASS(errctx, obj->facefunc(obj));
ATTEMPT {
CATCH(errctx, akgl_character_sprite_get(obj->basechar, obj->state, &curSprite));
// is it time to change frames?
if ( ((curtime) - obj->curSpriteFrameTimer) >= curSprite->speed) {
CATCH(errctx, obj->changeframefunc(obj, curSprite, curtime));
obj->curSpriteFrameTimer = curtime;
@@ -167,6 +144,8 @@ akerr_ErrorContext *akgl_actor_update(akgl_Actor *obj)
} CLEANUP {
} PROCESS(errctx) {
} HANDLE(errctx, AKERR_KEY) {
// TODO : Why are we passing this error? It could only come from akgl_character_sprite_get
// or changeframefunc, both of which should never return AKERR_KEY...
SUCCEED_RETURN(errctx);
} FINISH(errctx, true);
@@ -227,7 +206,7 @@ akerr_ErrorContext *akgl_actor_render(akgl_Actor *obj)
if ( ! visible ) {
SUCCEED_RETURN(errctx);
}
if ( (obj->curSpriteFrameId > curSprite->frames) ) {
// This isn't necessarily an error - this actor's frame index is outside the range of
// their current sprite. There are a number of reasons this could happen, and it will
@@ -279,39 +258,6 @@ akerr_ErrorContext *akgl_actor_add_child(akgl_Actor *obj, akgl_Actor *child)
FAIL_RETURN(errctx, AKERR_OUTOFBOUNDS, "Parent object has no remaining child slots left");
}
// SDL iterator so we can't return error information here, void only
// this means we don't have anywhere to send exceptions up to, so if we hit an error, we log and exit(1) here
void akgl_registry_iterate_actor(void *userdata, SDL_PropertiesID registry, const char *name)
{
PREPARE_ERROR(errctx);
akgl_Iterator *opflags = (akgl_Iterator *)userdata;
ATTEMPT {
FAIL_ZERO_BREAK(errctx, name, AKERR_NULLPOINTER, "registry_iterate_actor received NULL property name");
FAIL_ZERO_BREAK(errctx, opflags, AKERR_NULLPOINTER, "received NULL iterator flags");
akgl_Actor *obj = (akgl_Actor *)SDL_GetPointerProperty(registry, name, NULL);
FAIL_ZERO_BREAK(errctx, obj, AKERR_KEY, "registry_iterate_actor received property name that was not in the registry");
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_LAYERMASK) ) {
if ( obj->layer != opflags->layerid ) {
break;
}
}
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_UPDATE) ) {
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) ) {
CATCH(errctx, obj->renderfunc(obj));
}
} CLEANUP {
} PROCESS(errctx) {
} FINISH_NORETURN(errctx);
}
akerr_ErrorContext AKERR_NOIGNORE *akgl_Actor_cmhf_left_on(akgl_Actor *obj, SDL_Event *event)
{
PREPARE_ERROR(errctx);