using UnityEngine; using UnityEngine.Rendering.Universal; using static UnityEngine.GraphicsBuffer; public class ThrowableHand : Tool { [Header("Throwable Hand Parameters")] public float range; public float forceModifier; public float loft; public ItemIdEnum activeThrowable; private int activeThrowableIndex; // Mathematical plane used to catch the raycast from camera to get direction for // looking at the mouse private Plane handGroundPlane; private DecalProjector targetProjection; private float throwForce; private void Update() { if (GameManager.Instance.PlayerController != null) { DrawTargetProjection(); } } private void SetGroundPlane() { if (handGroundPlane == null) { handGroundPlane = new Plane(Vector3.up, -GameManager.Instance.PlayerController.DougBody.transform.position.y); } handGroundPlane.distance = -GameManager.Instance.PlayerController.DougBody.transform.position.y; handGroundPlane.normal = Vector3.up; } private void DrawTargetProjection() { if (targetProjection == null) { targetProjection = GetComponentInChildren(); } Transform player = GameManager.Instance.PlayerController.DougBody.transform; Transform camera = GameManager.Instance.PlayerController.cameraController.MainCamera.transform; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); Vector3 targetPoint; // First try real world geometry if (Physics.Raycast(ray, out RaycastHit hit, 1000f)) { targetPoint = hit.point; } else { // Fallback plane if nothing hit Plane plane = new Plane(Vector3.up, player.position); if (!plane.Raycast(ray, out float distance)) return; targetPoint = ray.GetPoint(distance); } // Flatten relative to player Vector3 offset = targetPoint - player.position; offset.y = 0f; // Clamp range offset = Vector3.ClampMagnitude(offset, range); throwForce = offset.magnitude; // Final position Vector3 finalPosition = player.position + offset; // Snap back to ground if (Physics.Raycast( finalPosition + Vector3.up * 10f, Vector3.down, out RaycastHit groundHit, 50f)) { finalPosition = groundHit.point; } targetProjection.transform.position = finalPosition; } private ItemIdEnum GetNextThrowable() { // Use active throwable index to let us continue to search for throwables if (activeThrowableIndex >= GameManager.Instance.Inventory.itemSlots.Length) activeThrowableIndex = 0; // Search starting at throwable index for (int i = activeThrowableIndex; i < GameManager.Instance.Inventory.itemSlots.Length; i++) { if (ItemUtilities.GetItemFromId(GameManager.Instance.Inventory.itemSlots[i].item).throwable) { activeThrowableIndex = i; return GameManager.Instance.Inventory.itemSlots[i].item; } } // Wrap back around to 0 if we didn't find anything for (int i = 0; i < activeThrowableIndex; i++) { if (ItemUtilities.GetItemFromId(GameManager.Instance.Inventory.itemSlots[i].item).throwable) { activeThrowableIndex = i; return GameManager.Instance.Inventory.itemSlots[i].item; } } // We have no throwable items... activeThrowableIndex = 0; return ItemIdEnum.NONE; } public override void Use() { if (activeThrowable == ItemIdEnum.NONE) { activeThrowable = GetNextThrowable(); } if (activeThrowable != ItemIdEnum.NONE && GameManager.Instance.Inventory.GetItemQuantity(activeThrowable) > 0) { GameObject throwable = Instantiate(GameManager.Instance.ItemInstantiationManager.GetThrowablePrefab(activeThrowable)); if (throwable != null) { throwable.transform.position = transform.position; Vector3 direction = transform.forward * throwForce * forceModifier; direction += GameManager.Instance.PlayerController.GetVelocity(); direction.y = loft; throwable.GetComponent().AddForce(direction, ForceMode.Impulse); GameManager.Instance.Inventory.RemoveItemQuantity(activeThrowable, 1); } } } public override void UseAlt() { activeThrowable = GetNextThrowable(); } }