EerieVillage/Assets/Scripts/Skills/Effectors/ProjectileSpawner.cs

87 lines
3.4 KiB
C#

using UnityEngine;
using Platformer.Mechanics;
namespace EerieVillage.Skills.Effectors
{
/// <summary>
/// 투사체 생성기. IEffector 구현체.
/// SkillFireEvent.Execute 에서 ActiveCategory.Projectile 분기 시 호출.
/// BT12-Dev Phase 2-B §4-4.
///
/// 다중 발사: PlayerStats.ExtraProjectiles 반영 (P08 투사체증폭).
/// 궤적 분기: ActiveSkillData.Trajectory — Line → Projectile, Homing → HomingProjectile.
/// </summary>
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<PlayerController>();
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<HomingProjectile>() ?? go.AddComponent<HomingProjectile>();
else
proj = go.GetComponent<Projectile>() ?? go.AddComponent<Projectile>();
proj.Initialize(runtime, inventory, dir);
}
}
/// <summary>
/// 투사체 프리팹 로드.
/// Phase 2-C 에서 data.projectilePrefab 필드를 추가하면 해당 경로 우선 사용.
/// 현재는 Resources/Skills/Projectiles/Default 폴백.
/// 폴백 실패 시 Collider2D 부착 빈 오브젝트를 반환한다.
/// </summary>
private static GameObject LoadProjectilePrefab(ActiveSkillData data)
{
var prefab = Resources.Load<GameObject>("Skills/Projectiles/Default");
if (prefab != null) return prefab;
// 폴백 — 빈 오브젝트 + CircleCollider2D (시각 없음, 판정만)
var go = new GameObject($"Projectile_{data.CardId}");
var col = go.AddComponent<CircleCollider2D>();
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);
}
}
}