Files
Northbound/Assets/Scripts/EnemyPortal.cs
dal4segno 4bd46b2a0a 네트워크 동기화 문제 해결
몬스터와 크립에 네트워크 관련 컴포넌트가 없는 문제 수정
포탈/캠프와 몬스터/크립 간의 계층 구조 해제
 - 네트워크 오브젝트끼리 계층 구조로 둘 수 없음
2026-02-04 18:16:59 +09:00

153 lines
4.1 KiB
C#

using Northbound;
using Northbound.Data;
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;
public class EnemyPortal : NetworkBehaviour
{
[System.Serializable]
public class MonsterEntry
{
public GameObject prefab;
}
[Header("Spawn Settings")]
[Tooltip("몬스터 프리팹 목록 (Editor에서 자동 로드 가능)")]
[SerializeField] private List<MonsterEntry> monsterEntries = new();
[Header("Cost Settings")]
[Tooltip("시간당 코스트 시작 값")]
[SerializeField] private float initialCost = 4f;
[Tooltip("사이클마다 코스트 증가율 (%)")]
[SerializeField] private float costIncreaseRate = 10f;
private float currentCost;
void Start()
{
currentCost = initialCost;
GlobalTimer.Instance.OnCycleStart += OnCycleStart;
}
private void OnCycleStart(int cycleNumber)
{
SpawnMonsters();
IncreaseCost();
}
private void SpawnMonsters()
{
float remainingCost = currentCost;
int spawnedCount = 0;
while (remainingCost > 0 && monsterEntries.Count > 0)
{
MonsterEntry selectedEntry = SelectMonsterByWeight();
MonsterData monsterData = GetMonsterDataFromPrefab(selectedEntry.prefab);
if (monsterData == null)
{
Debug.LogWarning($"[EnemyPortal] Could not find MonsterData on {selectedEntry.prefab.name}");
continue;
}
if (monsterData.cost > remainingCost)
{
if (!CanSpawnAnyMonster(remainingCost))
{
break;
}
continue;
}
SpawnEnemy(selectedEntry.prefab);
remainingCost -= monsterData.cost;
spawnedCount++;
}
if (spawnedCount > 0)
{
Debug.Log($"[EnemyPortal] Spawned {spawnedCount} monsters (Cost used: {currentCost - remainingCost:F2})");
}
}
private bool CanSpawnAnyMonster(float remainingCost)
{
foreach (var entry in monsterEntries)
{
MonsterData monsterData = GetMonsterDataFromPrefab(entry.prefab);
if (monsterData != null && monsterData.cost <= remainingCost)
{
return true;
}
}
return false;
}
private MonsterEntry SelectMonsterByWeight()
{
float totalWeight = 0f;
foreach (var entry in monsterEntries)
{
MonsterData monsterData = GetMonsterDataFromPrefab(entry.prefab);
if (monsterData != null)
{
totalWeight += monsterData.weight;
}
}
float randomValue = Random.Range(0f, totalWeight);
float cumulativeWeight = 0f;
foreach (var entry in monsterEntries)
{
MonsterData monsterData = GetMonsterDataFromPrefab(entry.prefab);
if (monsterData != null)
{
cumulativeWeight += monsterData.weight;
if (randomValue <= cumulativeWeight)
{
return entry;
}
}
}
return monsterEntries[0];
}
private MonsterData GetMonsterDataFromPrefab(GameObject prefab)
{
if (prefab == null) return null;
MonsterDataComponent component = prefab.GetComponent<MonsterDataComponent>();
if (component != null)
{
return component.monsterData;
}
return null;
}
private void SpawnEnemy(GameObject prefab)
{
if (!IsServer) return;
GameObject enemy = Instantiate(prefab, transform);
if (enemy.GetComponent<FogOfWarVisibility>() == null)
{
var visibility = enemy.AddComponent<FogOfWarVisibility>();
visibility.showInExploredAreas = false;
visibility.updateInterval = 0.2f;
}
enemy.GetComponent<NetworkObject>().SpawnWithOwnership(NetworkManager.Singleton.LocalClientId);
}
private void IncreaseCost()
{
currentCost *= (1f + costIncreaseRate / 100f);
}
}