using System.Collections; using Unity.VisualScripting.Antlr3.Runtime; using UnityEngine; using static UnityEngine.GraphicsBuffer; public class PlayerController : MonoBehaviour { public GameObject DougBody; public Tool[] tools; float toolUseTimestamp = 0; public float walkSpeed; public float sprintMultiplier = 1.5f; public float gravity = 10; Interactable nearestInteractable; public CameraController cameraController; private CharacterController characterController; private Vector3 moveDir; private bool hasControl = true; // set this to false if we want to stop reading player inputs private bool canUseTools = true; // set this to false if we want to stop reading player tool use private bool isSprinting = false; private bool paused = false; // Mathematical plane used to catch the raycast from camera to get direction for // looking at the mouse private Plane groundPlane; // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { groundPlane = new Plane(Vector3.up, -DougBody.transform.position.y); characterController = GetComponent(); cameraController = GetComponent(); SwitchTools(GameManager.Instance.PlayerManager.CurrentToolIndex); } // Update is called once per frame void Update() { moveDir = Vector3.zero; groundPlane.distance = -DougBody.transform.position.y; // TODO: Move input detection somewhere else if (Input.GetKeyDown(KeyCode.Escape)) { if (!paused) { Cursor.lockState = CursorLockMode.None; Time.timeScale = 0; canUseTools = false; hasControl = false; GameManager.Instance.MenuController.ShowScreen("Pause"); } else { Time.timeScale = 1; canUseTools = true; hasControl = true; GameManager.Instance.MenuController.HideAllScreens(); } paused = !paused; } if (hasControl) { if (!tools[GameManager.Instance.PlayerManager.CurrentToolIndex].inUse) { RotatePlayerTowardMouse(); TryInteract(); } CheckWeaponChange(); ApplyWalk(); } if (canUseTools) { ToolUseDetector(); } CheckSprint(); ApplyGravity(); DoMovement(); } /// /// Checks if shift is being held, isSprinting is true if it is /// private void CheckSprint() { if (Input.GetKey(KeyCode.LeftShift)) { isSprinting = true; } else { isSprinting = false; } } /// /// Checks if weapon is being switched by scroll wheel /// private void CheckWeaponChange() { if (Input.mouseScrollDelta.y > 0) { SwitchTools(true); } else if (Input.mouseScrollDelta.y < 0) { SwitchTools(false); } } /// /// Apply walking inputs to moveDir /// void ApplyWalk() { float verticalMovement = 0; float horizontalMovement = 0; if (!tools[GameManager.Instance.PlayerManager.CurrentToolIndex].inUse) { verticalMovement = Input.GetAxisRaw("Vertical"); horizontalMovement = Input.GetAxisRaw("Horizontal"); } moveDir = new Vector3(horizontalMovement, 0, verticalMovement).normalized; if (cameraController != null) { // re-matrix the rotation direction so movement is consistent no matter what // the camera rotation is Matrix4x4 matrix = Matrix4x4.Rotate(Quaternion.Euler(0, cameraController.playerCamHome.rotation.eulerAngles.y, 0)); moveDir = matrix.MultiplyPoint3x4(moveDir); } } /// /// Apply gravity and speed to moveDir /// void ApplyGravity() { if (isSprinting) moveDir *= (walkSpeed * sprintMultiplier); else moveDir *= walkSpeed; moveDir.y += -gravity; } /// /// Move character with moveDir /// void DoMovement() { characterController.Move(moveDir * Time.deltaTime); } /// /// Pass movement into character controller, lets us expose function without exposing /// whole char controller /// public void CharacterControllerMove(Vector3 movement) { characterController.Move(movement); } /// /// Auto-walk the character in the specified direction. Uses character's walk /// speed and camera rotation (per-frame) /// public void WalkInDirection(Vector3 direction) { Vector3 forwardDir = direction; forwardDir.y = 0; // don't move on the y axis forwardDir *= walkSpeed; characterController.Move(forwardDir * Time.deltaTime); } /// /// Detect input for tool use /// void ToolUseDetector() { if (!tools[GameManager.Instance.PlayerManager.CurrentToolIndex].inUse) { if (Input.GetMouseButtonDown(0)) { tools[GameManager.Instance.PlayerManager.CurrentToolIndex].Use(); tools[GameManager.Instance.PlayerManager.CurrentToolIndex].inUse = true; toolUseTimestamp = Time.time + tools[GameManager.Instance.PlayerManager.CurrentToolIndex].useTimeSec; // fuck coroutines fr fr } else if (Input.GetMouseButtonDown(1)) { tools[GameManager.Instance.PlayerManager.CurrentToolIndex].UseAlt(); tools[GameManager.Instance.PlayerManager.CurrentToolIndex].inUse = true; toolUseTimestamp = Time.time + tools[GameManager.Instance.PlayerManager.CurrentToolIndex].altUseTimeSec; } } else { if (Time.time > toolUseTimestamp) { tools[GameManager.Instance.PlayerManager.CurrentToolIndex].inUse = false; } } } /// /// Face character graphic toward mouse /// void RotatePlayerTowardMouse() { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (groundPlane.Raycast(ray, out var distance)) { Vector3 hitPoint = ray.GetPoint(distance); DougBody.transform.LookAt(new Vector3(hitPoint.x, DougBody.transform.position.y, hitPoint.z)); } } /// /// Try to interact by detecting nearest interactable /// void TryInteract() { if (Input.GetKeyDown(KeyCode.E) && nearestInteractable != null) { nearestInteractable.Interact(); } } private void OnTriggerEnter(Collider other) { Interactable interactable = other.GetComponent(); // store nearest interactable if it exists if (interactable != null) { nearestInteractable = interactable; interactable.MoveInsideRange(); } } private void OnTriggerExit(Collider other) { // just null out interactables when we leave an interactable trigger (we cant and shouldn't overlap interactables) Interactable interactable = other.GetComponent(); // store nearest interactable if it exists if (interactable != null && nearestInteractable != null) { nearestInteractable.MoveOutsideRange(); nearestInteractable = null; } } /// /// Sets the character's "hasControl" bool. All input is ignored when false /// public void SetCharacterControl(bool hasControl) { this.hasControl = hasControl; } /// /// Sets the character's "canUseTools" bool. Tool use input is ignored when false /// public void SetCharacterCanUseTools(bool canUseTools) { this.canUseTools = canUseTools; } /// /// Gets the character's "hasControl" bool. All input is ignored when false /// public bool GetCharacterHasControl() { return hasControl; } /// /// Expose the character controller's velocity /// public Vector3 GetVelocity() { return characterController.velocity; } /// /// Switches the tools in hand by taking an index /// /// Index of the tool to switch to /// private void SwitchTools(int toolIndex) { if (toolIndex < 0 || toolIndex >= tools.Length) { toolIndex = 0; } // disable all tools foreach (Tool tool in tools) { tool.gameObject.SetActive(false); } // load new tool GameManager.Instance.PlayerManager.CurrentToolIndex = toolIndex; tools[GameManager.Instance.PlayerManager.CurrentToolIndex].gameObject.SetActive(true); } /// /// Switches the tools in hand by moving up or down the list /// /// Are we moving up (-1) the list? /// private void SwitchTools(bool up) { // calculate index of next tool int newIndex = up ? GameManager.Instance.PlayerManager.CurrentToolIndex - 1 : GameManager.Instance.PlayerManager.CurrentToolIndex + 1; if (newIndex < 0) { newIndex = tools.Length + newIndex; } else if (newIndex >= tools.Length) { newIndex = newIndex % tools.Length; } // disable current tool tools[GameManager.Instance.PlayerManager.CurrentToolIndex].gameObject.SetActive(false); // load new tool GameManager.Instance.PlayerManager.CurrentToolIndex = newIndex; tools[GameManager.Instance.PlayerManager.CurrentToolIndex].gameObject.SetActive(true); } }