mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-05-02 02:23:56 +00:00
Fix mobile camera zoom/transition and name bubble issues
- Reduce pinch zoom sensitivity (15x → 6x multiplier) - Add cumulative deadzone threshold for 1st/3rd person transitions to prevent accidental mode switches from slight finger movement - Preserve camera touch tracking through 3rd→1st transition so the same fingers can pinch back without lifting (seamless round-trip) - On 1st→3rd transition, selectively clear only camera-owned fingers from LegoInputManager's touch scheme state, preserving any active left-side movement finger - Suppress camera gesture processing until finger positions re-sync after transition to prevent camera jumps from stale coordinates - Hide local player name bubble when transitioning to 1st person, restore on transition back to 3rd person Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
577fa09a3b
commit
74271aa189
@ -180,6 +180,7 @@ class LegoInputManager : public MxPresenter {
|
||||
// LegoInputManager::`scalar deleting destructor'
|
||||
|
||||
friend class Extensions::MultiplayerExt;
|
||||
friend class Extensions::ThirdPersonCameraExt;
|
||||
|
||||
private:
|
||||
void InitializeHaptics();
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
namespace Extensions
|
||||
{
|
||||
class MultiplayerExt;
|
||||
class ThirdPersonCameraExt;
|
||||
namespace Common
|
||||
{
|
||||
class CharacterCloner;
|
||||
|
||||
@ -26,7 +26,7 @@ class Controller {
|
||||
Controller();
|
||||
|
||||
void Enable();
|
||||
void Disable();
|
||||
void Disable(bool p_preserveTouch = false);
|
||||
bool IsEnabled() const { return m_enabled; }
|
||||
bool IsActive() const { return m_active; }
|
||||
|
||||
@ -77,10 +77,13 @@ class Controller {
|
||||
float GetOrbitDistance() const { return m_orbit.GetOrbitDistance(); }
|
||||
void SetOrbitDistance(float p_distance) { m_orbit.SetOrbitDistance(p_distance); }
|
||||
void ResetTouchState() { m_input.ResetTouchState(); }
|
||||
void SuppressGestures() { m_input.SuppressGestures(); }
|
||||
|
||||
bool TryClaimFinger(const SDL_TouchFingerEvent& event) { return m_input.TryClaimFinger(event, m_active); }
|
||||
bool TryReleaseFinger(SDL_FingerID id) { return m_input.TryReleaseFinger(id); }
|
||||
bool IsFingerTracked(SDL_FingerID id) const { return m_input.IsFingerTracked(id); }
|
||||
int GetTouchCount() const { return m_input.GetTouchCount(); }
|
||||
SDL_FingerID GetFingerID(int idx) const { return m_input.GetFingerID(idx); }
|
||||
|
||||
void FreezeDisplayActor() { m_display.FreezeDisplayActor(); }
|
||||
void UnfreezeDisplayActor() { m_display.UnfreezeDisplayActor(); }
|
||||
|
||||
@ -18,20 +18,26 @@ class InputHandler {
|
||||
bool TryClaimFinger(const SDL_TouchFingerEvent& p_event, bool p_active);
|
||||
bool TryReleaseFinger(SDL_FingerID p_id);
|
||||
bool IsFingerTracked(SDL_FingerID p_id) const;
|
||||
int GetTouchCount() const { return m_touch.count; }
|
||||
SDL_FingerID GetFingerID(int p_idx) const { return m_touch.id[p_idx]; }
|
||||
|
||||
bool ConsumeAutoDisable();
|
||||
bool ConsumeAutoEnable();
|
||||
|
||||
void ResetTouchState() { m_touch = {}; }
|
||||
void SuppressGestures();
|
||||
|
||||
static constexpr float CAMERA_ZONE_X = 0.5f;
|
||||
static constexpr float PINCH_TRANSITION_THRESHOLD = 0.03f;
|
||||
|
||||
private:
|
||||
struct TouchState {
|
||||
SDL_FingerID id[2];
|
||||
float x[2], y[2];
|
||||
bool synced[2];
|
||||
int count;
|
||||
float initialPinchDist;
|
||||
float gesturePinchDist;
|
||||
} m_touch;
|
||||
|
||||
bool m_wantsAutoDisable;
|
||||
|
||||
@ -75,6 +75,15 @@ MxResult NetworkManager::Tickle()
|
||||
if (cameraEnabled != m_lastCameraEnabled) {
|
||||
m_lastCameraEnabled = cameraEnabled;
|
||||
NotifyThirdPersonChanged(cameraEnabled);
|
||||
|
||||
if (m_localNameBubble) {
|
||||
if (!cameraEnabled) {
|
||||
m_localNameBubble->SetVisible(false);
|
||||
}
|
||||
else if (m_showNameBubbles) {
|
||||
m_localNameBubble->SetVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create local name bubble when display ROI becomes available
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "extensions/thirdpersoncamera/controller.h"
|
||||
#include "islepathactor.h"
|
||||
#include "legoeventnotificationparam.h"
|
||||
#include "legoinputmanager.h"
|
||||
#include "legonavcontroller.h"
|
||||
#include "legopathactor.h"
|
||||
#include "legovideomanager.h"
|
||||
@ -118,10 +119,29 @@ void ThirdPersonCameraExt::OnSDLEvent(SDL_Event* p_event)
|
||||
s_camera->HandleSDLEventImpl(p_event);
|
||||
|
||||
if (s_camera->ConsumeAutoDisable()) {
|
||||
s_camera->Disable();
|
||||
s_camera->Disable(/*p_preserveTouch=*/true);
|
||||
}
|
||||
else if (s_camera->ConsumeAutoEnable()) {
|
||||
s_camera->ResetTouchState();
|
||||
// Clear the movement system's touch state for camera-owned fingers only,
|
||||
// so any virtual thumbstick input from 1st-person mode is zeroed while
|
||||
// leaving a left-side movement finger intact.
|
||||
LegoInputManager* im = InputManager();
|
||||
if (im) {
|
||||
for (int i = 0; i < s_camera->GetTouchCount(); i++) {
|
||||
SDL_FingerID fid = s_camera->GetFingerID(i);
|
||||
if (im->m_touchFinger == fid) {
|
||||
im->m_touchFinger = 0;
|
||||
im->m_touchVirtualThumb = {0, 0};
|
||||
im->m_touchVirtualThumbOrigin = {0, 0};
|
||||
}
|
||||
im->m_touchFlags.erase(fid);
|
||||
}
|
||||
}
|
||||
|
||||
// Suppress camera gestures until finger positions re-sync to avoid
|
||||
// a camera jump from stale positions carried through the transition.
|
||||
s_camera->SuppressGestures();
|
||||
|
||||
s_camera->SetOrbitDistance(ThirdPersonCamera::Controller::MIN_DISTANCE);
|
||||
s_camera->Enable();
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ void Controller::Enable()
|
||||
ReinitForCharacter();
|
||||
}
|
||||
|
||||
void Controller::Disable()
|
||||
void Controller::Disable(bool p_preserveTouch)
|
||||
{
|
||||
m_enabled = false;
|
||||
|
||||
@ -60,7 +60,9 @@ void Controller::Disable()
|
||||
m_animator.ClearAll();
|
||||
|
||||
m_orbit.ResetOrbitState();
|
||||
m_input.ResetTouchState();
|
||||
if (!p_preserveTouch) {
|
||||
m_input.ResetTouchState();
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::OnActorEnter(IslePathActor* p_actor)
|
||||
|
||||
@ -21,12 +21,14 @@ bool InputHandler::TryClaimFinger(const SDL_TouchFingerEvent& p_event, bool p_ac
|
||||
m_touch.id[idx] = p_event.fingerID;
|
||||
m_touch.x[idx] = p_event.x;
|
||||
m_touch.y[idx] = p_event.y;
|
||||
m_touch.synced[idx] = true;
|
||||
m_touch.count++;
|
||||
|
||||
if (m_touch.count == 2) {
|
||||
float dx = m_touch.x[1] - m_touch.x[0];
|
||||
float dy = m_touch.y[1] - m_touch.y[0];
|
||||
m_touch.initialPinchDist = SDL_sqrtf(dx * dx + dy * dy);
|
||||
m_touch.gesturePinchDist = m_touch.initialPinchDist;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -40,9 +42,11 @@ bool InputHandler::TryReleaseFinger(SDL_FingerID p_id)
|
||||
m_touch.id[0] = m_touch.id[1];
|
||||
m_touch.x[0] = m_touch.x[1];
|
||||
m_touch.y[0] = m_touch.y[1];
|
||||
m_touch.synced[0] = m_touch.synced[1];
|
||||
}
|
||||
m_touch.count--;
|
||||
m_touch.initialPinchDist = 0.0f;
|
||||
m_touch.gesturePinchDist = 0.0f;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -69,6 +73,14 @@ bool InputHandler::ConsumeAutoEnable()
|
||||
return std::exchange(m_wantsAutoEnable, false);
|
||||
}
|
||||
|
||||
void InputHandler::SuppressGestures()
|
||||
{
|
||||
m_touch.synced[0] = false;
|
||||
m_touch.synced[1] = false;
|
||||
m_touch.initialPinchDist = 0.0f;
|
||||
m_touch.gesturePinchDist = 0.0f;
|
||||
}
|
||||
|
||||
void InputHandler::HandleSDLEvent(SDL_Event* p_event, OrbitCamera& p_orbit, bool p_active)
|
||||
{
|
||||
switch (p_event->type) {
|
||||
@ -117,12 +129,14 @@ void InputHandler::HandleSDLEvent(SDL_Event* p_event, OrbitCamera& p_orbit, bool
|
||||
m_touch.id[idx] = p_event->tfinger.fingerID;
|
||||
m_touch.x[idx] = p_event->tfinger.x;
|
||||
m_touch.y[idx] = p_event->tfinger.y;
|
||||
m_touch.synced[idx] = true;
|
||||
m_touch.count++;
|
||||
|
||||
if (m_touch.count == 2) {
|
||||
float dx = m_touch.x[1] - m_touch.x[0];
|
||||
float dy = m_touch.y[1] - m_touch.y[0];
|
||||
m_touch.initialPinchDist = SDL_sqrtf(dx * dx + dy * dy);
|
||||
m_touch.gesturePinchDist = m_touch.initialPinchDist;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -134,6 +148,13 @@ void InputHandler::HandleSDLEvent(SDL_Event* p_event, OrbitCamera& p_orbit, bool
|
||||
break;
|
||||
}
|
||||
if (m_touch.id[0] == p_event->tfinger.fingerID) {
|
||||
if (!m_touch.synced[0]) {
|
||||
m_touch.x[0] = p_event->tfinger.x;
|
||||
m_touch.y[0] = p_event->tfinger.y;
|
||||
m_touch.synced[0] = true;
|
||||
break;
|
||||
}
|
||||
|
||||
float oldX = m_touch.x[0];
|
||||
float oldY = m_touch.y[0];
|
||||
m_touch.x[0] = p_event->tfinger.x;
|
||||
@ -158,6 +179,20 @@ void InputHandler::HandleSDLEvent(SDL_Event* p_event, OrbitCamera& p_orbit, bool
|
||||
break;
|
||||
}
|
||||
|
||||
if (!m_touch.synced[idx]) {
|
||||
m_touch.x[idx] = p_event->tfinger.x;
|
||||
m_touch.y[idx] = p_event->tfinger.y;
|
||||
m_touch.synced[idx] = true;
|
||||
|
||||
if (m_touch.synced[0] && m_touch.synced[1]) {
|
||||
float dx = m_touch.x[1] - m_touch.x[0];
|
||||
float dy = m_touch.y[1] - m_touch.y[0];
|
||||
m_touch.initialPinchDist = SDL_sqrtf(dx * dx + dy * dy);
|
||||
m_touch.gesturePinchDist = m_touch.initialPinchDist;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
float oldX = m_touch.x[idx];
|
||||
float oldY = m_touch.y[idx];
|
||||
m_touch.x[idx] = p_event->tfinger.x;
|
||||
@ -171,20 +206,26 @@ void InputHandler::HandleSDLEvent(SDL_Event* p_event, OrbitCamera& p_orbit, bool
|
||||
float pinchDelta = m_touch.initialPinchDist - newDist;
|
||||
|
||||
if (!p_active) {
|
||||
if (pinchDelta > 0) {
|
||||
float totalDelta = m_touch.gesturePinchDist - newDist;
|
||||
if (totalDelta > PINCH_TRANSITION_THRESHOLD) {
|
||||
m_wantsAutoEnable = true;
|
||||
m_touch.gesturePinchDist = newDist;
|
||||
}
|
||||
m_touch.initialPinchDist = newDist;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_orbit.GetOrbitDistance() <= OrbitCamera::MIN_DISTANCE && pinchDelta < 0) {
|
||||
m_wantsAutoDisable = true;
|
||||
m_touch.initialPinchDist = newDist;
|
||||
break;
|
||||
if (p_orbit.GetOrbitDistance() <= OrbitCamera::MIN_DISTANCE) {
|
||||
float totalDelta = newDist - m_touch.gesturePinchDist;
|
||||
if (totalDelta > PINCH_TRANSITION_THRESHOLD) {
|
||||
m_wantsAutoDisable = true;
|
||||
m_touch.initialPinchDist = newDist;
|
||||
m_touch.gesturePinchDist = newDist;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p_orbit.AdjustDistance(pinchDelta * 15.0f);
|
||||
p_orbit.AdjustDistance(pinchDelta * 6.0f);
|
||||
p_orbit.ClampDistance();
|
||||
m_touch.initialPinchDist = newDist;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user