Add proportional zoom and reduced default max zoom with extended toggle

Zoom speed now scales with distance for fine control near the character.
Default max zoom out reduced from 50 to 33 units. New "Extended Camera
Zoom" toggle in Gameplay settings restores the full 50-unit range.
This commit is contained in:
Kelsi 2026-02-23 08:09:27 -08:00
parent 5cfb0817ed
commit b70f08d14f
4 changed files with 26 additions and 4 deletions

View file

@ -27,6 +27,8 @@ public:
float getMouseSensitivity() const { return mouseSensitivity; } float getMouseSensitivity() const { return mouseSensitivity; }
void setInvertMouse(bool invert) { invertMouse = invert; } void setInvertMouse(bool invert) { invertMouse = invert; }
bool isInvertMouse() const { return invertMouse; } bool isInvertMouse() const { return invertMouse; }
void setExtendedZoom(bool extended) { extendedZoom_ = extended; }
bool isExtendedZoom() const { return extendedZoom_; }
void setEnabled(bool enabled) { this->enabled = enabled; } void setEnabled(bool enabled) { this->enabled = enabled; }
void setTerrainManager(TerrainManager* tm) { terrainManager = tm; } void setTerrainManager(TerrainManager* tm) { terrainManager = tm; }
void setWMORenderer(WMORenderer* wmo) { wmoRenderer = wmo; } void setWMORenderer(WMORenderer* wmo) { wmoRenderer = wmo; }
@ -137,7 +139,9 @@ private:
float collisionDistance = 10.0f; // Max allowed by collision float collisionDistance = 10.0f; // Max allowed by collision
bool externalFollow_ = false; bool externalFollow_ = false;
static constexpr float MIN_DISTANCE = 0.5f; // Minimum zoom (first-person threshold) static constexpr float MIN_DISTANCE = 0.5f; // Minimum zoom (first-person threshold)
static constexpr float MAX_DISTANCE = 50.0f; // Maximum zoom out static constexpr float MAX_DISTANCE_NORMAL = 33.0f; // Default max zoom out
static constexpr float MAX_DISTANCE_EXTENDED = 50.0f; // Extended max zoom out
bool extendedZoom_ = false;
static constexpr float ZOOM_SMOOTH_SPEED = 15.0f; // How fast zoom eases static constexpr float ZOOM_SMOOTH_SPEED = 15.0f; // How fast zoom eases
static constexpr float CAM_SMOOTH_SPEED = 20.0f; // How fast camera position smooths static constexpr float CAM_SMOOTH_SPEED = 20.0f; // How fast camera position smooths
static constexpr float PIVOT_HEIGHT = 1.8f; // Pivot at head height static constexpr float PIVOT_HEIGHT = 1.8f; // Pivot at head height

View file

@ -94,6 +94,7 @@ private:
int pendingActivityVolume = 100; int pendingActivityVolume = 100;
float pendingMouseSensitivity = 0.2f; float pendingMouseSensitivity = 0.2f;
bool pendingInvertMouse = false; bool pendingInvertMouse = false;
bool pendingExtendedZoom = false;
int pendingUiOpacity = 65; int pendingUiOpacity = 65;
bool pendingMinimapRotate = false; bool pendingMinimapRotate = false;
bool pendingMinimapSquare = false; bool pendingMinimapSquare = false;

View file

@ -1678,9 +1678,11 @@ void CameraController::teleportTo(const glm::vec3& pos) {
} }
void CameraController::processMouseWheel(float delta) { void CameraController::processMouseWheel(float delta) {
// Adjust user's target distance (collision may limit actual distance) // Scale zoom speed proportionally to current distance for fine control up close
userTargetDistance -= delta * 2.0f; // 2.0 units per scroll notch float zoomSpeed = glm::max(userTargetDistance * 0.15f, 0.3f);
userTargetDistance = glm::clamp(userTargetDistance, MIN_DISTANCE, MAX_DISTANCE); userTargetDistance -= delta * zoomSpeed;
float maxDist = extendedZoom_ ? MAX_DISTANCE_EXTENDED : MAX_DISTANCE_NORMAL;
userTargetDistance = glm::clamp(userTargetDistance, MIN_DISTANCE, maxDist);
} }
void CameraController::setFollowTarget(glm::vec3* target) { void CameraController::setFollowTarget(glm::vec3* target) {

View file

@ -5916,6 +5916,7 @@ void GameScreen::renderSettingsWindow() {
if (auto* cameraController = renderer->getCameraController()) { if (auto* cameraController = renderer->getCameraController()) {
pendingMouseSensitivity = cameraController->getMouseSensitivity(); pendingMouseSensitivity = cameraController->getMouseSensitivity();
pendingInvertMouse = cameraController->isInvertMouse(); pendingInvertMouse = cameraController->isInvertMouse();
cameraController->setExtendedZoom(pendingExtendedZoom);
} }
} }
pendingResIndex = 0; pendingResIndex = 0;
@ -6275,6 +6276,16 @@ void GameScreen::renderSettingsWindow() {
} }
saveSettings(); saveSettings();
} }
if (ImGui::Checkbox("Extended Camera Zoom", &pendingExtendedZoom)) {
if (renderer) {
if (auto* cameraController = renderer->getCameraController()) {
cameraController->setExtendedZoom(pendingExtendedZoom);
}
}
saveSettings();
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Allow the camera to zoom out further than normal");
ImGui::Spacing(); ImGui::Spacing();
ImGui::Spacing(); ImGui::Spacing();
@ -6354,6 +6365,7 @@ void GameScreen::renderSettingsWindow() {
if (ImGui::Button("Restore Gameplay Defaults", ImVec2(-1, 0))) { if (ImGui::Button("Restore Gameplay Defaults", ImVec2(-1, 0))) {
pendingMouseSensitivity = kDefaultMouseSensitivity; pendingMouseSensitivity = kDefaultMouseSensitivity;
pendingInvertMouse = kDefaultInvertMouse; pendingInvertMouse = kDefaultInvertMouse;
pendingExtendedZoom = false;
pendingUiOpacity = 65; pendingUiOpacity = 65;
pendingMinimapRotate = false; pendingMinimapRotate = false;
pendingMinimapSquare = false; pendingMinimapSquare = false;
@ -6368,6 +6380,7 @@ void GameScreen::renderSettingsWindow() {
if (auto* cameraController = renderer->getCameraController()) { if (auto* cameraController = renderer->getCameraController()) {
cameraController->setMouseSensitivity(pendingMouseSensitivity); cameraController->setMouseSensitivity(pendingMouseSensitivity);
cameraController->setInvertMouse(pendingInvertMouse); cameraController->setInvertMouse(pendingInvertMouse);
cameraController->setExtendedZoom(pendingExtendedZoom);
} }
if (auto* minimap = renderer->getMinimap()) { if (auto* minimap = renderer->getMinimap()) {
minimap->setRotateWithCamera(minimapRotate_); minimap->setRotateWithCamera(minimapRotate_);
@ -7085,6 +7098,7 @@ void GameScreen::saveSettings() {
// Controls // Controls
out << "mouse_sensitivity=" << pendingMouseSensitivity << "\n"; out << "mouse_sensitivity=" << pendingMouseSensitivity << "\n";
out << "invert_mouse=" << (pendingInvertMouse ? 1 : 0) << "\n"; out << "invert_mouse=" << (pendingInvertMouse ? 1 : 0) << "\n";
out << "extended_zoom=" << (pendingExtendedZoom ? 1 : 0) << "\n";
// Chat // Chat
out << "chat_active_tab=" << activeChatTab_ << "\n"; out << "chat_active_tab=" << activeChatTab_ << "\n";
@ -7166,6 +7180,7 @@ void GameScreen::loadSettings() {
// Controls // Controls
else if (key == "mouse_sensitivity") pendingMouseSensitivity = std::clamp(std::stof(val), 0.05f, 1.0f); else if (key == "mouse_sensitivity") pendingMouseSensitivity = std::clamp(std::stof(val), 0.05f, 1.0f);
else if (key == "invert_mouse") pendingInvertMouse = (std::stoi(val) != 0); else if (key == "invert_mouse") pendingInvertMouse = (std::stoi(val) != 0);
else if (key == "extended_zoom") pendingExtendedZoom = (std::stoi(val) != 0);
// Chat // Chat
else if (key == "chat_active_tab") activeChatTab_ = std::clamp(std::stoi(val), 0, 3); else if (key == "chat_active_tab") activeChatTab_ = std::clamp(std::stoi(val), 0, 3);
else if (key == "chat_timestamps") chatShowTimestamps_ = (std::stoi(val) != 0); else if (key == "chat_timestamps") chatShowTimestamps_ = (std::stoi(val) != 0);