using UnityEngine; using Platformer.Mechanics; namespace EerieVillage.Skills.Effectors { /// /// 투사체 생성기. IEffector 구현체. /// SkillFireEvent.Execute 에서 ActiveCategory.Projectile 분기 시 호출. /// BT12-Dev Phase 2-B §4-4. /// /// 다중 발사: PlayerStats.ExtraProjectiles 반영 (P08 투사체증폭). /// 궤적 분기: ActiveSkillData.Trajectory — Line → Projectile, Homing → HomingProjectile. /// public class ProjectileSpawner : IEffector { public void Trigger(ActiveSkillRuntime runtime, PlayerSkillInventory inventory) { var data = runtime.ActiveData; // 플레이어 위치·방향 취득 Transform playerTransform = inventory.transform; Vector2 spawnPos = playerTransform.position; // PlayerController.Facing 참조 Vector2 facing = Vector2.right; var pc = inventory.GetComponent(); if (pc != null) facing = pc.Facing; // 프리팹 로드 GameObject prefab = LoadProjectilePrefab(data); if (prefab == null) { Debug.LogWarning($"[ProjectileSpawner] 투사체 프리팹 로드 실패 (data.id={data.CardId})"); return; } // 다중 발사 수 (기본 1 + ExtraProjectiles) int count = 1 + Mathf.Max(0, inventory.Stats.ExtraProjectiles); float angleStep = count > 1 ? 10f : 0f; float startAngle = -angleStep * (count - 1) * 0.5f; for (int i = 0; i < count; i++) { float angle = startAngle + angleStep * i; Vector2 dir = RotateVector(facing, angle); var go = Object.Instantiate(prefab, (Vector3)spawnPos, Quaternion.identity); Projectile proj; if (data.Trajectory == ProjectileTrajectory.Homing) proj = go.GetComponent() ?? go.AddComponent(); else proj = go.GetComponent() ?? go.AddComponent(); proj.Initialize(runtime, inventory, dir); } } /// /// 투사체 프리팹 로드. /// Phase 2-C 에서 data.projectilePrefab 필드를 추가하면 해당 경로 우선 사용. /// 현재는 Resources/Skills/Projectiles/Default 폴백. /// 폴백 실패 시 Collider2D 부착 빈 오브젝트를 반환한다. /// private static GameObject LoadProjectilePrefab(ActiveSkillData data) { var prefab = Resources.Load("Skills/Projectiles/Default"); if (prefab != null) return prefab; // 폴백 — 빈 오브젝트 + CircleCollider2D (시각 없음, 판정만) var go = new GameObject($"Projectile_{data.CardId}"); var col = go.AddComponent(); col.isTrigger = true; col.radius = 0.2f; return go; } private static Vector2 RotateVector(Vector2 v, float degrees) { float rad = degrees * Mathf.Deg2Rad; float cos = Mathf.Cos(rad); float sin = Mathf.Sin(rad); return new Vector2(v.x * cos - v.y * sin, v.x * sin + v.y * cos); } } }