199 lines
6.1 KiB
C#
199 lines
6.1 KiB
C#
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
|
|
/// <summary>
|
|
/// Simple world pickup for bat or hammer. Uses Input System action "WeaponPickup" via WeaponManager to equip when in range.
|
|
/// Plays the pickup animation on the player, hides the world pickup, and shows the in-hand weapon.
|
|
/// Assumes the player already has WeaponManager and the weapon models hidden on hand.
|
|
/// </summary>
|
|
[RequireComponent(typeof(Collider))]
|
|
public class WeaponPickup : MonoBehaviour
|
|
{
|
|
public enum PickupType { Bat, Hammer }
|
|
public PickupType pickupType = PickupType.Bat;
|
|
|
|
[Header("Pickup Settings")]
|
|
public float pickUpRange = 2.5f;
|
|
public Transform player;
|
|
|
|
[Header("Input System")]
|
|
[SerializeField] private string pickupActionName = "WeaponPickup";
|
|
|
|
private bool _playerInTrigger;
|
|
private PlayerInput _playerInput;
|
|
private InputAction _pickupAction; // action named "WeaponPickup" in the input asset
|
|
|
|
// Tracks the pickup the player is currently inside (single-player assumption)
|
|
public static WeaponPickup currentPickupInRange;
|
|
|
|
private void Reset()
|
|
{
|
|
var col = GetComponent<Collider>();
|
|
col.isTrigger = true;
|
|
// Ensure trigger events fire by having a kinematic Rigidbody on the pickup
|
|
var rb = GetComponent<Rigidbody>();
|
|
if (rb == null)
|
|
{
|
|
rb = gameObject.AddComponent<Rigidbody>();
|
|
}
|
|
rb.isKinematic = true;
|
|
rb.useGravity = false;
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
// Attempt to bind immediately if player is already assigned
|
|
TryBindInput();
|
|
}
|
|
|
|
private void OnTriggerEnter(Collider other)
|
|
{
|
|
// Robustly detect the player even if a child collider enters
|
|
var wm = other.GetComponentInParent<WeaponManager>();
|
|
if (wm != null)
|
|
{
|
|
player = wm.transform;
|
|
_playerInTrigger = true;
|
|
currentPickupInRange = this;
|
|
TryBindInput();
|
|
}
|
|
}
|
|
|
|
private void OnTriggerExit(Collider other)
|
|
{
|
|
var wm = other.GetComponentInParent<WeaponManager>();
|
|
if (wm != null && player == wm.transform)
|
|
{
|
|
_playerInTrigger = false;
|
|
if (currentPickupInRange == this)
|
|
currentPickupInRange = null;
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (player == null)
|
|
{
|
|
// Lazy find player by component to be safer
|
|
var wm = FindObjectOfType<WeaponManager>();
|
|
if (wm != null) player = wm.transform;
|
|
}
|
|
|
|
// Ensure input is bound/enabled (even though we don't read it here)
|
|
TryBindInput();
|
|
|
|
// IMPORTANT: Do not handle input here. WeaponManager exclusively handles the WeaponPickup action.
|
|
|
|
// Proximity fallback: if triggers fail, still allow pickup when close
|
|
if (player != null)
|
|
{
|
|
bool near = Vector3.Distance(player.position, transform.position) <= pickUpRange;
|
|
if (near)
|
|
{
|
|
currentPickupInRange = this;
|
|
}
|
|
else if (!_playerInTrigger && currentPickupInRange == this)
|
|
{
|
|
currentPickupInRange = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void TryBindInput()
|
|
{
|
|
if (player == null) return;
|
|
|
|
if (_playerInput == null)
|
|
{
|
|
_playerInput = player.GetComponent<PlayerInput>();
|
|
}
|
|
|
|
if (_playerInput == null) return;
|
|
|
|
if (_pickupAction == null)
|
|
{
|
|
_pickupAction = _playerInput.actions?.FindAction(pickupActionName, false);
|
|
}
|
|
|
|
if (_pickupAction != null && !_pickupAction.enabled)
|
|
{
|
|
_pickupAction.SafeEnable();
|
|
}
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
// Keep action enabled via PlayerInput; only clear local refs
|
|
if (currentPickupInRange == this)
|
|
currentPickupInRange = null;
|
|
_pickupAction = null;
|
|
_playerInput = null;
|
|
}
|
|
|
|
// Expose for global handler (called by WeaponManager when button pressed and in range)
|
|
public void TryEquip()
|
|
{
|
|
if (player == null) return;
|
|
|
|
// Safety: ensure still in range and not holding a weapon
|
|
bool inRange = _playerInTrigger || Vector3.Distance(player.position, transform.position) <= pickUpRange;
|
|
var wm = player.GetComponent<WeaponManager>();
|
|
if (!inRange || wm == null)
|
|
{
|
|
return;
|
|
}
|
|
if (wm.IsWeaponEquipped)
|
|
{
|
|
// Let WeaponManager handle dropping with the same button
|
|
return;
|
|
}
|
|
|
|
// Play pickup animation if available
|
|
var anim = player.GetComponent<AnimationManager>();
|
|
if (anim != null)
|
|
{
|
|
anim.PlayAnimation(AnimationNames.WeaponPickup);
|
|
}
|
|
|
|
switch (pickupType)
|
|
{
|
|
case PickupType.Bat:
|
|
wm.EquipWeaponFromPickup(WeaponManager.WeaponType.Bat, this);
|
|
break;
|
|
case PickupType.Hammer:
|
|
wm.EquipWeaponFromPickup(WeaponManager.WeaponType.Hammer, this);
|
|
break;
|
|
}
|
|
|
|
// Hide the world pickup (simulate taking it). You can pool/destroy instead.
|
|
gameObject.SetActive(false);
|
|
|
|
// Clear static reference if this was the current pickup
|
|
if (currentPickupInRange == this)
|
|
currentPickupInRange = null;
|
|
}
|
|
|
|
// Called by WeaponManager to place this pickup back into the world when dropping
|
|
public void PlaceAsDropped(Transform playerTransform)
|
|
{
|
|
gameObject.SetActive(true);
|
|
transform.position = playerTransform.position + Vector3.up * 0.25f;
|
|
transform.rotation = Quaternion.Euler(0f, playerTransform.eulerAngles.y, 0f);
|
|
|
|
// Prevent instant re-trigger by disabling collider briefly
|
|
var col = GetComponent<Collider>();
|
|
if (col != null)
|
|
{
|
|
StartCoroutine(DisableColliderBrief(col));
|
|
}
|
|
}
|
|
|
|
private System.Collections.IEnumerator DisableColliderBrief(Collider col)
|
|
{
|
|
bool prev = col.enabled;
|
|
col.enabled = false;
|
|
yield return new WaitForSeconds(0.2f);
|
|
col.enabled = prev;
|
|
}
|
|
}
|