Practice_Unity/Assets/Scripts/Controllers/SpawnController.cs
Seonkyu.kim ccc9d46df7 작업
1. 이동시 Rigdoby와 Nav 충돌나는거 수정
2. 데이터 매니저에서 데이터 받아오는것에 대한 방식을 대폭 수정
3. 스폰 컨트롤러 방식 조금 수정
4. 벽과 플레이어 캐릭터 충돌시 미끄러지는 기능 추가(다른 오브젝트와는 테스트 안해 봄)

- 캐릭터 컨트롤러에 스테이터스 하는거 손 봐야 함
2025-09-25 18:00:21 +09:00

137 lines
4.6 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
public class SpawnController : MonoBehaviour
{
private Dictionary<string, EnemyData> _enemyDatas;
private Dictionary<string, GameObject> _prototypes = new Dictionary<string, GameObject>();
private readonly List<GameObject> _spawned = new();
[SerializeField] private string _enemyPrefabPath; // 스폰할 프리팹
[SerializeField] private string _enemyDataPath; // 스폰할 프리팹
[SerializeField] private LayerMask _spawnedTargetLayers; // 스포너 Inspector에서 설정
[SerializeField] private LayerMask _spawnedObstacleLayers; // 스포너 Inspector에서 설정
private Transform _prototypeRoot; // 계층 관리용
int monsterCount = 0;
public string EnemyPrefabPath { get { return _enemyPrefabPath; } set { _enemyPrefabPath = value; }}
public string EnemyDataPath { get { return _enemyDataPath; } set { _enemyDataPath = value; }}
void Awake()
{
var root = new GameObject("EnemyPrototypes");
root.SetActive(false);
_prototypeRoot = root.transform;
}
private void Start()
{
if (string.IsNullOrEmpty(EnemyPrefabPath) || string.IsNullOrEmpty(EnemyDataPath))
throw new ArgumentNullException("EnemyPrefabPath or EnemyDataPath is null or empty");
_enemyDatas =
Manager.Data.LoadToDict<EnemyDataLoader, string, EnemyData>(EnemyDataPath, (enemy) => enemy.name);
CreateEnemyPrototype();
}
void Update()
{
float radius = 2.0f;
for (; monsterCount < 5; monsterCount++)
{
float angle = monsterCount * Mathf.PI * 2 / 5;
Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius + new Vector3(0, 0, 10);
SpawnFromProtoType("Test_Enemy_1", pos);
}
}
void CreateEnemyPrototype()
{
foreach (var enemyData in _enemyDatas)
{
string key = enemyData.Key;
EnemyData data = enemyData.Value;
GameObject enemy = Manager.Resource.Instantiate(EnemyPrefabPath);
enemy.name = $"{key}_Prototype";
enemy.transform.SetParent(_prototypeRoot, worldPositionStays: false);
enemy.SetActive(false);
if(!enemy.TryGetComponent<EnemyController>(out _)) enemy.AddComponent<EnemyController>();
var status = enemy.GetComponent<Status_Enemy>();
if (status == null) status = enemy.AddComponent<Status_Enemy>();
status.Data = data.status;
// status = data.status;
// status.CopyFrom(statusData);
_prototypes[key] = enemy;
}
}
public GameObject SpawnFromProtoType(string key, Vector3 position, Quaternion? rotation = null)
{
if(!_prototypes.TryGetValue(key, out GameObject prototype)|| prototype == null)
{
Debug.LogError($"SpawnFromProtoType Failed! : {key}");
return null;
}
var rot = rotation ?? Quaternion.identity;
GameObject clone = Instantiate(prototype, position, rot);
clone.name = $"{key}";
clone.SetActive(true);
_spawned.Add(clone);
return clone;
}
// 오버로드: 회전 생략
// public GameObject SpawnFromPrototype(string key, Vector3 position) => SpawnFromPrototype(key, position, null);
public void Despawn(GameObject go)
{
if (go == null) return;
_spawned.Remove(go);
Destroy(go);
}
public void DespawnAll()
{
for (int i = _spawned.Count - 1; i >= 0; i--)
{
Despawn(_spawned[i]);
}
_spawned.Clear();
}
// private static void CopyStatusValues(Status_Enemy src, Status_Enemy dst)
// {
// if (src == null || dst == null) return;
//
// var type = typeof(Status_Enemy);
//
// foreach (var f in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
// {
// if (f.IsInitOnly || f.IsLiteral) continue;
// if (typeof(Delegate).IsAssignableFrom(f.FieldType)) continue;
// f.SetValue(dst, f.GetValue(src));
// }
//
// foreach (var p in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
// {
// if (!p.CanRead || !p.CanWrite) continue;
// if (p.GetIndexParameters().Length > 0) continue;
// try { p.SetValue(dst, p.GetValue(src)); } catch { }
// }
// }
}