Files
Net.Like.Xue.Tokyo/Packages-Local/Com.Project.B.Unity/AI/AISensorService.cs
2025-06-24 23:49:13 +08:00

111 lines
4.0 KiB
C#

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using BITKit;
using BITKit.Entities;
using Microsoft.Extensions.DependencyInjection;
using Net.BITKit.BitMask;
using Net.BITKit.Quadtree;
using Net.Project.B.Faction;
using Net.Project.B.Health;
using Project.B.CharacterController;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Pool;
namespace Net.Project.B.AI
{
public class AISensorService:IDisposable
{
private readonly ITicker _ticker;
private readonly IHealthService _healthService;
private readonly IEntitiesService _entitiesService;
private readonly ConcurrentDictionary<int, float> _alertValues = new();
private readonly IDictionary<Type, HashSet<Type>> _enemies;
private readonly Dictionary<Type, BITKit.Quadtree.Quadtree> _quadTrees = new();
private readonly SortedDictionary<float, int> _sortedDictionary = new();
public AISensorService(ITicker ticker, IEntitiesService entitiesService, IServiceProvider serviceProvider, IHealthService healthService)
{
_ticker = ticker;
_entitiesService = entitiesService;
_healthService = healthService;
_ticker.Add(OnTick);
foreach (var scriptableMask in _entitiesService.QueryComponents<ScriptableBitMask>())
{
if (scriptableMask.Type != typeof(IFactionType)) continue;
_enemies = scriptableMask.FlagMask;
foreach (var (type,_) in _enemies)
{
var service = serviceProvider.GetRequiredService(typeof(QuadTreeService<>).MakeGenericType(type)).As<QuadTreeService>();
_quadTrees[type] = service.Quadtree;
}
return;
}
throw new ArgumentNullException($"未找到类型为:{nameof(IFactionType)}的Mask");
}
private void OnTick(float obj)
{
foreach (var (entity, blackBoard, factionType, characterController) in _entitiesService
.QueryComponents<IEntity, AIBlackBoard, IFactionType, ICharacterController>())
{
{
if (_healthService.Healths.TryGetValue(entity.Id, out var hp) is false || hp < 0) continue;
}
var enemies = _enemies[factionType.GetType()];
_sortedDictionary.Clear();
var position = characterController.Position.xz;
foreach (var enemy in enemies)
{
var quadtree = _quadTrees[enemy];
foreach (var id in quadtree.Query(position, 128))
{
if (_healthService.Healths.TryGetValue(id, out var hp) is false || hp < 0)
{
continue;
}
var distance = math.distance(quadtree.Positions[id], position);
_sortedDictionary[distance] = id;
}
}
if (_sortedDictionary.Count is 0)
{
if (blackBoard.Target is not null)
{
if (_healthService.Healths.TryGetValue(blackBoard.Target.Id, out var hp) is false || hp < 0)
{
blackBoard.Target = null;
}
blackBoard.AlertValue -= obj;
}
if (blackBoard.Target is not null && blackBoard.AlertValue is 0)
{
blackBoard.Target = null;
}
continue;
}
var target = _entitiesService.Entities[_sortedDictionary.First().Value];
blackBoard.Target = target;
blackBoard.AlertValue += obj;
}
}
public void Dispose()
{
_ticker.Remove(OnTick);
}
}
}