mirror of
https://github.com/Raicuparta/nomai-vr.git
synced 2025-12-11 20:15:08 +01:00
Added Snap Turning (#556)
* Added Snap Turning - Disabled by default, can be enabled in settings - Amount per input can be defined in settings (current range is 15 - 90 degrees) - Default input action is the right thumb stick (same as smooth turn) * Moved snap turn from slider to selector for settings * Fixed snap turning with smooth HUD/Helmet - Previously, the smooth HUD/Helmet would uncomfortably move a long distance after you snap turn - Now, if smooth HUD and snap turning are both enabled, the helmet snap turns for a frame, then resumes it's previous behavior * Disable snap turning while in zero-g --------- Co-authored-by: Raicuparta <Raicuparta@users.noreply.github.com>
This commit is contained in:
parent
28a335a38d
commit
aefee463b0
@ -17,6 +17,8 @@ namespace NomaiVR.ModConfig
|
|||||||
bool PreventClipping { get; }
|
bool PreventClipping { get; }
|
||||||
bool FlashlightGesture { get; }
|
bool FlashlightGesture { get; }
|
||||||
bool ControllerOrientedMovement { get; }
|
bool ControllerOrientedMovement { get; }
|
||||||
|
bool SnapTurning { get; }
|
||||||
|
string SnapTurnIncrement { get; }
|
||||||
bool AutoHideToolbelt { get; }
|
bool AutoHideToolbelt { get; }
|
||||||
float ToolbeltHeight { get; }
|
float ToolbeltHeight { get; }
|
||||||
float HudScale { get; }
|
float HudScale { get; }
|
||||||
|
|||||||
@ -19,6 +19,8 @@ namespace NomaiVR.ModConfig
|
|||||||
public static bool PreventClipping => settingsProvider.PreventClipping;
|
public static bool PreventClipping => settingsProvider.PreventClipping;
|
||||||
public static bool FlashlightGesture => settingsProvider.FlashlightGesture;
|
public static bool FlashlightGesture => settingsProvider.FlashlightGesture;
|
||||||
public static bool ControllerOrientedMovement => settingsProvider.ControllerOrientedMovement;
|
public static bool ControllerOrientedMovement => settingsProvider.ControllerOrientedMovement;
|
||||||
|
public static bool SnapTurning => settingsProvider.SnapTurning;
|
||||||
|
public static string SnapTurnIncrement => settingsProvider.SnapTurnIncrement;
|
||||||
public static bool AutoHideToolbelt => settingsProvider.AutoHideToolbelt;
|
public static bool AutoHideToolbelt => settingsProvider.AutoHideToolbelt;
|
||||||
public static float ToolbeltHeight => settingsProvider.ToolbeltHeight;
|
public static float ToolbeltHeight => settingsProvider.ToolbeltHeight;
|
||||||
public static float HudScale => settingsProvider.HudScale;
|
public static float HudScale => settingsProvider.HudScale;
|
||||||
|
|||||||
@ -18,6 +18,8 @@ namespace NomaiVR.ModConfig
|
|||||||
public bool PreventClipping { get; private set; }
|
public bool PreventClipping { get; private set; }
|
||||||
public bool FlashlightGesture { get; private set; }
|
public bool FlashlightGesture { get; private set; }
|
||||||
public bool ControllerOrientedMovement { get; private set; }
|
public bool ControllerOrientedMovement { get; private set; }
|
||||||
|
public bool SnapTurning { get; private set; }
|
||||||
|
public string SnapTurnIncrement { get; private set; }
|
||||||
public bool AutoHideToolbelt { get; private set; }
|
public bool AutoHideToolbelt { get; private set; }
|
||||||
public float ToolbeltHeight { get; private set; }
|
public float ToolbeltHeight { get; private set; }
|
||||||
public float HudScale { get; private set; }
|
public float HudScale { get; private set; }
|
||||||
@ -38,6 +40,8 @@ namespace NomaiVR.ModConfig
|
|||||||
VibrationStrength = config.GetSettingsValue<float>("vibrationIntensity");
|
VibrationStrength = config.GetSettingsValue<float>("vibrationIntensity");
|
||||||
ShowHelmet = config.GetSettingsValue<bool>("helmetVisibility");
|
ShowHelmet = config.GetSettingsValue<bool>("helmetVisibility");
|
||||||
ControllerOrientedMovement = config.GetSettingsValue<bool>("movementControllerOriented");
|
ControllerOrientedMovement = config.GetSettingsValue<bool>("movementControllerOriented");
|
||||||
|
SnapTurning = config.GetSettingsValue<bool>("snapTurning");
|
||||||
|
SnapTurnIncrement = config.GetSettingsValue<string>("snapTurnIncrement");
|
||||||
EnableGesturePrompts = config.GetSettingsValue<bool>("showGesturePrompts");
|
EnableGesturePrompts = config.GetSettingsValue<bool>("showGesturePrompts");
|
||||||
EnableHandLaser = config.GetSettingsValue<bool>("showHandLaser");
|
EnableHandLaser = config.GetSettingsValue<bool>("showHandLaser");
|
||||||
EnableFeetMarker = config.GetSettingsValue<bool>("showFeetMarker");
|
EnableFeetMarker = config.GetSettingsValue<bool>("showFeetMarker");
|
||||||
|
|||||||
@ -78,6 +78,25 @@
|
|||||||
"yes": "Controller",
|
"yes": "Controller",
|
||||||
"no": "Head"
|
"no": "Head"
|
||||||
},
|
},
|
||||||
|
"snapTurning": {
|
||||||
|
"type": "toggle",
|
||||||
|
"value": false,
|
||||||
|
"title": "Snap turning",
|
||||||
|
"yes": "Enabled",
|
||||||
|
"no": "Disabled"
|
||||||
|
},
|
||||||
|
"snapTurnIncrement": {
|
||||||
|
"type": "selector",
|
||||||
|
"value": "45",
|
||||||
|
"options": [
|
||||||
|
"15",
|
||||||
|
"30",
|
||||||
|
"45",
|
||||||
|
"60",
|
||||||
|
"90"
|
||||||
|
],
|
||||||
|
"title": "Snap turn increment"
|
||||||
|
},
|
||||||
"showGesturePrompts": {
|
"showGesturePrompts": {
|
||||||
"type": "toggle",
|
"type": "toggle",
|
||||||
"value": true,
|
"value": true,
|
||||||
|
|||||||
@ -14,6 +14,8 @@ namespace NomaiVR.Player
|
|||||||
|
|
||||||
public class Behaviour : MonoBehaviour
|
public class Behaviour : MonoBehaviour
|
||||||
{
|
{
|
||||||
|
public static Action OnSnapTurn;
|
||||||
|
|
||||||
private Transform cameraParent;
|
private Transform cameraParent;
|
||||||
private static Transform playArea;
|
private static Transform playArea;
|
||||||
private static OWCamera playerCamera;
|
private static OWCamera playerCamera;
|
||||||
@ -22,6 +24,10 @@ namespace NomaiVR.Player
|
|||||||
private static PlayerCharacterController playerController;
|
private static PlayerCharacterController playerController;
|
||||||
private static Autopilot autopilot;
|
private static Autopilot autopilot;
|
||||||
private readonly SteamVR_Action_Boolean recenterAction = SteamVR_Actions._default.Recenter;
|
private readonly SteamVR_Action_Boolean recenterAction = SteamVR_Actions._default.Recenter;
|
||||||
|
private static readonly SteamVR_Action_Vector2 turnAction = SteamVR_Actions._default.Look;
|
||||||
|
private static readonly float snapTurnInputThreshold = 0.15f;
|
||||||
|
private static bool isSnapTurnInCooldown = false;
|
||||||
|
private float lastTurnTime;
|
||||||
|
|
||||||
internal void Start()
|
internal void Start()
|
||||||
{
|
{
|
||||||
@ -95,12 +101,23 @@ namespace NomaiVR.Player
|
|||||||
}
|
}
|
||||||
|
|
||||||
UpdateRecenter();
|
UpdateRecenter();
|
||||||
|
|
||||||
|
if (ModSettings.SnapTurning)
|
||||||
|
{
|
||||||
|
// Check if time has passed and input stick was returned to neutral
|
||||||
|
if (isSnapTurnInCooldown && Time.time - lastTurnTime > 0.05f && Mathf.Abs(turnAction.axis.x) < snapTurnInputThreshold)
|
||||||
|
{
|
||||||
|
isSnapTurnInCooldown = false;
|
||||||
|
lastTurnTime = Time.time;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Patch : NomaiVRPatch
|
public class Patch : NomaiVRPatch
|
||||||
{
|
{
|
||||||
public override void ApplyPatches()
|
public override void ApplyPatches()
|
||||||
{
|
{
|
||||||
|
Postfix<OWInput>(nameof(OWInput.GetAxisValue), nameof(PostGetAxisValue));
|
||||||
Postfix<PlayerCharacterController>(nameof(PlayerCharacterController.UpdateTurning), nameof(PostCharacterTurning));
|
Postfix<PlayerCharacterController>(nameof(PlayerCharacterController.UpdateTurning), nameof(PostCharacterTurning));
|
||||||
Postfix<JetpackThrusterController>(nameof(JetpackThrusterController.FixedUpdate), nameof(PostThrusterUpdate));
|
Postfix<JetpackThrusterController>(nameof(JetpackThrusterController.FixedUpdate), nameof(PostThrusterUpdate));
|
||||||
Prefix<OWCamera>("set_" + nameof(OWCamera.fieldOfView), nameof(PatchOwCameraFOV));
|
Prefix<OWCamera>("set_" + nameof(OWCamera.fieldOfView), nameof(PatchOwCameraFOV));
|
||||||
@ -136,11 +153,25 @@ namespace NomaiVR.Player
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ModSettings.SnapTurning && !PlayerState.InZeroG())
|
||||||
|
{
|
||||||
|
float turnInput = turnAction.axis.x;
|
||||||
|
|
||||||
|
// If snap turning, only do the snap turn, skip reorienting the play area
|
||||||
|
if (!isSnapTurnInCooldown && Mathf.Abs(turnInput) > snapTurnInputThreshold)
|
||||||
|
{
|
||||||
|
isSnapTurnInCooldown = true;
|
||||||
|
float sign = Mathf.Sign(turnInput);
|
||||||
|
Quaternion snapRotation = Quaternion.AngleAxis(GetSnapTurnIncrement() * sign, playerBody.transform.up);
|
||||||
|
var fromToSnap = Quaternion.FromToRotation(playerBody.transform.forward, snapRotation * playerBody.transform.forward);
|
||||||
|
|
||||||
|
rotationSetter(fromToSnap * playerBody.transform.rotation);
|
||||||
|
OnSnapTurn?.Invoke();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var rotationSource = isControllerOriented ? LaserPointer.Behaviour.MovementLaser : playerCamera.transform;
|
var rotationSource = isControllerOriented ? LaserPointer.Behaviour.MovementLaser : playerCamera.transform;
|
||||||
|
|
||||||
var fromTo = Quaternion.FromToRotation(playerBody.transform.forward, Vector3.ProjectOnPlane(rotationSource.transform.forward, playerBody.transform.up));
|
|
||||||
|
|
||||||
var magnitude = 0f;
|
var magnitude = 0f;
|
||||||
if (!isControllerOriented)
|
if (!isControllerOriented)
|
||||||
{
|
{
|
||||||
@ -154,6 +185,7 @@ namespace NomaiVR.Player
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fromTo = Quaternion.FromToRotation(playerBody.transform.forward, Vector3.ProjectOnPlane(rotationSource.transform.forward, playerBody.transform.up));
|
||||||
var targetRotation = fromTo * playerBody.transform.rotation;
|
var targetRotation = fromTo * playerBody.transform.rotation;
|
||||||
var inverseRotation = Quaternion.Inverse(fromTo) * playArea.rotation;
|
var inverseRotation = Quaternion.Inverse(fromTo) * playArea.rotation;
|
||||||
|
|
||||||
@ -170,6 +202,20 @@ namespace NomaiVR.Player
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Override vanilla input handling for disabling turning while snap turning is enabled
|
||||||
|
private static void PostGetAxisValue(ref Vector2 __result, IInputCommands command, InputMode mask)
|
||||||
|
{
|
||||||
|
if (!ModSettings.SnapTurning || (OWInput.GetInputMode() != InputMode.Character))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.CommandType == InputConsts.InputCommandType.LOOK)
|
||||||
|
{
|
||||||
|
__result = Vector2.zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static bool PatchOwCameraFOV(OWCamera __instance)
|
private static bool PatchOwCameraFOV(OWCamera __instance)
|
||||||
{
|
{
|
||||||
//Prevents changing the fov of VR cameras
|
//Prevents changing the fov of VR cameras
|
||||||
@ -183,6 +229,25 @@ namespace NomaiVR.Player
|
|||||||
if (__instance.mainCamera.stereoEnabled) __result = CameraHelper.GetScaledFieldOfView(__instance.mainCamera);
|
if (__instance.mainCamera.stereoEnabled) __result = CameraHelper.GetScaledFieldOfView(__instance.mainCamera);
|
||||||
return !__instance.mainCamera.stereoEnabled;
|
return !__instance.mainCamera.stereoEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static float GetSnapTurnIncrement()
|
||||||
|
{
|
||||||
|
switch(ModSettings.SnapTurnIncrement)
|
||||||
|
{
|
||||||
|
case "15":
|
||||||
|
return 15f;
|
||||||
|
case "30":
|
||||||
|
return 30f;
|
||||||
|
case "45":
|
||||||
|
return 45f;
|
||||||
|
case "60":
|
||||||
|
return 60f;
|
||||||
|
case "90":
|
||||||
|
return 90f;
|
||||||
|
default:
|
||||||
|
return 45f;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using NomaiVR.ModConfig;
|
using NomaiVR.ModConfig;
|
||||||
|
using NomaiVR.Player;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace NomaiVR.UI
|
namespace NomaiVR.UI
|
||||||
@ -8,19 +9,22 @@ namespace NomaiVR.UI
|
|||||||
private Quaternion lastFrameRotation;
|
private Quaternion lastFrameRotation;
|
||||||
private const float speed = 0.5f;
|
private const float speed = 0.5f;
|
||||||
private bool smoothEnabled = true;
|
private bool smoothEnabled = true;
|
||||||
|
private bool snapEnabled = false;
|
||||||
|
private bool snapTurnedLastFrame = false;
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
lastFrameRotation = transform.rotation;
|
lastFrameRotation = transform.rotation;
|
||||||
|
|
||||||
SetSmoothEnabled();
|
RefreshEnabledSettings();
|
||||||
|
|
||||||
ModSettings.OnConfigChange += SetSmoothEnabled;
|
ModSettings.OnConfigChange += RefreshEnabledSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
ModSettings.OnConfigChange -= SetSmoothEnabled;
|
ModSettings.OnConfigChange -= RefreshEnabledSettings;
|
||||||
|
PlayerBodyPosition.Behaviour.OnSnapTurn -= OnSnapTurn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LateUpdate()
|
private void LateUpdate()
|
||||||
@ -32,23 +36,41 @@ namespace NomaiVR.UI
|
|||||||
|
|
||||||
var targetRotation = Camera.main.transform.rotation;
|
var targetRotation = Camera.main.transform.rotation;
|
||||||
|
|
||||||
if (smoothEnabled)
|
if (!smoothEnabled)
|
||||||
|
{
|
||||||
|
transform.rotation = targetRotation;
|
||||||
|
}
|
||||||
|
else if (snapEnabled && snapTurnedLastFrame)
|
||||||
|
{
|
||||||
|
snapTurnedLastFrame = false;
|
||||||
|
transform.rotation = targetRotation;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
var difference = Mathf.Abs(Quaternion.Angle(lastFrameRotation, targetRotation));
|
var difference = Mathf.Abs(Quaternion.Angle(lastFrameRotation, targetRotation));
|
||||||
var step = speed * Time.unscaledDeltaTime * difference * difference;
|
var step = speed * Time.unscaledDeltaTime * difference * difference;
|
||||||
transform.rotation = Quaternion.RotateTowards(lastFrameRotation, targetRotation, step);
|
transform.rotation = Quaternion.RotateTowards(lastFrameRotation, targetRotation, step);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
transform.rotation = targetRotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastFrameRotation = transform.rotation;
|
lastFrameRotation = transform.rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetSmoothEnabled()
|
private void RefreshEnabledSettings()
|
||||||
{
|
{
|
||||||
smoothEnabled = ModSettings.HudSmoothFollow;
|
smoothEnabled = ModSettings.HudSmoothFollow;
|
||||||
|
snapEnabled = ModSettings.SnapTurning;
|
||||||
|
|
||||||
|
PlayerBodyPosition.Behaviour.OnSnapTurn -= OnSnapTurn;
|
||||||
|
|
||||||
|
if (snapEnabled)
|
||||||
|
{
|
||||||
|
PlayerBodyPosition.Behaviour.OnSnapTurn += OnSnapTurn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSnapTurn()
|
||||||
|
{
|
||||||
|
snapTurnedLastFrame = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user