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 playerCollider = caster.GetComponent(); if (projectileCollider != null && playerCollider != null) { Physics.IgnoreCollision(projectileCollider, playerCollider); } // 7. Register Events & Modifiers caster.RegisterSpellDamageEvents(obj, this); caster.ApplyDamageModifiers(obj); Destroy(obj, lifeTime); } } }