mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
rendering: drive Run/Stand animations from actual movement state
CameraController now transitions the player character to Run (anim 4) on movement start and back to Stand (anim 0) on stop, guarded by a prevPlayerMoving_ flag so animation time is not reset every frame. Death animation (anim 1) is never overridden. Application creature sync similarly switches creature models to Run (4) when they move between server positions and Stand (0) when they stop, with per-guid creatureWasMoving_ tracking to avoid per-frame resets.
This commit is contained in:
parent
c8d9d6b792
commit
4e137c4061
4 changed files with 37 additions and 2 deletions
|
|
@ -187,6 +187,7 @@ private:
|
|||
std::unordered_map<uint64_t, uint32_t> creatureInstances_; // guid → render instanceId
|
||||
std::unordered_map<uint64_t, uint32_t> creatureModelIds_; // guid → loaded modelId
|
||||
std::unordered_map<uint64_t, glm::vec3> creatureRenderPosCache_; // guid -> last synced render position
|
||||
std::unordered_map<uint64_t, bool> creatureWasMoving_; // guid -> previous-frame movement state
|
||||
std::unordered_set<uint64_t> creatureWeaponsAttached_; // guid set when NPC virtual weapons attached
|
||||
std::unordered_map<uint64_t, uint8_t> creatureWeaponAttachAttempts_; // guid -> attach attempts
|
||||
std::unordered_map<uint32_t, bool> modelIdIsWolfLike_; // modelId → cached wolf/worg check
|
||||
|
|
|
|||
|
|
@ -226,6 +226,9 @@ private:
|
|||
bool autoRunning = false;
|
||||
bool tildeWasDown = false;
|
||||
|
||||
// Movement animation state tracking
|
||||
bool prevPlayerMoving_ = false;
|
||||
|
||||
// Movement state tracking (for sending opcodes on state change)
|
||||
bool wasMovingForward = false;
|
||||
bool wasMovingBackward = false;
|
||||
|
|
|
|||
|
|
@ -749,6 +749,7 @@ void Application::logoutToLogin() {
|
|||
creatureRenderPosCache_.clear();
|
||||
creatureWeaponsAttached_.clear();
|
||||
creatureWeaponAttachAttempts_.clear();
|
||||
creatureWasMoving_.clear();
|
||||
deadCreatureGuids_.clear();
|
||||
nonRenderableCreatureDisplayIds_.clear();
|
||||
creaturePermanentFailureGuids_.clear();
|
||||
|
|
@ -1466,14 +1467,28 @@ void Application::update(float deltaTime) {
|
|||
auto unitPtr = std::static_pointer_cast<game::Unit>(entity);
|
||||
const bool deadOrCorpse = unitPtr->getHealth() == 0;
|
||||
const bool largeCorrection = (planarDist > 6.0f) || (dz > 3.0f);
|
||||
const bool isMovingNow = !deadOrCorpse && (planarDist > 0.03f || dz > 0.08f);
|
||||
if (deadOrCorpse || largeCorrection) {
|
||||
charRenderer->setInstancePosition(instanceId, renderPos);
|
||||
} else if (planarDist > 0.03f || dz > 0.08f) {
|
||||
// Use movement interpolation so step/run animation can play.
|
||||
} else if (isMovingNow) {
|
||||
float duration = std::clamp(planarDist / 5.5f, 0.05f, 0.22f);
|
||||
charRenderer->moveInstanceTo(instanceId, renderPos, duration);
|
||||
}
|
||||
posIt->second = renderPos;
|
||||
|
||||
// Drive movement animation: Run (4) when moving, Stand (0) when idle.
|
||||
// Only switch on transitions to avoid resetting animation time.
|
||||
// Don't override Death (1) animation.
|
||||
bool prevMoving = creatureWasMoving_[guid];
|
||||
if (isMovingNow != prevMoving) {
|
||||
creatureWasMoving_[guid] = isMovingNow;
|
||||
uint32_t curAnimId = 0; float curT = 0.0f, curDur = 0.0f;
|
||||
bool gotState = charRenderer->getAnimationState(instanceId, curAnimId, curT, curDur);
|
||||
if (!gotState || curAnimId != 1 /*Death*/) {
|
||||
charRenderer->playAnimation(instanceId,
|
||||
isMovingNow ? 4u : 0u, /*loop=*/true);
|
||||
}
|
||||
}
|
||||
}
|
||||
float renderYaw = entity->getOrientation() + glm::radians(90.0f);
|
||||
charRenderer->setInstanceRotation(instanceId, glm::vec3(0.0f, 0.0f, renderYaw));
|
||||
|
|
@ -8449,6 +8464,7 @@ void Application::despawnOnlineCreature(uint64_t guid) {
|
|||
creatureRenderPosCache_.erase(guid);
|
||||
creatureWeaponsAttached_.erase(guid);
|
||||
creatureWeaponAttachAttempts_.erase(guid);
|
||||
creatureWasMoving_.erase(guid);
|
||||
|
||||
LOG_DEBUG("Despawned creature: guid=0x", std::hex, guid, std::dec);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1445,6 +1445,21 @@ void CameraController::update(float deltaTime) {
|
|||
// Honor first-person intent even if anti-clipping pushes camera back slightly.
|
||||
bool shouldHidePlayer = isFirstPersonView() || (actualDist < MIN_DISTANCE + 0.1f);
|
||||
characterRenderer->setInstanceVisible(playerInstanceId, !shouldHidePlayer);
|
||||
|
||||
// Drive movement animation: Run (4) when moving, Stand (0) when idle.
|
||||
// Only transition on state changes to avoid resetting animation time every frame.
|
||||
// Skip if current animation is Death (1) — death pose must persist.
|
||||
bool nowMoving = isMoving();
|
||||
if (nowMoving != prevPlayerMoving_) {
|
||||
prevPlayerMoving_ = nowMoving;
|
||||
uint32_t curAnimId = 0; float curT = 0.0f, curDur = 0.0f;
|
||||
bool gotState = characterRenderer->getAnimationState(
|
||||
playerInstanceId, curAnimId, curT, curDur);
|
||||
if (!gotState || curAnimId != 1 /*Death*/) {
|
||||
characterRenderer->playAnimation(playerInstanceId,
|
||||
nowMoving ? 4u : 0u, /*loop=*/true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Free-fly camera mode (original behavior)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue