BITFALL/Assets/Artists/Scripts/GameMode/UnityAISpawner.cs

158 lines
5.0 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms.VisualStyles;
using BITKit;
using BITKit.Entities;
using BITKit.OpenWorld;
using Quadtree;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.AI;
using YooAsset;
using Random = UnityEngine.Random;
namespace BITFALL.GameMode
{
public class UnityAISpawner : MonoBehaviour,IWorldChunkObject
{
[SerializeReference,SubclassSelector] private ITicker ticker;
[SerializeReference, SubclassSelector] private new IReference name;
[SerializeReference,SubclassSelector] private IReference entityPath;
[SerializeReference,SubclassSelector] private IChunkService chunkService;
[SerializeField, ReadOnly] private int lod;
[SerializeField, ReadOnly] private int spawnedCount;
[SerializeField] private int minCapacity;
[SerializeField] private int maxCapacity;
[SerializeField] private int cycleMaxCount;
[SerializeField] private float4x4 bounds;
private readonly HashSet<IEntity> _spawnedEntities = new();
public string Name => name.Value;
public int MinCapacity => minCapacity;
public int MaxCapacity => maxCapacity;
private int _capacity;
public IEntity Entity
{
get
{
var task = YooAssets.LoadAssetAsync<GameObject>(entityPath.Value);
task.WaitForAsyncComplete();
return task.AssetObject.As<GameObject>().GetComponent<IEntity>();
}
}
public int CycleMaxCount => cycleMaxCount;
public float4x4 Bounds => bounds;
public IEntity[] spawnedEntities => _spawnedEntities.ToArray();
private readonly ConcurrentQueue<IEntity> _removeQueue = new();
private readonly ValidHandle allowTick = new();
private void OnEnable()
{
_capacity = Random.Range(minCapacity, maxCapacity);
}
private void Start()
{
lod = -1;
allowTick.AddListener(x =>
{
if(x)
ticker.Add(OnTick);
else
ticker.Remove(OnTick);
});
chunkService.Register(this);
destroyCancellationToken.Register(Dispose);
}
private void Dispose()
{
chunkService.Unregister(this);
}
private void OnTick(float obj)
{
if(lod is not 0) return;
while (_removeQueue.TryDequeue(out var entity))
{
if (_spawnedEntities.Contains(entity))
_spawnedEntities.Remove(entity);
}
spawnedCount = _spawnedEntities.Count;
if (spawnedEntities.Length >= _capacity) return;
for (var i = 0; i < Math.Min(cycleMaxCount, _capacity - spawnedEntities.Length); i++)
{
var position =transform.position + new Vector3(
Random.Range(-8, 8),
Random.Range(0, 8),
Random.Range(-8, 8)
);
if(Physics.Raycast(position,Vector3.down,out var hit,100))
position = hit.point;
var rotation = Quaternion.Euler(
0,
Random.Range(0, 360),
0);
var entity = Entity.As<Entity>();
entity = Instantiate(entity, position, rotation);
_spawnedEntities.Add(entity);
entity.TryGetComponent<IHealth>(out var heal);
heal.OnSetAlive += (x) =>
{
if (x) return;
_removeQueue.Enqueue(entity);
};
}
}
public Bounds GetBounds() => new(transform.position, new Vector3(4, 4, 4));
public Node<IWorldChunkObject> ParentNode { get; set; }
public void QuadTree_Root_Initialized(IQuadtreeRoot<IWorldChunkObject, Node<IWorldChunkObject>> root)
{
}
public int Id { get; set; }
public int Lod
{
get=>lod;
set
{
lod = value;
switch (lod)
{
case 0:
allowTick.AddElement(this);
break;
case 1:
case 2:
allowTick.RemoveElement(this);
break;
default:
allowTick.RemoveElement(this);
// foreach (var x in _spawnedEntities)
// {
// Destroy(x.As<MonoBehaviour>().gameObject);
// }
// _spawnedEntities.Clear();
// spawnedCount = 0;
break;
}
}
}
}
}