Fix movement, mounts, and terrain seams

This commit is contained in:
Kelsi 2026-02-07 20:24:25 -08:00
parent c5a4d04bf5
commit 9f19d9fa1a
8 changed files with 93 additions and 27 deletions

View file

@ -1259,26 +1259,7 @@ bool CameraController::isMoving() const {
if (!enabled || !camera) {
return false;
}
if (ImGui::GetIO().WantCaptureKeyboard) {
return false;
}
auto& input = core::Input::getInstance();
bool keyW = input.isKeyPressed(SDL_SCANCODE_W);
bool keyS = input.isKeyPressed(SDL_SCANCODE_S);
bool keyA = input.isKeyPressed(SDL_SCANCODE_A);
bool keyD = input.isKeyPressed(SDL_SCANCODE_D);
bool keyQ = input.isKeyPressed(SDL_SCANCODE_Q);
bool keyE = input.isKeyPressed(SDL_SCANCODE_E);
// In third-person without RMB, A/D are turn keys (not movement).
if (thirdPerson && !rightMouseDown) {
return keyW || keyS || keyQ || keyE || autoRunning;
}
bool mouseAutorun = leftMouseDown && rightMouseDown;
return keyW || keyS || keyA || keyD || keyQ || keyE || mouseAutorun || autoRunning;
return moveForwardActive || moveBackwardActive || strafeLeftActive || strafeRightActive || autoRunning;
}
bool CameraController::isSprinting() const {

View file

@ -647,6 +647,7 @@ bool M2Renderer::loadModel(const pipeline::M2Model& model, uint32_t modelId) {
tightMax = glm::max(tightMax, v.position);
}
bool foliageOrTreeLike = false;
bool chestName = false;
{
std::string lowerName = model.name;
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(),
@ -684,9 +685,16 @@ bool M2Renderer::loadModel(const pipeline::M2Model& model, uint32_t modelId) {
(lowerName.find("box") != std::string::npos) ||
(lowerName.find("chest") != std::string::npos) ||
(lowerName.find("barrel") != std::string::npos);
chestName = (lowerName.find("chest") != std::string::npos);
bool foliageName =
(lowerName.find("bush") != std::string::npos) ||
(lowerName.find("grass") != std::string::npos) ||
(lowerName.find("drygrass") != std::string::npos) ||
(lowerName.find("dry_grass") != std::string::npos) ||
(lowerName.find("dry-grass") != std::string::npos) ||
(lowerName.find("deadgrass") != std::string::npos) ||
(lowerName.find("dead_grass") != std::string::npos) ||
(lowerName.find("dead-grass") != std::string::npos) ||
((lowerName.find("plant") != std::string::npos) && !isPlanter) ||
(lowerName.find("flower") != std::string::npos) ||
(lowerName.find("shrub") != std::string::npos) ||
@ -694,6 +702,10 @@ bool M2Renderer::loadModel(const pipeline::M2Model& model, uint32_t modelId) {
(lowerName.find("vine") != std::string::npos) ||
(lowerName.find("lily") != std::string::npos) ||
(lowerName.find("weed") != std::string::npos) ||
(lowerName.find("pumpkin") != std::string::npos) ||
(lowerName.find("firefly") != std::string::npos) ||
(lowerName.find("fireflies") != std::string::npos) ||
(lowerName.find("fireflys") != std::string::npos) ||
(lowerName.find("mushroom") != std::string::npos) ||
(lowerName.find("fungus") != std::string::npos) ||
(lowerName.find("toadstool") != std::string::npos);
@ -763,7 +775,7 @@ bool M2Renderer::loadModel(const pipeline::M2Model& model, uint32_t modelId) {
break;
}
}
gpuModel.disableAnimation = foliageOrTreeLike;
gpuModel.disableAnimation = foliageOrTreeLike || chestName;
// Flag smoke models for UV scroll animation (particle emitters not implemented)
{

View file

@ -662,7 +662,27 @@ void Renderer::updateCharacterAnimation() {
characterRenderer->setInstanceRotation(mountInstanceId_, glm::vec3(0.0f, 0.0f, yawRad));
// Drive mount model animation: idle when still, run when moving
uint32_t mountAnimId = moving ? ANIM_RUN : ANIM_STAND;
auto pickMountAnim = [&](std::initializer_list<uint32_t> candidates, uint32_t fallback) -> uint32_t {
for (uint32_t id : candidates) {
if (characterRenderer->hasAnimation(mountInstanceId_, id)) {
return id;
}
}
return fallback;
};
uint32_t mountAnimId = ANIM_STAND;
if (moving) {
if (anyStrafeLeft) {
mountAnimId = pickMountAnim({ANIM_STRAFE_RUN_LEFT, ANIM_STRAFE_WALK_LEFT, ANIM_RUN}, ANIM_RUN);
} else if (anyStrafeRight) {
mountAnimId = pickMountAnim({ANIM_STRAFE_RUN_RIGHT, ANIM_STRAFE_WALK_RIGHT, ANIM_RUN}, ANIM_RUN);
} else if (movingBackward) {
mountAnimId = pickMountAnim({ANIM_BACKPEDAL}, ANIM_RUN);
} else {
mountAnimId = ANIM_RUN;
}
}
uint32_t curMountAnim = 0;
float curMountTime = 0, curMountDur = 0;
bool haveMountState = characterRenderer->getAnimationState(mountInstanceId_, curMountAnim, curMountTime, curMountDur);
@ -827,7 +847,24 @@ void Renderer::updateCharacterAnimation() {
break;
case CharAnimState::MOUNT:
break; // Handled by early return above
// If we got here, the mount state was cleared externally but the
// animation state hasn't been reset yet. Fall back to normal logic.
if (swim) {
newState = moving ? CharAnimState::SWIM : CharAnimState::SWIM_IDLE;
} else if (sitting && grounded) {
newState = CharAnimState::SIT_DOWN;
} else if (!grounded && jumping) {
newState = CharAnimState::JUMP_START;
} else if (!grounded) {
newState = CharAnimState::JUMP_MID;
} else if (moving && sprinting) {
newState = CharAnimState::RUN;
} else if (moving) {
newState = CharAnimState::WALK;
} else {
newState = CharAnimState::IDLE;
}
break;
}
if (forceMelee) {