Add entity turn lockout

This commit is contained in:
2026-06-30 21:23:34 -05:00
parent 84ebaa0751
commit a34831aa02
8 changed files with 70 additions and 25 deletions
+7 -1
View File
@@ -113,6 +113,12 @@ errorret_t assetMeshLoaderSync(assetloading_t *loading) {
errorChain(ret);
}
#ifndef DUSK_OPENGL_LEGACY
// VBO owns the data now; CPU copy is no longer needed.
memoryFree(out->vertices);
out->vertices = NULL;
#endif
loading->entry->state = ASSET_ENTRY_STATE_LOADED;
errorOk();
}
@@ -125,7 +131,7 @@ errorret_t assetMeshDispose(assetentry_t *entry) {
assetmeshoutput_t *out = &entry->data.mesh;
if(out->vertices != NULL) {
errorChain(meshDispose(&out->mesh));
// memoryFree(out->vertices);
memoryFree(out->vertices);
out->vertices = NULL;
}
errorOk();
+11
View File
@@ -9,6 +9,7 @@
#include "rpg/overworld/map.h"
#include "rpg/overworld/tile.h"
#include "time/time.h"
#include "entityanimwalk.h"
const entityanimcallback_t ENTITY_ANIM_CALLBACKS[ENTITY_ANIM_COUNT] = {
[ENTITY_ANIM_IDLE] = { entityAnimIdleUpdate },
@@ -25,9 +26,19 @@ void entityAnimUpdate(entity_t *entity) {
if(entity->animation != ENTITY_ANIM_IDLE) {
entity->animTime -= TIME.delta;
if(entity->animTime <= 0) {
if(
entity->animation == ENTITY_ANIM_WALK ||
entity->animation == ENTITY_ANIM_RUN
) {
entity->walkEndCooldown = ENTITY_ANIM_WALK_TURN_COOLDOWN;
}
entity->animation = ENTITY_ANIM_IDLE;
entity->animTime = 0;
}
}
if(entity->walkEndCooldown > 0) {
entity->walkEndCooldown -= TIME.delta;
if(entity->walkEndCooldown < 0) entity->walkEndCooldown = 0;
}
ENTITY_ANIM_CALLBACKS[entity->animation].update(entity);
}
+1 -1
View File
@@ -11,7 +11,7 @@
typedef struct entity_s entity_t;
#define ENTITY_ANIM_TURN_DURATION TIME_TICKS_TO_TIME(2)
#define ENTITY_ANIM_TURN_DURATION TIME_TICKS_TO_TIME(4)
/**
* Updates render position for the turn animation state.
+2 -1
View File
@@ -11,7 +11,8 @@
typedef struct entity_s entity_t;
#define ENTITY_ANIM_WALK_DURATION TIME_TICKS_TO_TIME(10)
#define ENTITY_ANIM_WALK_DURATION TIME_TICKS_TO_TIME(12)
#define ENTITY_ANIM_WALK_TURN_COOLDOWN TIME_TICKS_TO_TIME(4)
/**
* Updates render position for the walk animation state.
+2 -1
View File
@@ -52,7 +52,8 @@ void entityUpdate(entity_t *entity) {
}
bool_t entityCanTurn(entity_t *entity) {
return entity->animation == ENTITY_ANIM_IDLE;
return entity->animation == ENTITY_ANIM_IDLE &&
entity->walkEndCooldown <= 0;
}
bool_t entityCanWalk(entity_t *entity) {
+1
View File
@@ -27,6 +27,7 @@ typedef struct entity_s {
entityanim_t animation;
float_t animTime;
float_t walkEndCooldown;
entityinteract_t interact;
+37 -20
View File
@@ -17,6 +17,10 @@ void playerInit(entity_t *entity) {
assertNotNull(entity, "Entity pointer cannot be NULL");
}
bool_t playerCanInteract(entity_t *entity) {
return entity->animation == ENTITY_ANIM_IDLE;
}
void playerInput(entity_t *entity) {
assertNotNull(entity, "Entity pointer cannot be NULL");
@@ -33,37 +37,51 @@ void playerInput(entity_t *entity) {
// Can player act?
if(UI_FOCUS.count > 0) return;
// Turn - only if not already holding the direction we face
const playerinputdirmap_t *dirMap = PLAYER_INPUT_DIR_MAP;
bool_t holdingFaced = false;
// Determine direction player may be trying to face/go.
const playerinputdirmap_t *dirMap;
// First pass, we want to prefer a button relative to what the player is
// already facing, e.g. if they hold DOWN and start moving down, then tap
// right we want to prefer down over right.
// Determine current dirmap based on facing direction.
dirMap = PLAYER_INPUT_DIR_MAP;
do {
if(!inputIsDown(dirMap->action)) continue;
if(entity->direction != dirMap->direction) continue;
holdingFaced = true;
if(dirMap->direction != entity->direction) continue;
break;
} while((++dirMap)->action != 0xFF);
if(!holdingFaced) {
// Are we holding that button?
if(!inputIsDown(dirMap->action)) {
// No, so we need to check all directions.
dirMap = PLAYER_INPUT_DIR_MAP;
do {
if(!inputIsDown(dirMap->action)) continue;
if(entity->direction == dirMap->direction) continue;
return entityTurn(entity, dirMap->direction);
break;
} while((++dirMap)->action != 0xFF);
}
// Walk / Run
bool_t running = inputIsDown(INPUT_ACTION_CANCEL);
dirMap = PLAYER_INPUT_DIR_MAP;
do {
if(!inputIsDown(dirMap->action)) continue;
if(entity->direction != dirMap->direction) continue;
if(running) return entityRun(entity, dirMap->direction);
return entityWalk(entity, dirMap->direction);
} while((++dirMap)->action != 0xFF);
// Trying to direct?
if(dirMap->action != 0xFF) {
// Is the player attempting to turn? That is, is the player idle and has the
// turn lockout passed?
if(entityCanTurn(entity)) {
if(entity->direction != dirMap->direction) {
entityTurn(entity, dirMap->direction);
return;
}
}
bool_t running = inputIsDown(INPUT_ACTION_CANCEL);
if(running && entityCanRun(entity)) {
entityRun(entity, dirMap->direction);
} else if(entityCanWalk(entity)) {
entityWalk(entity, dirMap->direction);
}
}
// Interaction
if(inputPressed(INPUT_ACTION_ACCEPT)) {
if(inputPressed(INPUT_ACTION_ACCEPT) && playerCanInteract(entity)) {
worldunit_t x, y, z;
{
worldunits_t relX, relY;
@@ -77,5 +95,4 @@ void playerInput(entity_t *entity) {
if(target == NULL) return;
entityInteractWith(entity, target);
}
}
+9 -1
View File
@@ -35,9 +35,17 @@ static const playerinputdirmap_t PLAYER_INPUT_DIR_MAP[] = {
*/
void playerInit(entity_t *entity);
/**
* Returns true if the player entity is in a state where it can interact.
*
* @param entity Pointer to the player entity to check.
* @returns True if the entity can interact.
*/
bool_t playerCanInteract(entity_t *entity);
/**
* Handles movement logic for the player entity.
*
*
* @param entity Pointer to the player entity structure.
*/
void playerInput(entity_t *entity);