158 lines
5.0 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|