mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
feat: implement SMSG_CAMERA_SHAKE with sinusoidal camera shake effect
- Add triggerShake(magnitude, frequency, duration) to CameraController - Apply envelope-decaying sinusoidal XYZ offset to camera in update() - Handle SMSG_CAMERA_SHAKE opcode in GameHandler dispatch - Translate shakeId to magnitude (minor <50: 0.04, larger: 0.08 world units) - Wire CameraShakeCallback from GameHandler through to CameraController - Shake uses 18Hz oscillation with 30% fade-out envelope at end of duration
This commit is contained in:
parent
214c1a9ff8
commit
9aa4b223dc
5 changed files with 70 additions and 0 deletions
|
|
@ -882,6 +882,11 @@ public:
|
|||
using KnockBackCallback = std::function<void(float vcos, float vsin, float hspeed, float vspeed)>;
|
||||
void setKnockBackCallback(KnockBackCallback cb) { knockBackCallback_ = std::move(cb); }
|
||||
|
||||
// Camera shake callback: called when server sends SMSG_CAMERA_SHAKE.
|
||||
// Parameters: magnitude (world units), frequency (Hz), duration (seconds).
|
||||
using CameraShakeCallback = std::function<void(float magnitude, float frequency, float duration)>;
|
||||
void setCameraShakeCallback(CameraShakeCallback cb) { cameraShakeCallback_ = std::move(cb); }
|
||||
|
||||
// Unstuck callback (resets player Z to floor height)
|
||||
using UnstuckCallback = std::function<void()>;
|
||||
void setUnstuckCallback(UnstuckCallback cb) { unstuckCallback_ = std::move(cb); }
|
||||
|
|
@ -2323,6 +2328,7 @@ private:
|
|||
// ---- Phase 3: Spells ----
|
||||
WorldEntryCallback worldEntryCallback_;
|
||||
KnockBackCallback knockBackCallback_;
|
||||
CameraShakeCallback cameraShakeCallback_;
|
||||
UnstuckCallback unstuckCallback_;
|
||||
UnstuckCallback unstuckGyCallback_;
|
||||
UnstuckCallback unstuckHearthCallback_;
|
||||
|
|
|
|||
|
|
@ -129,6 +129,12 @@ public:
|
|||
// vspeed: raw packet vspeed field (server sends negative for upward launch)
|
||||
void applyKnockBack(float vcos, float vsin, float hspeed, float vspeed);
|
||||
|
||||
// Trigger a camera shake effect (e.g. from SMSG_CAMERA_SHAKE).
|
||||
// magnitude: peak positional offset in world units
|
||||
// frequency: oscillation frequency in Hz
|
||||
// duration: shake duration in seconds
|
||||
void triggerShake(float magnitude, float frequency, float duration);
|
||||
|
||||
// For first-person player hiding
|
||||
void setCharacterRenderer(class CharacterRenderer* cr, uint32_t playerId) {
|
||||
characterRenderer = cr;
|
||||
|
|
@ -369,6 +375,12 @@ private:
|
|||
glm::vec2 knockbackHorizVel_ = glm::vec2(0.0f); // render-space horizontal velocity (units/s)
|
||||
// Horizontal velocity decays via WoW-like drag so the player doesn't slide forever.
|
||||
static constexpr float KNOCKBACK_HORIZ_DRAG = 4.5f; // exponential decay rate (1/s)
|
||||
|
||||
// Camera shake state (SMSG_CAMERA_SHAKE)
|
||||
float shakeElapsed_ = 0.0f;
|
||||
float shakeDuration_ = 0.0f;
|
||||
float shakeMagnitude_ = 0.0f;
|
||||
float shakeFrequency_ = 0.0f;
|
||||
};
|
||||
|
||||
} // namespace rendering
|
||||
|
|
|
|||
|
|
@ -646,6 +646,11 @@ void Application::setState(AppState newState) {
|
|||
renderer->getCameraController()->applyKnockBack(vcos, vsin, hspeed, vspeed);
|
||||
}
|
||||
});
|
||||
gameHandler->setCameraShakeCallback([this](float magnitude, float frequency, float duration) {
|
||||
if (renderer && renderer->getCameraController()) {
|
||||
renderer->getCameraController()->triggerShake(magnitude, frequency, duration);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Load quest marker models
|
||||
loadQuestMarkerModels();
|
||||
|
|
|
|||
|
|
@ -2760,6 +2760,25 @@ void GameHandler::handlePacket(network::Packet& packet) {
|
|||
handleMoveKnockBack(packet);
|
||||
break;
|
||||
|
||||
case Opcode::SMSG_CAMERA_SHAKE: {
|
||||
// uint32 shakeID (CameraShakes.dbc), uint32 shakeType
|
||||
// We don't parse CameraShakes.dbc; apply a hardcoded moderate shake.
|
||||
if (packet.getSize() - packet.getReadPos() >= 8) {
|
||||
uint32_t shakeId = packet.readUInt32();
|
||||
uint32_t shakeType = packet.readUInt32();
|
||||
(void)shakeType;
|
||||
// Map shakeId ranges to approximate magnitudes:
|
||||
// IDs < 50: minor environmental (0.04), others: larger boss effects (0.08)
|
||||
float magnitude = (shakeId < 50) ? 0.04f : 0.08f;
|
||||
if (cameraShakeCallback_) {
|
||||
cameraShakeCallback_(magnitude, 18.0f, 0.5f);
|
||||
}
|
||||
LOG_DEBUG("SMSG_CAMERA_SHAKE: id=", shakeId, " type=", shakeType,
|
||||
" magnitude=", magnitude);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Opcode::SMSG_CLIENT_CONTROL_UPDATE: {
|
||||
// Minimal parse: PackedGuid + uint8 allowMovement.
|
||||
if (packet.getSize() - packet.getReadPos() < 2) {
|
||||
|
|
|
|||
|
|
@ -140,6 +140,17 @@ std::optional<float> CameraController::getCachedFloorHeight(float x, float y, fl
|
|||
return result;
|
||||
}
|
||||
|
||||
void CameraController::triggerShake(float magnitude, float frequency, float duration) {
|
||||
// Allow stronger shake to override weaker; don't allow zero magnitude.
|
||||
if (magnitude <= 0.0f || duration <= 0.0f) return;
|
||||
if (magnitude > shakeMagnitude_ || shakeElapsed_ >= shakeDuration_) {
|
||||
shakeMagnitude_ = magnitude;
|
||||
shakeFrequency_ = frequency;
|
||||
shakeDuration_ = duration;
|
||||
shakeElapsed_ = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void CameraController::update(float deltaTime) {
|
||||
if (!enabled || !camera) {
|
||||
return;
|
||||
|
|
@ -1859,6 +1870,23 @@ void CameraController::update(float deltaTime) {
|
|||
wasFalling = !grounded && verticalVelocity <= 0.0f;
|
||||
|
||||
// R key is now handled above with chat safeguard (WantTextInput check)
|
||||
|
||||
// Camera shake (SMSG_CAMERA_SHAKE): apply sinusoidal offset to final camera position.
|
||||
if (shakeElapsed_ < shakeDuration_) {
|
||||
shakeElapsed_ += deltaTime;
|
||||
float t = shakeElapsed_ / shakeDuration_;
|
||||
// Envelope: fade out over the last 30% of shake duration
|
||||
float envelope = (t < 0.7f) ? 1.0f : (1.0f - (t - 0.7f) / 0.3f);
|
||||
float theta = shakeElapsed_ * shakeFrequency_ * 2.0f * 3.14159265f;
|
||||
glm::vec3 offset(
|
||||
shakeMagnitude_ * envelope * std::sin(theta),
|
||||
shakeMagnitude_ * envelope * std::cos(theta * 1.3f),
|
||||
shakeMagnitude_ * envelope * std::sin(theta * 0.7f) * 0.5f
|
||||
);
|
||||
if (camera) {
|
||||
camera->setPosition(camera->getPosition() + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CameraController::processMouseMotion(const SDL_MouseMotionEvent& event) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue