using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using BITFALL; using BITFALL.Bullet; using BITKit; using BITKit.Entities; 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.AI; using Random = UnityEngine.Random; namespace Net.Project.B.AI { public class AIShooterService : IDisposable { private readonly IBulletService _bulletService; private readonly IEntitiesService _entitiesService; private readonly ITicker _ticker; private readonly ConcurrentDictionary _fireLimits = new(); private readonly ConcurrentDictionary _fireIntervals = new(); private readonly ConcurrentDictionary _fireRateIntervals = new(); private readonly LayerMask _layerMask=LayerMask.GetMask("Default"); private static LimitTimes CreateLimitTimes(int id) { return new LimitTimes(3); } private static IntervalUpdate CreateFireRateIntervals(int id) { return new IntervalUpdate(0.1f); } private readonly BulletData _bulletData = new() { InitialDamage = 30, MaxDamage = 30, StartSpeed = 256, }; public AIShooterService(ITicker ticker, IBulletService bulletService, IEntitiesService entitiesService) { _ticker = ticker; _bulletService = bulletService; _entitiesService = entitiesService; _bulletService.OnHit += OnHit; _ticker.Add(OnTick); } private bool OnHit(int arg1, int arg2) { return (_fireIntervals.ContainsKey(arg1) && _fireIntervals.ContainsKey(arg2)) is false; } public void Dispose() { _bulletService.OnHit -= OnHit; _ticker.Remove(OnTick); } private void OnTick(float obj) { foreach (var (entity,blackBoard, characterController, shooter,healthComponent,navMeshAgent) in _entitiesService .QueryComponents()) { if(healthComponent.HealthPoint<0)continue; if(blackBoard.AlertValue is not 1)continue; if(blackBoard is not {Target:not null,AlertValue:1})continue; #if UNITY_EDITOR { blackBoard.Target.ServiceProvider.QueryComponents(out ICharacterController zombieCharacterController); var targetPos = zombieCharacterController.ViewPosition + zombieCharacterController.Velocity * obj; Debug.DrawLine(characterController.ViewPosition,targetPos,Color.green,obj); } #endif if (_fireRateIntervals.GetOrAdd(entity.Id, CreateFireRateIntervals).AllowUpdate is false) continue; var fireLimits = _fireLimits.GetOrAdd(entity.Id, CreateLimitTimes); if (_fireIntervals.GetOrCreate(entity.Id).AllowUpdate) { fireLimits.Reset(); } if (fireLimits.Allow is false) continue; { blackBoard.Target.ServiceProvider.QueryComponents(out ICharacterController zombieCharacterController); var targetPos = zombieCharacterController.ViewPosition + zombieCharacterController.Velocity * obj; if (Physics.Linecast(characterController.ViewPosition, targetPos, out var hit,layerMask:_layerMask)) { //Debug.DrawLine(characterController.ViewPosition,hit.point,Color.red,obj); //navMeshAgent.SetDestination(targetPos); continue; } _bulletData.Initiator = entity.Id; _bulletData.Position = characterController.ViewPosition; _bulletData.Rotation = Quaternion.LookRotation( targetPos- characterController.ViewPosition) * Quaternion.Euler(Random.insideUnitSphere) ; _bulletData.Forward = (Quaternion)_bulletData.Rotation * Vector3.forward; _bulletService.Spawn(_bulletData); } } } } }