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 _alertValues = new(); private readonly IDictionary> _enemies; private readonly Dictionary _quadTrees = new(); private readonly SortedDictionary _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()) { if (scriptableMask.Type != typeof(IFactionType)) continue; _enemies = scriptableMask.FlagMask; foreach (var (type,_) in _enemies) { var service = serviceProvider.GetRequiredService(typeof(QuadTreeService<>).MakeGenericType(type)).As(); _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()) { { 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); } } }