303 lines
7.0 KiB
C#
303 lines
7.0 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using DragonLi.Core;
|
|
using UnityEngine;
|
|
using FluffyUnderware.Curvy;
|
|
using Unity.VisualScripting;
|
|
|
|
public class FishSpawner : MonoBehaviour
|
|
{
|
|
public static FishSpawner Instance;
|
|
|
|
public readonly HashSet<Fish> AliveFishes = new HashSet<Fish>();
|
|
|
|
[Header("Spawn Rule")]
|
|
public float checkInterval = 1f;
|
|
|
|
[Header("Prefabs")]
|
|
public GameObject fishGroupPrefab;
|
|
|
|
public float fishSpeed;
|
|
public int maxFishCount;
|
|
|
|
private Dictionary<FishType, FishData> fishDataMap = new();
|
|
private Dictionary<FishType, FishSpawnState> spawnStates = new();
|
|
|
|
private float timer;
|
|
|
|
// 高价值互斥锁
|
|
private bool highFishAlive;
|
|
private bool angelHorseAlive;
|
|
|
|
private const float MIX_MIDDLE_BASE_RATE = 0.3f;
|
|
|
|
void Awake()
|
|
{
|
|
Instance = this;
|
|
}
|
|
|
|
#region Fish Register
|
|
|
|
public void RegisterFish(Fish fish)
|
|
{
|
|
if (fish == null) return;
|
|
AliveFishes.Add(fish);
|
|
}
|
|
|
|
public void UnregisterFish(Fish fish)
|
|
{
|
|
if (fish == null) return;
|
|
AliveFishes.Remove(fish);
|
|
}
|
|
|
|
#endregion
|
|
|
|
void Start()
|
|
{
|
|
fishSpeed = 1;
|
|
maxFishCount = 200;
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
timer += Time.deltaTime;
|
|
if (timer >= checkInterval)
|
|
{
|
|
timer = 0f;
|
|
TrySpawnFish();
|
|
}
|
|
}
|
|
|
|
public void LoadFishData()
|
|
{
|
|
// ⚠️ 实际项目中从配置表加载
|
|
foreach (var item in GameManager.Ins.FishDataDic)
|
|
{
|
|
fishDataMap.Add((FishType)item.Key, item.Value);
|
|
}
|
|
foreach (var kv in fishDataMap)
|
|
spawnStates[kv.Key] = new FishSpawnState();
|
|
}
|
|
|
|
void TrySpawnFish()
|
|
{
|
|
if(AliveFishes.Count>=maxFishCount)
|
|
return;
|
|
FishData data = GetFishByProbability();
|
|
if (data == null) return;
|
|
|
|
FishType type = (FishType)data.FishId;
|
|
FishValueLevel level = FishValueHelper.GetValueLevel(data);
|
|
|
|
// ⛔ 特高价值唯一
|
|
if (level == FishValueLevel.UltraHigh && angelHorseAlive)
|
|
return;
|
|
|
|
// ⛔ 高价值互斥
|
|
if (level == FishValueLevel.High && highFishAlive)
|
|
return;
|
|
|
|
FishSpawnState state = spawnStates[type];
|
|
if (Time.time < state.CooldownEndTime)
|
|
return;
|
|
|
|
int count = GetFishCount(data);
|
|
CurvySpline spline = GetSplineByType();
|
|
|
|
// ====== 生成 ======
|
|
if (count > 1)
|
|
{
|
|
if (level == FishValueLevel.Low)
|
|
SpawnLowValueGroup(data, count, spline, state);
|
|
else
|
|
SpawnNormalGroup(data, count, spline);
|
|
}
|
|
else
|
|
{
|
|
SpawnSingleFish(data, spline);
|
|
}
|
|
|
|
state.CooldownEndTime = Time.time + data.IntervalTime;
|
|
|
|
if (level == FishValueLevel.High)
|
|
highFishAlive = true;
|
|
|
|
if (level == FishValueLevel.UltraHigh)
|
|
angelHorseAlive = true;
|
|
}
|
|
|
|
#region Spawn Logic
|
|
|
|
void SpawnLowValueGroup(
|
|
FishData data,
|
|
int count,
|
|
CurvySpline spline,
|
|
FishSpawnState state)
|
|
{
|
|
List<FishData> list = new();
|
|
|
|
for (int i = 0; i < count; i++)
|
|
list.Add(data);
|
|
|
|
float rate = MIX_MIDDLE_BASE_RATE;
|
|
if (state.NoMiddleFishCount >= 3)
|
|
rate *= 2f;
|
|
|
|
bool hasMiddle = false;
|
|
|
|
if (Random.value < rate)
|
|
{
|
|
FishData middle = GetRandomMiddleValueFish();
|
|
if (middle != null)
|
|
{
|
|
list.Add(middle);
|
|
hasMiddle = true;
|
|
}
|
|
}
|
|
|
|
state.NoMiddleFishCount = hasMiddle ? 0 : state.NoMiddleFishCount + 1;
|
|
|
|
SpawnGroup(list, spline);
|
|
}
|
|
|
|
void SpawnNormalGroup(FishData data, int count, CurvySpline spline)
|
|
{
|
|
List<FishData> list = new();
|
|
for (int i = 0; i < count; i++)
|
|
list.Add(data);
|
|
|
|
SpawnGroup(list, spline);
|
|
}
|
|
|
|
void SpawnGroup(List<FishData> list, CurvySpline spline)
|
|
{
|
|
GameObject go = Instantiate(fishGroupPrefab);
|
|
go.GetComponent<FishGroup>().Init(list, spline);
|
|
}
|
|
|
|
void SpawnSingleFish(FishData data, CurvySpline spline)
|
|
{
|
|
GameObject go = Instantiate(GameManager.Ins.GetFishPre(data.FishId-1));
|
|
go.GetComponent<Fish>().Init(data, spline);
|
|
}
|
|
|
|
public void CreateTypeFish(FishType fishType)
|
|
{
|
|
FishData data= fishDataMap[fishType];
|
|
CurvySpline spline = GetSplineByType();
|
|
SpawnSingleFish(data,spline);
|
|
FishValueLevel level = FishValueHelper.GetValueLevel(data);
|
|
if (level == FishValueLevel.High)
|
|
highFishAlive = true;
|
|
|
|
if (level == FishValueLevel.UltraHigh)
|
|
angelHorseAlive = true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Utils
|
|
|
|
FishData GetFishByProbability()
|
|
{
|
|
float total = 0;
|
|
foreach (var d in fishDataMap.Values)
|
|
total += d.Odds;
|
|
|
|
float r = Random.Range(0, total);
|
|
float cur = 0;
|
|
|
|
foreach (var d in fishDataMap.Values)
|
|
{
|
|
cur += d.Odds;
|
|
if (r <= cur)
|
|
return d;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
int GetFishCount(FishData data)
|
|
{
|
|
if (data.FishCount == null || data.FishCount.Length < 2)
|
|
return 1;
|
|
|
|
return Random.Range(data.FishCount[0], data.FishCount[1] + 1);
|
|
}
|
|
|
|
CurvySpline GetSplineByType()
|
|
{
|
|
return GameInit.Ins.GetFishPath();
|
|
}
|
|
|
|
FishData GetRandomMiddleValueFish()
|
|
{
|
|
List<FishData> list = new();
|
|
|
|
foreach (var d in fishDataMap.Values)
|
|
{
|
|
if (FishValueHelper.GetValueLevel(d) == FishValueLevel.Middle)
|
|
list.Add(d);
|
|
}
|
|
|
|
return list.Count == 0 ? null : list[Random.Range(0, list.Count)];
|
|
}
|
|
|
|
public void OnHighFishRemoved(FishValueLevel level)
|
|
{
|
|
if (level == FishValueLevel.High)
|
|
highFishAlive = false;
|
|
|
|
if (level == FishValueLevel.UltraHigh)
|
|
angelHorseAlive = false;
|
|
}
|
|
|
|
#endregion
|
|
|
|
public int GetFishCount(FishType fishType)
|
|
{
|
|
int count = 0;
|
|
foreach (var item in AliveFishes)
|
|
{
|
|
if((FishType)item.Data.FishId==fishType)
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
public void SetFishSpeed(float curTime)
|
|
{
|
|
fishSpeed = 2;
|
|
foreach (var item in AliveFishes)
|
|
{
|
|
item.SetSpeed();
|
|
}
|
|
|
|
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
|
{
|
|
fishSpeed = 1;
|
|
foreach (var item in AliveFishes)
|
|
{
|
|
item.SetSpeed();
|
|
}
|
|
}, curTime);
|
|
}
|
|
|
|
public IEnumerator GetAllFishes()
|
|
{
|
|
List<Fish> allFish = new List<Fish>();
|
|
|
|
foreach (var item in AliveFishes)
|
|
{
|
|
allFish.Add(item);
|
|
}
|
|
|
|
foreach (var fish in allFish)
|
|
{
|
|
fish.DieFish();
|
|
yield return new WaitForSeconds(0.01f);
|
|
}
|
|
}
|
|
|
|
|
|
}
|