自写输入系统
This commit is contained in:
@@ -13,10 +13,21 @@ namespace NBF
|
||||
_rigidbody = GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
// BindPosition();
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (!target) return;
|
||||
_rigidbody.MovePosition(target.position);
|
||||
BindPosition();
|
||||
}
|
||||
|
||||
private void BindPosition()
|
||||
{
|
||||
// _rigidbody.MovePosition(target.position);
|
||||
_rigidbody.position = target.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
using System;
|
||||
using RootMotion.FinalIK;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
[RequireComponent(typeof(CharacterController))]
|
||||
public class SmoothFPSController : MonoBehaviour
|
||||
{
|
||||
public enum ControlMode
|
||||
{
|
||||
LocalPlayer, // 本地玩家,接受输入控制
|
||||
NetworkPlayer // 网络玩家,接受数据驱动
|
||||
}
|
||||
|
||||
[Header("Control Settings")] public ControlMode controlMode = ControlMode.LocalPlayer;
|
||||
[Range(0.1f, 10f)] public float lookSensitivity = 2f;
|
||||
[Range(0f, 0.5f)] public float lookSmoothing = 0.1f;
|
||||
[Range(0.1f, 10f)] public float moveSpeed = 5f;
|
||||
public float jumpHeight = 2f;
|
||||
public float gravity = -9.81f;
|
||||
|
||||
[Header("Components")] public CharacterController characterController;
|
||||
public Transform cameraTransform;
|
||||
|
||||
// 物理状态
|
||||
private Vector3 velocity;
|
||||
private bool isGrounded;
|
||||
|
||||
// 视角控制变量
|
||||
private Vector2 currentLookInput;
|
||||
private Vector2 smoothedLookInput;
|
||||
private Vector2 lookVelocity;
|
||||
private float xRotation = 0f;
|
||||
|
||||
// 移动控制变量
|
||||
private Vector2 currentMoveInput;
|
||||
private bool currentJumpInput;
|
||||
|
||||
// 网络同步数据
|
||||
// private Vector3 targetPosition;
|
||||
// private Quaternion targetRotation;
|
||||
private float positionLerpSpeed = 10f;
|
||||
private float rotationLerpSpeed = 5f;
|
||||
|
||||
|
||||
public bool IsSelf;
|
||||
|
||||
private FPlayer _player;
|
||||
public LookAtIK lookAtIK; // 挂在背部上的 LookAtIK 脚本
|
||||
|
||||
private Transform lookTarget; // 实际目标点
|
||||
[Header("限制角度(单位:度)")] public float maxUpAngle = 20f; // 相机抬头最多20°
|
||||
public float maxDownAngle = 40f; // 相机低头最多40°
|
||||
public float aimDistance = 1.5f; // 目标点离相机多远
|
||||
|
||||
[HideInInspector] public int nextShowSlotIndex = -1;
|
||||
|
||||
public LayerMask interactableLayer;
|
||||
|
||||
public Rigidbody physicsBody; // 用于物理同步的Rigidbody
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (characterController == null)
|
||||
characterController = GetComponent<CharacterController>();
|
||||
|
||||
interactableLayer = LayerMask.GetMask("Interactive");
|
||||
physicsBody = GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
InputManager.OnPlayerCanceled += OnPlayerCanceled;
|
||||
InputManager.OnPlayerPerformed += OnPlayerPerformed;
|
||||
|
||||
lookAtIK = GetComponent<LookAtIK>();
|
||||
_player = GetComponent<FPlayer>();
|
||||
|
||||
if (IsSelf)
|
||||
{
|
||||
// camera = BaseCamera.Main;
|
||||
}
|
||||
|
||||
lookTarget = new GameObject("SpineLookTarget").transform;
|
||||
lookTarget.SetParent(_player.transform);
|
||||
|
||||
transform.position = _player.Data.position;
|
||||
transform.rotation = _player.Data.rotation;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
InputManager.OnPlayerCanceled -= OnPlayerCanceled;
|
||||
InputManager.OnPlayerPerformed -= OnPlayerPerformed;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (controlMode == ControlMode.LocalPlayer)
|
||||
{
|
||||
UpdateLocalPlayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateNetworkPlayer();
|
||||
}
|
||||
|
||||
UpdateGear();
|
||||
UpdatePlayerHandView();
|
||||
}
|
||||
|
||||
|
||||
private void GetInputs()
|
||||
{
|
||||
currentMoveInput = InputManager.GetMovementInput();
|
||||
currentLookInput = InputManager.GetLookInput();
|
||||
currentJumpInput = Keyboard.current.spaceKey.wasPressedThisFrame;
|
||||
}
|
||||
|
||||
|
||||
private void UpdatePlayerHandView()
|
||||
{
|
||||
Vector3 cameraForward = cameraTransform.forward;
|
||||
Vector3 flatForward = Vector3.ProjectOnPlane(cameraForward, Vector3.up).normalized;
|
||||
|
||||
// 获取相机 pitch 角度(负值是上看,正值是下看)
|
||||
float pitchAngle = Vector3.SignedAngle(flatForward, cameraForward, cameraTransform.right);
|
||||
|
||||
// 限制 pitch 角度
|
||||
pitchAngle = Mathf.Clamp(pitchAngle, -maxUpAngle, maxDownAngle);
|
||||
|
||||
// 重新构造限制后的目标方向
|
||||
Quaternion limitedPitch = Quaternion.AngleAxis(pitchAngle, cameraTransform.right);
|
||||
Vector3 limitedDirection = limitedPitch * flatForward;
|
||||
|
||||
// 设置目标点
|
||||
lookTarget.position = cameraTransform.position + limitedDirection * aimDistance;
|
||||
lookAtIK.solver.target = lookTarget;
|
||||
}
|
||||
|
||||
|
||||
#region 钓组控制
|
||||
|
||||
private void UpdateGear()
|
||||
{
|
||||
if (_player.CanChangeGear())
|
||||
{
|
||||
if (nextShowSlotIndex > 0)
|
||||
{
|
||||
Debug.LogError("切换钓组=========");
|
||||
var data = Fishing.Inst.Datasource;
|
||||
data.SetSelfTestGear(nextShowSlotIndex);
|
||||
nextShowSlotIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 按键输入事件
|
||||
|
||||
private void OnPlayerPerformed(string action)
|
||||
{
|
||||
if (action == "Run")
|
||||
{
|
||||
Sprint();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayerCanceled(string action)
|
||||
{
|
||||
if (action == "Run")
|
||||
{
|
||||
StopSprinting();
|
||||
}
|
||||
else if (action.StartsWith("Quick"))
|
||||
{
|
||||
nextShowSlotIndex = int.Parse(action.Substring("Quick".Length));
|
||||
}
|
||||
else if (action == "UseTorch")
|
||||
{
|
||||
_player.Data.openLight = !_player.Data.openLight;
|
||||
}
|
||||
else if (action == "UseTelescope")
|
||||
{
|
||||
_player.Data.openTelescope = !_player.Data.openTelescope;
|
||||
_player.ToggleTelescope();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 角色位移和旋转控制
|
||||
|
||||
private bool _isSprinting;
|
||||
private bool _sprintInputPressed;
|
||||
|
||||
[Space(10.0f)] public float maxSprintSpeed = 10.0f;
|
||||
|
||||
private void UpdateNetworkPlayer()
|
||||
{
|
||||
}
|
||||
|
||||
private void UpdateLocalPlayer()
|
||||
{
|
||||
// 获取输入
|
||||
GetInputs();
|
||||
|
||||
// 处理地面检测
|
||||
GroundCheck();
|
||||
|
||||
// 处理移动
|
||||
HandleMovement();
|
||||
|
||||
// 处理视角旋转(现在更加平滑)
|
||||
HandleLookRotation();
|
||||
|
||||
// 处理跳跃
|
||||
// HandleJump();
|
||||
|
||||
// 应用重力
|
||||
ApplyGravity();
|
||||
}
|
||||
|
||||
|
||||
private void GroundCheck()
|
||||
{
|
||||
isGrounded = characterController.isGrounded;
|
||||
if (isGrounded && velocity.y < 0)
|
||||
{
|
||||
velocity.y = -2f; // 轻微下压确保贴地
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleMovement()
|
||||
{
|
||||
Vector3 move = (transform.right * currentMoveInput.x + transform.forward * currentMoveInput.y) *
|
||||
GetMaxSpeed();
|
||||
characterController.Move(move * Time.deltaTime);
|
||||
// physicsBody.MovePosition(move * Time.deltaTime);
|
||||
// physicsBody.Move(move * Time.deltaTime, transform.rotation);
|
||||
// 手动同步CharacterController和物理位置
|
||||
if (physicsBody != null)
|
||||
{
|
||||
physicsBody.position = transform.position;
|
||||
physicsBody.rotation = transform.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleLookRotation()
|
||||
{
|
||||
// 应用输入平滑(使用平滑阻尼)
|
||||
smoothedLookInput = Vector2.SmoothDamp(
|
||||
smoothedLookInput,
|
||||
currentLookInput,
|
||||
ref lookVelocity,
|
||||
lookSmoothing);
|
||||
|
||||
// 计算旋转量(应用灵敏度)
|
||||
float lookX = smoothedLookInput.x * lookSensitivity * Time.deltaTime;
|
||||
float lookY = smoothedLookInput.y * lookSensitivity * Time.deltaTime;
|
||||
|
||||
// 水平旋转(左右看)
|
||||
// transform.Rotate(Vector3.up * lookX);
|
||||
|
||||
physicsBody.MoveRotation(physicsBody.rotation * Quaternion.Euler(0, lookX, 0));
|
||||
|
||||
// 垂直旋转(上下看) - 带有角度限制
|
||||
xRotation -= lookY;
|
||||
xRotation = Mathf.Clamp(xRotation, -45f, 80f); // 限制上下视角范围
|
||||
|
||||
// 应用摄像机旋转
|
||||
cameraTransform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
|
||||
}
|
||||
|
||||
private void HandleJump()
|
||||
{
|
||||
if (currentJumpInput && isGrounded)
|
||||
{
|
||||
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyGravity()
|
||||
{
|
||||
velocity.y += gravity * Time.deltaTime;
|
||||
characterController.Move(velocity * Time.deltaTime);
|
||||
}
|
||||
|
||||
|
||||
public void Sprint()
|
||||
{
|
||||
_sprintInputPressed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request the character to stop sprinting.
|
||||
/// </summary>
|
||||
public void StopSprinting()
|
||||
{
|
||||
_sprintInputPressed = false;
|
||||
}
|
||||
|
||||
private bool CanSprint()
|
||||
{
|
||||
return true;
|
||||
// return IsWalking() && !IsCrouched();
|
||||
}
|
||||
|
||||
|
||||
private void CheckSprintInput()
|
||||
{
|
||||
if (!_isSprinting && _sprintInputPressed && CanSprint())
|
||||
{
|
||||
_isSprinting = true;
|
||||
}
|
||||
else if (_isSprinting && (!_sprintInputPressed || !CanSprint()))
|
||||
{
|
||||
_isSprinting = false;
|
||||
}
|
||||
}
|
||||
|
||||
public float GetMaxSpeed()
|
||||
{
|
||||
return _isSprinting ? maxSprintSpeed : moveSpeed;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 606ee481d29f49f3a157a642d84c7e74
|
||||
timeCreated: 1748348937
|
||||
Reference in New Issue
Block a user