first commit
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
using OTGIntegrated.Stats;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OTGIntegrated.Player
|
||||
{
|
||||
[RequireComponent(typeof(CharacterController))]
|
||||
public sealed class PlayerController : MonoBehaviour
|
||||
{
|
||||
[Header("Movement")]
|
||||
[SerializeField] private float rotationSpeed = 12f;
|
||||
[SerializeField] private float gravity = -24f;
|
||||
|
||||
[Header("Camera")]
|
||||
public Transform cameraRoot;
|
||||
public Camera playerCamera;
|
||||
[SerializeField] private Vector3 cameraOffset = new Vector3(0f, 8.5f, -12.5f);
|
||||
[SerializeField] private float mouseSensitivity = 2.2f;
|
||||
|
||||
private CharacterController characterController;
|
||||
private PlayerStats playerStats;
|
||||
private Vector3 velocity;
|
||||
private float cameraYaw;
|
||||
private bool inputEnabled = true;
|
||||
|
||||
public bool InputEnabled => inputEnabled;
|
||||
|
||||
public void Initialize(PlayerStats stats)
|
||||
{
|
||||
playerStats = stats != null ? stats : GetComponent<PlayerStats>();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
characterController = GetComponent<CharacterController>();
|
||||
if (playerStats == null)
|
||||
{
|
||||
playerStats = GetComponent<PlayerStats>();
|
||||
}
|
||||
|
||||
if (playerCamera == null)
|
||||
{
|
||||
playerCamera = Camera.main;
|
||||
}
|
||||
|
||||
if (cameraRoot == null)
|
||||
{
|
||||
GameObject root = new GameObject("CameraRoot");
|
||||
cameraRoot = root.transform;
|
||||
cameraRoot.position = transform.position;
|
||||
}
|
||||
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
Cursor.visible = false;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!inputEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HandleCameraInput();
|
||||
HandleMovement();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
UpdateCamera();
|
||||
}
|
||||
|
||||
public void SetInputEnabled(bool enabled)
|
||||
{
|
||||
inputEnabled = enabled;
|
||||
if (!enabled)
|
||||
{
|
||||
velocity.x = 0f;
|
||||
velocity.z = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetAimForward()
|
||||
{
|
||||
Vector3 forward = playerCamera != null ? playerCamera.transform.forward : transform.forward;
|
||||
forward.y = 0f;
|
||||
return forward.sqrMagnitude > 0.001f ? forward.normalized : transform.forward;
|
||||
}
|
||||
|
||||
private void HandleCameraInput()
|
||||
{
|
||||
cameraYaw += Input.GetAxis("Mouse X") * mouseSensitivity;
|
||||
}
|
||||
|
||||
private void HandleMovement()
|
||||
{
|
||||
float horizontal = Input.GetAxisRaw("Horizontal");
|
||||
float vertical = Input.GetAxisRaw("Vertical");
|
||||
Vector3 input = new Vector3(horizontal, 0f, vertical);
|
||||
input = Vector3.ClampMagnitude(input, 1f);
|
||||
|
||||
Quaternion yawRotation = Quaternion.Euler(0f, cameraYaw, 0f);
|
||||
Vector3 move = yawRotation * input;
|
||||
float moveSpeed = playerStats != null ? playerStats.MoveSpeed : 5f;
|
||||
|
||||
if (move.sqrMagnitude > 0.001f)
|
||||
{
|
||||
Quaternion targetRotation = Quaternion.LookRotation(move, Vector3.up);
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
if (characterController.isGrounded && velocity.y < 0f)
|
||||
{
|
||||
velocity.y = -2f;
|
||||
}
|
||||
|
||||
velocity.y += gravity * Time.deltaTime;
|
||||
Vector3 motion = move * moveSpeed + Vector3.up * velocity.y;
|
||||
characterController.Move(motion * Time.deltaTime);
|
||||
}
|
||||
|
||||
private void UpdateCamera()
|
||||
{
|
||||
if (cameraRoot == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cameraRoot.position = transform.position;
|
||||
cameraRoot.rotation = Quaternion.Euler(0f, cameraYaw, 0f);
|
||||
|
||||
if (playerCamera != null)
|
||||
{
|
||||
Vector3 offset = Quaternion.Euler(0f, cameraYaw, 0f) * cameraOffset;
|
||||
playerCamera.transform.position = transform.position + offset;
|
||||
playerCamera.transform.LookAt(transform.position + Vector3.up * 1.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2e1e9d509df7e54aa12d3ba20855357
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,105 @@
|
||||
using OTGIntegrated.UI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OTGIntegrated.Player
|
||||
{
|
||||
public interface IInteractable
|
||||
{
|
||||
Transform InteractTransform { get; }
|
||||
string GetPrompt();
|
||||
bool CanInteract(GameObject interactor);
|
||||
void Interact(GameObject interactor);
|
||||
}
|
||||
|
||||
public sealed class PlayerInteraction : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private float interactionRadius = 2.6f;
|
||||
[SerializeField] private LayerMask interactionMask = ~0;
|
||||
public InteractionPromptUI promptUI;
|
||||
|
||||
private readonly Collider[] hits = new Collider[24];
|
||||
private PlayerController playerController;
|
||||
private IInteractable currentInteractable;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
playerController = GetComponent<PlayerController>();
|
||||
if (promptUI == null)
|
||||
{
|
||||
promptUI = FindObjectOfType<InteractionPromptUI>();
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (playerController != null && !playerController.InputEnabled)
|
||||
{
|
||||
SetCurrent(null);
|
||||
return;
|
||||
}
|
||||
|
||||
FindNearestInteractable();
|
||||
|
||||
if (currentInteractable != null && Input.GetKeyDown(KeyCode.E))
|
||||
{
|
||||
currentInteractable.Interact(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void FindNearestInteractable()
|
||||
{
|
||||
int count = Physics.OverlapSphereNonAlloc(transform.position, interactionRadius, hits, interactionMask, QueryTriggerInteraction.Collide);
|
||||
IInteractable nearest = null;
|
||||
float nearestDistance = float.MaxValue;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Collider hit = hits[i];
|
||||
if (hit == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IInteractable interactable = hit.GetComponentInParent<IInteractable>();
|
||||
if (interactable == null || !interactable.CanInteract(gameObject))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Transform interactTransform = interactable.InteractTransform != null ? interactable.InteractTransform : hit.transform;
|
||||
float distance = (interactTransform.position - transform.position).sqrMagnitude;
|
||||
if (distance < nearestDistance)
|
||||
{
|
||||
nearestDistance = distance;
|
||||
nearest = interactable;
|
||||
}
|
||||
}
|
||||
|
||||
SetCurrent(nearest);
|
||||
}
|
||||
|
||||
private void SetCurrent(IInteractable interactable)
|
||||
{
|
||||
currentInteractable = interactable;
|
||||
if (promptUI == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentInteractable == null)
|
||||
{
|
||||
promptUI.Hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
promptUI.Show(currentInteractable.GetPrompt());
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.color = new Color(1f, 0.75f, 0.2f, 0.25f);
|
||||
Gizmos.DrawSphere(transform.position, interactionRadius);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: def57f8de123682a59566f0e184ccdf3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user