476 lines
18 KiB
C#
476 lines
18 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using Cielonos.MainGame.Inventory;
|
||
using Cielonos.MainGame.UI;
|
||
using Sirenix.OdinInspector;
|
||
using SLSUtilities.UI;
|
||
using UniRx;
|
||
using Unity.Cinemachine;
|
||
using UnityEngine;
|
||
using UnityEngine.Events;
|
||
using UnityEngine.InputSystem;
|
||
using UnityEngine.SceneManagement;
|
||
using UnityEngine.Serialization;
|
||
|
||
namespace Cielonos.MainGame.Characters
|
||
{
|
||
[RequireComponent(typeof(Player))]
|
||
public partial class PlayerInputSubcontroller : SubcontrollerBase<Player>
|
||
{
|
||
public Player player => owner;
|
||
public PlayerInput playerInput;
|
||
public PlayerInputActions inputActions;
|
||
public PlayerOperationSubcontroller operation;
|
||
public Vector2 Move { get; private set; }
|
||
public Vector2 Look { get; private set; }
|
||
public bool JumpPressed { get; private set; }
|
||
public bool JumpHeld { get; private set; }
|
||
public bool IsMoving => Move != Vector2.zero;
|
||
public bool IsWalking { get; private set; }
|
||
public string CurrentScheme => playerInput.currentControlScheme;
|
||
|
||
[ShowInInspector] public bool IsHoldingPrimary { get; private set; }
|
||
[ShowInInspector] public bool IsHoldingSecondary { get; private set; }
|
||
[ShowInInspector] public bool IsHoldingSpecialA { get; private set; }
|
||
[ShowInInspector] public bool IsHoldingSpecialB { get; private set; }
|
||
[ShowInInspector] public bool IsHoldingSpecialC { get; private set; }
|
||
|
||
public BoolReactiveProperty isCursorLocked;
|
||
|
||
public PlayerPreinputSubmodule preinputSubmodule;
|
||
|
||
public override void Initialize()
|
||
{
|
||
base.Initialize();
|
||
playerInput = owner.GetComponent<PlayerInput>();
|
||
inputActions = new PlayerInputActions();
|
||
inputActions.Player.Enable();
|
||
operation = owner.operationSc;
|
||
|
||
isCursorLocked = new BoolReactiveProperty(true);
|
||
isCursorLocked.Subscribe(isLocked =>
|
||
{
|
||
Cursor.lockState = isLocked ? CursorLockMode.Locked : CursorLockMode.None;
|
||
Cursor.visible = !isLocked;
|
||
Look = Vector2.zero;
|
||
Move = Vector2.zero;
|
||
|
||
// 同步禁用 Cinemachine 的自有输入控制器,防止 UI 打开时视角继续转动
|
||
var cinemachineInput = player.viewSc.freeLookCamera.GetComponent<CinemachineInputAxisController>();
|
||
cinemachineInput.enabled = isLocked;
|
||
});
|
||
|
||
player.inputSc.isCursorLocked.Value = false;
|
||
preinputSubmodule = new PlayerPreinputSubmodule(this);
|
||
|
||
InputBindingResolver.Initialize(inputActions.asset, "KeyboardMouse");
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
RegisterActionsInputs();
|
||
RegisterMainWeaponInputs();
|
||
RegisterSupportEquipmentInputs();
|
||
RegisterFunctionInputs();
|
||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||
}
|
||
|
||
|
||
private void Update()
|
||
{
|
||
if (isCursorLocked.Value)
|
||
{
|
||
Look = inputActions.Player.Look.ReadValue<Vector2>();
|
||
Move = inputActions.Player.Move.ReadValue<Vector2>().normalized;
|
||
JumpPressed = inputActions.Player.Jump.WasPressedThisFrame();
|
||
JumpHeld = inputActions.Player.Jump.IsPressed();
|
||
}
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
inputActions.Disable();
|
||
inputActions.Dispose();
|
||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||
}
|
||
}
|
||
|
||
public partial class PlayerInputSubcontroller
|
||
{
|
||
private void RegisterActionsInputs()
|
||
{
|
||
inputActions.Player.Interact.performed += ctx =>
|
||
{
|
||
if (ctx.performed && isCursorLocked.Value)
|
||
{
|
||
operation.Interact();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.Dash.performed += ctx =>
|
||
{
|
||
if (ctx.performed && isCursorLocked.Value)
|
||
{
|
||
if (IsMoving)
|
||
{
|
||
Vector3 inputDirection = new Vector3(Move.x, 0, Move.y);
|
||
operation.Dash(inputDirection);
|
||
preinputSubmodule.RegisterPreinputAction(() => operation.Dash(inputDirection),
|
||
PlayerPreinputSubmodule.DashDodgePreinputPriority);
|
||
}
|
||
else
|
||
{
|
||
operation.Dodge();
|
||
preinputSubmodule.RegisterPreinputAction(() => operation.Dodge(),
|
||
PlayerPreinputSubmodule.DashDodgePreinputPriority);
|
||
}
|
||
}
|
||
};
|
||
|
||
inputActions.Player.LockonTarget.performed += ctx =>
|
||
{
|
||
if (ctx.performed && isCursorLocked.Value)
|
||
{
|
||
operation.LockonTarget();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.SelectLockonTarget.performed += ctx =>
|
||
{
|
||
if (ctx.performed && isCursorLocked.Value)
|
||
{
|
||
//Debug.Log("Value: " + ctx.ReadValue<float>());
|
||
operation.SelectLockonTarget(ctx.ReadValue<float>());
|
||
}
|
||
};
|
||
|
||
inputActions.Player.Walk.performed += ctx =>
|
||
{
|
||
if (ctx.performed && isCursorLocked.Value)
|
||
{
|
||
IsWalking = true;
|
||
operation.WalkPress();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.Walk.canceled += ctx =>
|
||
{
|
||
if (ctx.canceled && isCursorLocked.Value)
|
||
{
|
||
IsWalking = false;
|
||
operation.WalkRelease();
|
||
}
|
||
};
|
||
|
||
// 交互选项导航:滚轮向上 / ↑ = -1(向上),滚轮向下 / ↓ = +1(向下)
|
||
// PassThrough + Axis 类型在松手/滚轮归零时也会触发 performed(raw = 0),需过滤
|
||
inputActions.Player.NavigateInteractionChoice.performed += ctx =>
|
||
{
|
||
if (isCursorLocked.Value)
|
||
{
|
||
float raw = ctx.ReadValue<float>();
|
||
if (Mathf.Approximately(raw, 0f)) return;
|
||
int delta = raw > 0f ? -1 : 1;
|
||
operation.NavigateInteractionChoice(delta);
|
||
}
|
||
};
|
||
}
|
||
|
||
private MainWeaponBase currentMainWeapon => player.inventorySc.equipmentSm.currentMainWeapon;
|
||
|
||
private List<PlayerInputModifierType> CaptureModifiers()
|
||
{
|
||
return InputModifier.Capture(IsHoldingSpecialA, IsHoldingSpecialB, IsHoldingSpecialC);
|
||
}
|
||
|
||
private void RegisterMainWeaponPreinput(PlayerEquipmentInputType inputType, List<PlayerInputModifierType> modifiers, Action action)
|
||
{
|
||
if (currentMainWeapon == null) return;
|
||
var context = new PlayerEquipmentInputContext(inputType, modifiers);
|
||
if (currentMainWeapon.TryGetPreinputPriority(context, out int priority))
|
||
{
|
||
preinputSubmodule.RegisterPreinputAction(inputType.ToString(), action, priority);
|
||
}
|
||
}
|
||
|
||
private void RegisterSupportEquipmentPreinput(int slotIndex, List<PlayerInputModifierType> modifiers, Action action)
|
||
{
|
||
SupportEquipmentBase equipment = GetSupportEquipment(slotIndex);
|
||
if (equipment == null) return;
|
||
PlayerEquipmentInputType inputType = slotIndex switch
|
||
{
|
||
0 => PlayerEquipmentInputType.SupportEquipment0,
|
||
1 => PlayerEquipmentInputType.SupportEquipment1,
|
||
2 => PlayerEquipmentInputType.SupportEquipment2,
|
||
3 => PlayerEquipmentInputType.SupportEquipment3,
|
||
_ => throw new ArgumentOutOfRangeException(nameof(slotIndex), slotIndex, null)
|
||
};
|
||
var context = new PlayerEquipmentInputContext(inputType, modifiers, slotIndex);
|
||
if (equipment.TryGetPreinputPriority(context, out int priority))
|
||
{
|
||
preinputSubmodule.RegisterPreinputAction(inputType.ToString(), action, priority);
|
||
}
|
||
}
|
||
|
||
private SupportEquipmentBase GetSupportEquipment(int slotIndex)
|
||
{
|
||
var equipments = player.inventorySc.equipmentSm.currentSupportEquipments;
|
||
return equipments.Count > slotIndex ? equipments[slotIndex] : null;
|
||
}
|
||
|
||
private void RegisterMainWeaponInputs()
|
||
{
|
||
inputActions.Player.MainWeaponPrimary.started += ctx =>
|
||
{
|
||
if (ctx.started && isCursorLocked.Value)
|
||
{
|
||
IsHoldingPrimary = true;
|
||
List<PlayerInputModifierType> modifiers = CaptureModifiers();
|
||
operation.MainWeaponPrimaryPress(modifiers);
|
||
RegisterMainWeaponPreinput(PlayerEquipmentInputType.MainWeaponPrimary, modifiers,
|
||
() => operation.MainWeaponPrimaryPress(modifiers));
|
||
}
|
||
};
|
||
inputActions.Player.MainWeaponPrimary.canceled += ctx =>
|
||
{
|
||
if (ctx.canceled && isCursorLocked.Value)
|
||
{
|
||
IsHoldingPrimary = false;
|
||
operation.MainWeaponPrimaryRelease();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.MainWeaponSecondary.started += ctx =>
|
||
{
|
||
if (ctx.started && isCursorLocked.Value)
|
||
{
|
||
IsHoldingSecondary = true;
|
||
List<PlayerInputModifierType> modifiers = CaptureModifiers();
|
||
operation.MainWeaponSecondaryPress(modifiers);
|
||
RegisterMainWeaponPreinput(PlayerEquipmentInputType.MainWeaponSecondary, modifiers,
|
||
() => operation.MainWeaponSecondaryPress(modifiers));
|
||
}
|
||
};
|
||
inputActions.Player.MainWeaponSecondary.canceled += ctx =>
|
||
{
|
||
if (ctx.canceled && isCursorLocked.Value)
|
||
{
|
||
IsHoldingSecondary = false;
|
||
operation.MainWeaponSecondaryRelease();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.MainWeaponSpecialA.started += ctx =>
|
||
{
|
||
if (ctx.started && isCursorLocked.Value)
|
||
{
|
||
IsHoldingSpecialA = true;
|
||
List<PlayerInputModifierType> modifiers = CaptureModifiers();
|
||
operation.MainWeaponSpecialAPress(modifiers);
|
||
RegisterMainWeaponPreinput(PlayerEquipmentInputType.MainWeaponSpecialA, modifiers,
|
||
() => operation.MainWeaponSpecialAPress(modifiers));
|
||
}
|
||
};
|
||
inputActions.Player.MainWeaponSpecialA.canceled += ctx =>
|
||
{
|
||
if (ctx.canceled && isCursorLocked.Value)
|
||
{
|
||
IsHoldingSpecialA = false;
|
||
operation.MainWeaponSpecialARelease();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.MainWeaponSpecialB.started += ctx =>
|
||
{
|
||
if (ctx.started && isCursorLocked.Value)
|
||
{
|
||
IsHoldingSpecialB = true;
|
||
List<PlayerInputModifierType> modifiers = CaptureModifiers();
|
||
operation.MainWeaponSpecialBPress(modifiers);
|
||
RegisterMainWeaponPreinput(PlayerEquipmentInputType.MainWeaponSpecialB, modifiers,
|
||
() => operation.MainWeaponSpecialBPress(modifiers));
|
||
}
|
||
};
|
||
inputActions.Player.MainWeaponSpecialB.canceled += ctx =>
|
||
{
|
||
if (ctx.canceled && isCursorLocked.Value)
|
||
{
|
||
IsHoldingSpecialB = false;
|
||
operation.MainWeaponSpecialBRelease();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.MainWeaponSpecialC.started += ctx =>
|
||
{
|
||
if (ctx.started && isCursorLocked.Value)
|
||
{
|
||
IsHoldingSpecialC = true;
|
||
List<PlayerInputModifierType> modifiers = CaptureModifiers();
|
||
operation.MainWeaponSpecialCPress(modifiers);
|
||
RegisterMainWeaponPreinput(PlayerEquipmentInputType.MainWeaponSpecialC, modifiers,
|
||
() => operation.MainWeaponSpecialCPress(modifiers));
|
||
}
|
||
};
|
||
inputActions.Player.MainWeaponSpecialC.canceled += ctx =>
|
||
{
|
||
if (ctx.canceled && isCursorLocked.Value)
|
||
{
|
||
IsHoldingSpecialC = false;
|
||
operation.MainWeaponSpecialCRelease();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.SwitchPreviousMainWeapon.performed += ctx =>
|
||
{
|
||
if (ctx.performed && isCursorLocked.Value)
|
||
{
|
||
operation.SwitchMainWeapon(-1);
|
||
}
|
||
};
|
||
|
||
inputActions.Player.SwitchNextMainWeapon.performed += ctx =>
|
||
{
|
||
if (ctx.performed && isCursorLocked.Value)
|
||
{
|
||
operation.SwitchMainWeapon(1);
|
||
}
|
||
};
|
||
|
||
inputActions.Player.RouletteSwitchMainWeapon.performed += ctx =>
|
||
{
|
||
if (ctx.performed && isCursorLocked.Value)
|
||
{
|
||
operation.OpenMainWeaponRoulette();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.RouletteSwitchMainWeapon.canceled += ctx =>
|
||
{
|
||
if (ctx.canceled)
|
||
{
|
||
operation.CloseMainWeaponRoulette();
|
||
}
|
||
};
|
||
}
|
||
|
||
private void RegisterSupportEquipmentInputs()
|
||
{
|
||
inputActions.Player.SupportEquipment0.performed += ctx =>
|
||
{
|
||
if (ctx.performed && isCursorLocked.Value)
|
||
{
|
||
List<PlayerInputModifierType> modifiers = CaptureModifiers();
|
||
operation.SupportEquipment0Press(modifiers);
|
||
RegisterSupportEquipmentPreinput(0, modifiers, () => operation.SupportEquipment0Press(modifiers));
|
||
}
|
||
};
|
||
|
||
inputActions.Player.SupportEquipment0.canceled += ctx =>
|
||
{
|
||
if (ctx.canceled && isCursorLocked.Value)
|
||
{
|
||
operation.SupportEquipment0Release();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.SupportEquipment1.performed += ctx =>
|
||
{
|
||
if (ctx.performed && isCursorLocked.Value)
|
||
{
|
||
List<PlayerInputModifierType> modifiers = CaptureModifiers();
|
||
operation.SupportEquipment1Press(modifiers);
|
||
RegisterSupportEquipmentPreinput(1, modifiers, () => operation.SupportEquipment1Press(modifiers));
|
||
}
|
||
};
|
||
|
||
inputActions.Player.SupportEquipment1.canceled += ctx =>
|
||
{
|
||
if (ctx.canceled && isCursorLocked.Value)
|
||
{
|
||
operation.SupportEquipment1Release();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.SupportEquipment2.performed += ctx =>
|
||
{
|
||
if (ctx.performed && isCursorLocked.Value)
|
||
{
|
||
List<PlayerInputModifierType> modifiers = CaptureModifiers();
|
||
operation.SupportEquipment2Press(modifiers);
|
||
RegisterSupportEquipmentPreinput(2, modifiers, () => operation.SupportEquipment2Press(modifiers));
|
||
}
|
||
};
|
||
|
||
inputActions.Player.SupportEquipment2.canceled += ctx =>
|
||
{
|
||
if (ctx.canceled && isCursorLocked.Value)
|
||
{
|
||
operation.SupportEquipment2Release();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.SupportEquipment3.performed += ctx =>
|
||
{
|
||
if (ctx.performed && isCursorLocked.Value)
|
||
{
|
||
List<PlayerInputModifierType> modifiers = CaptureModifiers();
|
||
operation.SupportEquipment3Press(modifiers);
|
||
RegisterSupportEquipmentPreinput(3, modifiers, () => operation.SupportEquipment3Press(modifiers));
|
||
}
|
||
};
|
||
|
||
inputActions.Player.SupportEquipment3.canceled += ctx =>
|
||
{
|
||
if (ctx.canceled && isCursorLocked.Value)
|
||
{
|
||
operation.SupportEquipment3Release();
|
||
}
|
||
};
|
||
}
|
||
|
||
private void RegisterFunctionInputs()
|
||
{
|
||
inputActions.Player.Inventory.performed += ctx =>
|
||
{
|
||
var inventoryPage = PlayerCanvas.MainGamePages.inventoryPage;
|
||
if (inventoryPage.IsOpen)
|
||
{
|
||
inventoryPage.Close();
|
||
}
|
||
else
|
||
{
|
||
inventoryPage.Open();
|
||
}
|
||
};
|
||
|
||
inputActions.Player.Map.performed += ctx =>
|
||
{
|
||
var mapPage = PlayerCanvas.MainGamePages.mapPage;
|
||
if (mapPage.IsOpen) mapPage.Close();
|
||
else mapPage.Open();
|
||
};
|
||
|
||
inputActions.Player.Escape.performed += ctx =>
|
||
{
|
||
// 优先关闭栈顶页面(包括 Settings 覆盖在 Pause 之上的情况)
|
||
if (UIPageManager.Instance != null && UIPageManager.Instance.HasOpenPages)
|
||
{
|
||
UIPageManager.Instance.CloseTopPage();
|
||
}
|
||
else
|
||
{
|
||
PlayerCanvas.PauseUIPage.Open();
|
||
}
|
||
};
|
||
}
|
||
}
|
||
|
||
public partial class PlayerInputSubcontroller
|
||
{
|
||
private void OnSceneLoaded(Scene a, LoadSceneMode b)
|
||
{
|
||
isCursorLocked.Value = true;
|
||
}
|
||
}
|
||
}
|