Implement activity SFX and decouple camera orbit from movement facing

This commit is contained in:
Kelsi 2026-02-03 19:49:56 -08:00
parent dfc29cad10
commit 8bc50818a9
9 changed files with 592 additions and 12 deletions

View file

@ -28,6 +28,7 @@
#include "game/zone_manager.hpp"
#include "audio/music_manager.hpp"
#include "audio/footstep_manager.hpp"
#include "audio/activity_sound_manager.hpp"
#include <GL/glew.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/euler_angles.hpp>
@ -190,6 +191,7 @@ bool Renderer::initialize(core::Window* win) {
// Create music manager (initialized later with asset manager)
musicManager = std::make_unique<audio::MusicManager>();
footstepManager = std::make_unique<audio::FootstepManager>();
activitySoundManager = std::make_unique<audio::ActivitySoundManager>();
LOG_INFO("Renderer initialized");
return true;
@ -266,6 +268,10 @@ void Renderer::shutdown() {
footstepManager->shutdown();
footstepManager.reset();
}
if (activitySoundManager) {
activitySoundManager->shutdown();
activitySoundManager.reset();
}
zoneManager.reset();
@ -647,13 +653,16 @@ void Renderer::update(float deltaTime) {
// Sync character model position/rotation and animation with follow target
if (characterInstanceId > 0 && characterRenderer && cameraController && cameraController->isThirdPerson()) {
characterRenderer->setInstancePosition(characterInstanceId, characterPosition);
if (activitySoundManager) {
std::string modelName;
if (characterRenderer->getInstanceModelName(characterInstanceId, modelName)) {
activitySoundManager->setCharacterVoiceProfile(modelName);
}
}
// 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();
// Movement-facing comes from camera controller and is decoupled from LMB orbit.
if (cameraController->isMoving() || cameraController->isRightMouseHeld()) {
characterYaw = cameraController->getFacingYaw();
} else if (targetPosition && !emoteActive && !cameraController->isMoving()) {
// Face target when idle
glm::vec3 toTarget = *targetPosition - characterPosition;
@ -737,6 +746,51 @@ void Renderer::update(float deltaTime) {
}
}
// Activity SFX: animation/state-driven jump, landing, and swim loops/splashes.
if (activitySoundManager) {
activitySoundManager->update(deltaTime);
if (cameraController && cameraController->isThirdPerson()) {
bool grounded = cameraController->isGrounded();
bool jumping = cameraController->isJumping();
bool falling = cameraController->isFalling();
bool swimming = cameraController->isSwimming();
bool moving = cameraController->isMoving();
if (!sfxStateInitialized) {
sfxPrevGrounded = grounded;
sfxPrevJumping = jumping;
sfxPrevFalling = falling;
sfxPrevSwimming = swimming;
sfxStateInitialized = true;
}
if (jumping && !sfxPrevJumping && !swimming) {
activitySoundManager->playJump();
}
if (grounded && !sfxPrevGrounded) {
bool hardLanding = sfxPrevFalling;
activitySoundManager->playLanding(resolveFootstepSurface(), hardLanding);
}
if (swimming && !sfxPrevSwimming) {
activitySoundManager->playWaterEnter();
} else if (!swimming && sfxPrevSwimming) {
activitySoundManager->playWaterExit();
}
activitySoundManager->setSwimmingState(swimming, moving);
sfxPrevGrounded = grounded;
sfxPrevJumping = jumping;
sfxPrevFalling = falling;
sfxPrevSwimming = swimming;
} else {
activitySoundManager->setSwimmingState(false, false);
sfxStateInitialized = false;
}
}
// Update M2 doodad animations
if (m2Renderer) {
m2Renderer->update(deltaTime);
@ -1011,6 +1065,9 @@ bool Renderer::loadTestTerrain(pipeline::AssetManager* assetManager, const std::
if (footstepManager) {
footstepManager->initialize(assetManager);
}
if (activitySoundManager) {
activitySoundManager->initialize(assetManager);
}
cachedAssetManager = assetManager;
}
@ -1079,6 +1136,11 @@ bool Renderer::loadTerrainArea(const std::string& mapName, int centerX, int cent
footstepManager->initialize(cachedAssetManager);
}
}
if (activitySoundManager && cachedAssetManager) {
if (!activitySoundManager->isInitialized()) {
activitySoundManager->initialize(cachedAssetManager);
}
}
// Wire WMO, M2, and water renderer to camera controller
if (cameraController && wmoRenderer) {