mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Add intent-driven strafe animation selection and movement state hooks
This commit is contained in:
parent
871172d63e
commit
dfc29cad10
5 changed files with 105 additions and 18 deletions
|
|
@ -42,6 +42,10 @@ public:
|
|||
bool isJumping() const { return !grounded && verticalVelocity > 0.0f; }
|
||||
bool isFalling() const { return !grounded && verticalVelocity <= 0.0f; }
|
||||
bool isSprinting() const;
|
||||
bool isMovingForward() const { return moveForwardActive; }
|
||||
bool isMovingBackward() const { return moveBackwardActive; }
|
||||
bool isStrafingLeft() const { return strafeLeftActive; }
|
||||
bool isStrafingRight() const { return strafeRightActive; }
|
||||
bool isRightMouseHeld() const { return rightMouseDown; }
|
||||
bool isSitting() const { return sitting; }
|
||||
bool isSwimming() const { return swimming; }
|
||||
|
|
@ -136,6 +140,10 @@ private:
|
|||
bool wasTurningRight = false;
|
||||
bool wasJumping = false;
|
||||
bool wasFalling = false;
|
||||
bool moveForwardActive = false;
|
||||
bool moveBackwardActive = false;
|
||||
bool strafeLeftActive = false;
|
||||
bool strafeRightActive = false;
|
||||
|
||||
// Movement callback
|
||||
MovementCallback movementCallback;
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ public:
|
|||
void setInstanceVisible(uint32_t instanceId, bool visible);
|
||||
void removeInstance(uint32_t instanceId);
|
||||
bool getAnimationState(uint32_t instanceId, uint32_t& animationId, float& animationTimeMs, float& animationDurationMs) const;
|
||||
bool hasAnimation(uint32_t instanceId, uint32_t animationId) const;
|
||||
|
||||
/** Attach a weapon model to a character instance at the given attachment point. */
|
||||
bool attachWeapon(uint32_t charInstanceId, uint32_t attachmentId,
|
||||
|
|
|
|||
|
|
@ -752,6 +752,10 @@ void CameraController::update(float deltaTime) {
|
|||
wasMovingBackward = nowBackward;
|
||||
wasStrafingLeft = nowStrafeLeft;
|
||||
wasStrafingRight = nowStrafeRight;
|
||||
moveForwardActive = nowForward;
|
||||
moveBackwardActive = nowBackward;
|
||||
strafeLeftActive = nowStrafeLeft;
|
||||
strafeRightActive = nowStrafeRight;
|
||||
wasTurningLeft = nowTurnLeft;
|
||||
wasTurningRight = nowTurnRight;
|
||||
wasJumping = nowJump;
|
||||
|
|
@ -827,6 +831,10 @@ void CameraController::reset() {
|
|||
wasJumping = false;
|
||||
wasFalling = false;
|
||||
wasSwimming = false;
|
||||
moveForwardActive = false;
|
||||
moveBackwardActive = false;
|
||||
strafeLeftActive = false;
|
||||
strafeRightActive = false;
|
||||
|
||||
glm::vec3 spawnPos = defaultPosition;
|
||||
|
||||
|
|
|
|||
|
|
@ -1165,6 +1165,26 @@ bool CharacterRenderer::getAnimationState(uint32_t instanceId, uint32_t& animati
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CharacterRenderer::hasAnimation(uint32_t instanceId, uint32_t animationId) const {
|
||||
auto it = instances.find(instanceId);
|
||||
if (it == instances.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto modelIt = models.find(it->second.modelId);
|
||||
if (modelIt == models.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& sequences = modelIt->second.data.sequences;
|
||||
for (const auto& seq : sequences) {
|
||||
if (seq.id == animationId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CharacterRenderer::attachWeapon(uint32_t charInstanceId, uint32_t attachmentId,
|
||||
const pipeline::M2Model& weaponModel, uint32_t weaponModelId,
|
||||
const std::string& texturePath) {
|
||||
|
|
|
|||
|
|
@ -299,6 +299,12 @@ void Renderer::updateCharacterAnimation() {
|
|||
constexpr uint32_t ANIM_STAND = 0;
|
||||
constexpr uint32_t ANIM_WALK = 4;
|
||||
constexpr uint32_t ANIM_RUN = 5;
|
||||
// Candidate locomotion clips by common WotLK IDs.
|
||||
constexpr uint32_t ANIM_STRAFE_RUN_RIGHT = 92;
|
||||
constexpr uint32_t ANIM_STRAFE_RUN_LEFT = 93;
|
||||
constexpr uint32_t ANIM_STRAFE_WALK_LEFT = 11;
|
||||
constexpr uint32_t ANIM_STRAFE_WALK_RIGHT = 12;
|
||||
constexpr uint32_t ANIM_BACKPEDAL = 13;
|
||||
constexpr uint32_t ANIM_JUMP_START = 37;
|
||||
constexpr uint32_t ANIM_JUMP_MID = 38;
|
||||
constexpr uint32_t ANIM_JUMP_END = 39;
|
||||
|
|
@ -310,6 +316,11 @@ void Renderer::updateCharacterAnimation() {
|
|||
CharAnimState newState = charAnimState;
|
||||
|
||||
bool moving = cameraController->isMoving();
|
||||
bool movingBackward = cameraController->isMovingBackward();
|
||||
bool strafeLeft = cameraController->isStrafingLeft();
|
||||
bool strafeRight = cameraController->isStrafingRight();
|
||||
bool anyStrafeLeft = strafeLeft && !strafeRight;
|
||||
bool anyStrafeRight = strafeRight && !strafeLeft;
|
||||
bool grounded = cameraController->isGrounded();
|
||||
bool jumping = cameraController->isJumping();
|
||||
bool sprinting = cameraController->isSprinting();
|
||||
|
|
@ -442,24 +453,61 @@ void Renderer::updateCharacterAnimation() {
|
|||
|
||||
if (newState != charAnimState) {
|
||||
charAnimState = newState;
|
||||
}
|
||||
|
||||
uint32_t animId = ANIM_STAND;
|
||||
bool loop = true;
|
||||
|
||||
switch (charAnimState) {
|
||||
case CharAnimState::IDLE: animId = ANIM_STAND; loop = true; break;
|
||||
case CharAnimState::WALK: animId = ANIM_WALK; loop = true; break;
|
||||
case CharAnimState::RUN: animId = ANIM_RUN; loop = true; break;
|
||||
case CharAnimState::JUMP_START: animId = ANIM_JUMP_START; loop = false; break;
|
||||
case CharAnimState::JUMP_MID: animId = ANIM_JUMP_MID; loop = false; break;
|
||||
case CharAnimState::JUMP_END: animId = ANIM_JUMP_END; loop = false; break;
|
||||
case CharAnimState::SIT_DOWN: animId = ANIM_SIT_DOWN; loop = false; break;
|
||||
case CharAnimState::SITTING: animId = ANIM_SITTING; loop = true; break;
|
||||
case CharAnimState::EMOTE: animId = emoteAnimId; loop = emoteLoop; break;
|
||||
case CharAnimState::SWIM_IDLE: animId = ANIM_SWIM_IDLE; loop = true; break;
|
||||
case CharAnimState::SWIM: animId = ANIM_SWIM; loop = true; break;
|
||||
auto pickFirstAvailable = [&](std::initializer_list<uint32_t> candidates, uint32_t fallback) -> uint32_t {
|
||||
for (uint32_t id : candidates) {
|
||||
if (characterRenderer->hasAnimation(characterInstanceId, id)) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
};
|
||||
|
||||
uint32_t animId = ANIM_STAND;
|
||||
bool loop = true;
|
||||
|
||||
switch (charAnimState) {
|
||||
case CharAnimState::IDLE: animId = ANIM_STAND; loop = true; break;
|
||||
case CharAnimState::WALK:
|
||||
if (movingBackward) {
|
||||
animId = pickFirstAvailable({ANIM_BACKPEDAL}, ANIM_WALK);
|
||||
} else if (anyStrafeLeft) {
|
||||
animId = pickFirstAvailable({ANIM_STRAFE_WALK_LEFT, ANIM_STRAFE_RUN_LEFT}, ANIM_WALK);
|
||||
} else if (anyStrafeRight) {
|
||||
animId = pickFirstAvailable({ANIM_STRAFE_WALK_RIGHT, ANIM_STRAFE_RUN_RIGHT}, ANIM_WALK);
|
||||
} else {
|
||||
animId = ANIM_WALK;
|
||||
}
|
||||
loop = true;
|
||||
break;
|
||||
case CharAnimState::RUN:
|
||||
if (movingBackward) {
|
||||
animId = pickFirstAvailable({ANIM_BACKPEDAL}, ANIM_WALK);
|
||||
} else if (anyStrafeLeft) {
|
||||
animId = pickFirstAvailable({ANIM_STRAFE_RUN_LEFT}, ANIM_RUN);
|
||||
} else if (anyStrafeRight) {
|
||||
animId = pickFirstAvailable({ANIM_STRAFE_RUN_RIGHT}, ANIM_RUN);
|
||||
} else {
|
||||
animId = ANIM_RUN;
|
||||
}
|
||||
loop = true;
|
||||
break;
|
||||
case CharAnimState::JUMP_START: animId = ANIM_JUMP_START; loop = false; break;
|
||||
case CharAnimState::JUMP_MID: animId = ANIM_JUMP_MID; loop = false; break;
|
||||
case CharAnimState::JUMP_END: animId = ANIM_JUMP_END; loop = false; break;
|
||||
case CharAnimState::SIT_DOWN: animId = ANIM_SIT_DOWN; loop = false; break;
|
||||
case CharAnimState::SITTING: animId = ANIM_SITTING; loop = true; break;
|
||||
case CharAnimState::EMOTE: animId = emoteAnimId; loop = emoteLoop; break;
|
||||
case CharAnimState::SWIM_IDLE: animId = ANIM_SWIM_IDLE; loop = true; break;
|
||||
case CharAnimState::SWIM: animId = ANIM_SWIM; loop = true; break;
|
||||
}
|
||||
|
||||
uint32_t currentAnimId = 0;
|
||||
float currentAnimTimeMs = 0.0f;
|
||||
float currentAnimDurationMs = 0.0f;
|
||||
bool haveState = characterRenderer->getAnimationState(characterInstanceId, currentAnimId, currentAnimTimeMs, currentAnimDurationMs);
|
||||
if (!haveState || currentAnimId != animId) {
|
||||
characterRenderer->playAnimation(characterInstanceId, animId, loop);
|
||||
}
|
||||
}
|
||||
|
|
@ -600,9 +648,11 @@ void Renderer::update(float deltaTime) {
|
|||
if (characterInstanceId > 0 && characterRenderer && cameraController && cameraController->isThirdPerson()) {
|
||||
characterRenderer->setInstancePosition(characterInstanceId, characterPosition);
|
||||
|
||||
// Only rotate character to face camera direction when right-click is held
|
||||
// Left-click orbits camera without turning the character
|
||||
if (cameraController->isRightMouseHeld() || cameraController->isMoving()) {
|
||||
// Keep facing decoupled from lateral movement:
|
||||
// face camera when RMB is held, or with forward/back intent.
|
||||
if (cameraController->isRightMouseHeld() ||
|
||||
cameraController->isMovingForward() ||
|
||||
cameraController->isMovingBackward()) {
|
||||
characterYaw = cameraController->getYaw();
|
||||
} else if (targetPosition && !emoteActive && !cameraController->isMoving()) {
|
||||
// Face target when idle
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue