2025-12-01 16:30:54 +00:00
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.InputSystem;
|
|
|
|
|
|
|
|
|
|
public class PlayerController : MonoBehaviour
|
|
|
|
|
{
|
|
|
|
|
[Header("Movement")]
|
|
|
|
|
public float moveSpeed = 5f;
|
|
|
|
|
public float mouseSensitivity = 15f;
|
|
|
|
|
|
|
|
|
|
[Header("Interaction")]
|
|
|
|
|
public float interactionDistance = 3f;
|
|
|
|
|
public LayerMask interactionLayer;
|
|
|
|
|
|
|
|
|
|
private CharacterController controller;
|
|
|
|
|
private Transform cameraTransform;
|
|
|
|
|
private float verticalRotation = 0f;
|
|
|
|
|
|
|
|
|
|
// Reference to the generated C# class
|
|
|
|
|
private InputSystem_Actions inputActions;
|
|
|
|
|
private Vector2 moveInput;
|
|
|
|
|
private Vector2 lookInput;
|
|
|
|
|
|
|
|
|
|
void Awake()
|
|
|
|
|
{
|
|
|
|
|
inputActions = new InputSystem_Actions();
|
|
|
|
|
controller = GetComponent<CharacterController>();
|
|
|
|
|
cameraTransform = Camera.main.transform;
|
|
|
|
|
|
2025-12-02 17:13:58 +00:00
|
|
|
// Lock cursor so it doesn't leave the window
|
2025-12-01 16:30:54 +00:00
|
|
|
Cursor.lockState = CursorLockMode.Locked;
|
|
|
|
|
Cursor.visible = false;
|
|
|
|
|
|
2025-12-02 17:13:58 +00:00
|
|
|
// --- INPUT BINDINGS ---
|
|
|
|
|
|
|
|
|
|
// 1. Movement (WASD)
|
2025-12-01 16:30:54 +00:00
|
|
|
inputActions.Player.Move.performed += ctx => moveInput = ctx.ReadValue<Vector2>();
|
|
|
|
|
inputActions.Player.Move.canceled += ctx => moveInput = Vector2.zero;
|
|
|
|
|
|
2025-12-02 17:13:58 +00:00
|
|
|
// 2. Looking (Mouse)
|
2025-12-01 16:30:54 +00:00
|
|
|
inputActions.Player.Look.performed += ctx => lookInput = ctx.ReadValue<Vector2>();
|
|
|
|
|
inputActions.Player.Look.canceled += ctx => lookInput = Vector2.zero;
|
|
|
|
|
|
2025-12-02 17:13:58 +00:00
|
|
|
// 3. Interaction (The "E" Key)
|
|
|
|
|
// This listens strictly for the button press.
|
|
|
|
|
// It does NOT trigger on collision.
|
2025-12-01 16:30:54 +00:00
|
|
|
inputActions.Player.Interact.performed += ctx => TryInteract();
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 17:13:58 +00:00
|
|
|
void OnEnable() => inputActions.Enable();
|
|
|
|
|
void OnDisable() => inputActions.Disable();
|
|
|
|
|
|
|
|
|
|
void Update()
|
2025-12-01 16:30:54 +00:00
|
|
|
{
|
2025-12-02 17:13:58 +00:00
|
|
|
HandleMovement();
|
|
|
|
|
HandleLook();
|
|
|
|
|
UpdateInteractionUI(); // Only updates the text, does not flip switches
|
2025-12-01 16:30:54 +00:00
|
|
|
}
|
|
|
|
|
|
2025-12-02 17:13:58 +00:00
|
|
|
void HandleMovement()
|
2025-12-01 16:30:54 +00:00
|
|
|
{
|
2025-12-02 17:13:58 +00:00
|
|
|
Vector3 move = transform.right * moveInput.x + transform.forward * moveInput.y;
|
|
|
|
|
controller.Move(move * moveSpeed * Time.deltaTime);
|
2025-12-01 16:30:54 +00:00
|
|
|
}
|
|
|
|
|
|
2025-12-02 17:13:58 +00:00
|
|
|
void HandleLook()
|
2025-12-01 16:30:54 +00:00
|
|
|
{
|
2025-12-02 17:13:58 +00:00
|
|
|
float mouseX = lookInput.x * mouseSensitivity * Time.deltaTime;
|
|
|
|
|
float mouseY = lookInput.y * mouseSensitivity * Time.deltaTime;
|
|
|
|
|
|
|
|
|
|
verticalRotation -= mouseY;
|
|
|
|
|
verticalRotation = Mathf.Clamp(verticalRotation, -90f, 90f);
|
|
|
|
|
|
|
|
|
|
cameraTransform.localRotation = Quaternion.Euler(verticalRotation, 0f, 0f);
|
|
|
|
|
transform.Rotate(Vector3.up * mouseX);
|
2025-12-01 16:30:54 +00:00
|
|
|
}
|
2025-12-02 17:13:58 +00:00
|
|
|
|
|
|
|
|
// --- INTERACTION LOGIC ---
|
|
|
|
|
|
|
|
|
|
// This checks what we are looking at to update the screen text (e.g. "Turn On")
|
|
|
|
|
void UpdateInteractionUI()
|
2025-12-01 16:30:54 +00:00
|
|
|
{
|
|
|
|
|
Ray ray = new Ray(cameraTransform.position, cameraTransform.forward);
|
|
|
|
|
RaycastHit hit;
|
|
|
|
|
|
|
|
|
|
if (Physics.Raycast(ray, out hit, interactionDistance, interactionLayer))
|
|
|
|
|
{
|
|
|
|
|
IInteractable interactable = hit.collider.GetComponent<IInteractable>();
|
2025-12-02 17:13:58 +00:00
|
|
|
if (interactable != null && InteractionUI.Instance != null)
|
2025-12-01 16:30:54 +00:00
|
|
|
{
|
2025-12-02 17:13:58 +00:00
|
|
|
InteractionUI.Instance.UpdatePrompt(interactable.GetDescription());
|
2025-12-01 16:30:54 +00:00
|
|
|
}
|
2025-12-02 17:13:58 +00:00
|
|
|
else if (InteractionUI.Instance != null)
|
2025-12-01 16:30:54 +00:00
|
|
|
{
|
2025-12-02 17:13:58 +00:00
|
|
|
InteractionUI.Instance.ClearPrompt();
|
2025-12-01 16:30:54 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (InteractionUI.Instance != null) InteractionUI.Instance.ClearPrompt();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 17:13:58 +00:00
|
|
|
// This is ONLY called when 'E' is pressed.
|
2025-12-01 16:30:54 +00:00
|
|
|
void TryInteract()
|
|
|
|
|
{
|
|
|
|
|
Ray ray = new Ray(cameraTransform.position, cameraTransform.forward);
|
|
|
|
|
RaycastHit hit;
|
|
|
|
|
|
2025-12-02 17:13:58 +00:00
|
|
|
// Fire a raycast forward
|
2025-12-01 16:30:54 +00:00
|
|
|
if (Physics.Raycast(ray, out hit, interactionDistance, interactionLayer))
|
|
|
|
|
{
|
2025-12-02 17:13:58 +00:00
|
|
|
// Did we hit something with the IInteractable script?
|
2025-12-01 16:30:54 +00:00
|
|
|
IInteractable interactable = hit.collider.GetComponent<IInteractable>();
|
2025-12-02 17:13:58 +00:00
|
|
|
|
2025-12-01 16:30:54 +00:00
|
|
|
if (interactable != null)
|
|
|
|
|
{
|
2025-12-02 17:13:58 +00:00
|
|
|
// If yes, execute the code (Flip the switch)
|
2025-12-01 16:30:54 +00:00
|
|
|
interactable.Interact();
|
2025-12-02 17:13:58 +00:00
|
|
|
|
|
|
|
|
// Immediately update the UI text so it switches from "Turn Off" to "Turn On" instantly
|
|
|
|
|
if (InteractionUI.Instance != null)
|
|
|
|
|
InteractionUI.Instance.UpdatePrompt(interactable.GetDescription());
|
2025-12-01 16:30:54 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|