Files
beyond/Assets/Scripts/Characters/Skills/ProjectileSpell.cs

75 lines
2.8 KiB
C#

using System.Collections;
using UnityEngine;
using Invector;
namespace Beyond
{
[CreateAssetMenu(menuName = "Magic/Spells/Projectile (Fireball)")]
public class ProjectileSpell : SpellDefinition
{
[Header("Projectile Settings")]
public GameObject projectilePrefab;
public float spawnDelay = 0.2f;
public float lifeTime = 10f;
[Header("Spawn Adjustments")]
[Tooltip("Position relative to Player Root. X=Right, Y=Up, Z=Forward.\nExample: (0, 1.5, 1.0) is Chest Height, 1m forward.")]
public Vector3 spawnOffset = new Vector3(0f, 1.5f, 1.0f);
[Tooltip("Offset for aiming logic only. Usually slightly higher than the target's pivot.")]
public float aimHeightOffset = 0.75f;
public override void Cast(MagicAttacks caster, Transform target)
{
caster.StartCoroutine(CastRoutine(caster, target));
}
private IEnumerator CastRoutine(MagicAttacks caster, Transform target)
{
// 1. Rotate
yield return caster.RotateTowardsTargetRoutine(target, rotationDuration);
// 2. Wait
float remainingDelay = spawnDelay - rotationDuration;
if (remainingDelay > 0) yield return new WaitForSeconds(remainingDelay);
// 3. Calculate Spawn Position (Relative to Player)
// TransformPoint converts local (Offset) to world space based on Player position/rotation
Vector3 spawnPos = caster.transform.TransformPoint(spawnOffset);
// 4. Calculate Rotation (Aiming)
Quaternion spawnRot = caster.transform.rotation; // Default forward
if (target != null)
{
Vector3 targetPos = target.position;
targetPos.y += aimHeightOffset;
Vector3 aimDir = (targetPos - spawnPos).normalized;
// Slight arc adjustment
aimDir.y += 0.1f;
if (aimDir.sqrMagnitude > 0.001f)
spawnRot = Quaternion.LookRotation(aimDir);
}
// 5. Instantiate
GameObject obj = Instantiate(projectilePrefab, spawnPos, spawnRot);
// 6. Ignore Collision with Caster (Crucial!)
Collider projectileCollider = obj.GetComponentInChildren<Collider>();
Collider playerCollider = caster.GetComponent<Collider>();
if (projectileCollider != null && playerCollider != null)
{
Physics.IgnoreCollision(projectileCollider, playerCollider);
}
// 7. Register Events & Modifiers
caster.RegisterSpellDamageEvents(obj, this);
caster.ApplyDamageModifiers(obj);
Destroy(obj, lifeTime);
}
}
}