Files
FablishRPG/Assets/Scripts/Projectile.cs
2026-09-28 20:46:57 +01:00

87 lines
2.9 KiB
C#

using UnityEngine;
public class Projectile : MonoBehaviour
{
[Header("Projectile Settings")]
[Tooltip("How fast the projectile moves forward")]
public float speed = 25f;
[Tooltip("How long before the projectile destroys itself if it misses")]
public float lifetime = 5f;
[Tooltip("Offset for embedding the arrow into the target so it doesn't just stick on the very edge")]
public float embedDepth = 0.2f;
[Header("Loaded Offsets (Before Firing)")]
[Tooltip("Adjust this to fix how the arrow sits in the hand before it is fired")]
public Vector3 loadedPositionOffset = Vector3.zero;
public Vector3 loadedRotationOffset = Vector3.zero;
private float _damage;
private LayerMask _targetLayers;
private bool _hasHit;
private Vector3 _lastPosition;
public void Initialize(float damage, LayerMask targets)
{
_damage = damage;
_targetLayers = targets;
// Destroy the arrow after a few seconds if it flies into the sky
Destroy(gameObject, lifetime);
}
private void Start()
{
_lastPosition = transform.position;
}
private void Update()
{
if (_hasHit) return;
// Move the projectile forward
Vector3 direction = transform.forward;
float distance = speed * Time.deltaTime;
transform.position += direction * distance;
// Raycast from the previous position to the new position to detect hits
// This prevents fast-moving arrows from passing straight through thin walls or enemies
if (Physics.Raycast(_lastPosition, direction, out RaycastHit hit, distance, _targetLayers))
{
HandleHit(hit);
}
_lastPosition = transform.position;
}
private void HandleHit(RaycastHit hit)
{
_hasHit = true;
// Move the arrow right exactly to the hit point, then embed it slightly
transform.position = hit.point + (transform.forward * embedDepth);
// Parent the arrow to the object it hit so it sticks and moves with it
transform.SetParent(hit.collider.transform, true);
// If your Arrow Prefab has a Rigidbody on it, it will fall down due to gravity even after being parented!
// We must destroy the Rigidbody component so it stays perfectly glued to the target.
Rigidbody rb = GetComponent<Rigidbody>();
if (rb != null)
{
Destroy(rb);
}
// Deal damage
Debug.Log($"Arrow hit {hit.collider.name} for {_damage} damage!");
hit.collider.GetComponent<WorldObject>()?.TakeDamage(_damage);
// Optional: Disable collider or script so it doesn't keep checking for hits
Collider myCollider = GetComponent<Collider>();
if (myCollider != null) myCollider.enabled = false;
this.enabled = false; // Stops the Update loop
}
}