115 lines
3.8 KiB
C#
115 lines
3.8 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Animancer;
|
|
using BITFALL;
|
|
using BITFALL.Bullet;
|
|
using BITKit;
|
|
using BITKit.Entities;
|
|
using Cysharp.Threading.Tasks;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
using Net.BITKit.Quadtree;
|
|
using Net.Project.B.Faction;
|
|
using Net.Project.B.Health;
|
|
using Net.Project.B.Melee;
|
|
using Project.B.CharacterController;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
using UnityEngine.AI;
|
|
using Random = UnityEngine.Random;
|
|
|
|
namespace Net.Project.B.AI
|
|
{
|
|
public class AIZombieService:IDisposable
|
|
{
|
|
private readonly IHealthService _healthService;
|
|
private readonly IMeleeService _meleeService;
|
|
private readonly ILogger<AIZombieService> _logger;
|
|
private readonly IEntitiesService _entitiesService;
|
|
private readonly ITicker _ticker;
|
|
|
|
private readonly ConcurrentDictionary<int,IntervalUpdate> _attackIntervals = new();
|
|
|
|
private readonly ScriptableAIAnimations _animations;
|
|
|
|
private readonly MeleeData _meleeData = new()
|
|
{
|
|
Damage = 10,
|
|
IgnoreTags = { "zombie" },
|
|
MaxTargetCount = 1,
|
|
Radius = 1.2f,
|
|
};
|
|
|
|
|
|
public AIZombieService(ITicker ticker, IEntitiesService entitiesService, ILogger<AIZombieService> logger, IMeleeService meleeService, IHealthService healthService)
|
|
{
|
|
_ticker = ticker;
|
|
_entitiesService = entitiesService;
|
|
_logger = logger;
|
|
_meleeService = meleeService;
|
|
_healthService = healthService;
|
|
|
|
_ticker.Add(OnTick);
|
|
|
|
|
|
_animations = _entitiesService.QueryComponents<ScriptableAIAnimations>() is {Length:>0} s ? s[0] :null;
|
|
}
|
|
|
|
private void OnTick(float obj)
|
|
{
|
|
foreach (var (blackBoard,characterController, entity, zombie, navMeshAgent, animancerComponent) in _entitiesService
|
|
.QueryComponents<AIBlackBoard,ICharacterController, IEntity, AIZombie, NavMeshAgent, AnimancerComponent>())
|
|
{
|
|
if (!navMeshAgent.isOnNavMesh) continue;
|
|
if (characterController.AllowMovement.Allow is false) continue;
|
|
if(blackBoard is not {Target:not null , AlertValue: 1})continue;
|
|
|
|
blackBoard.Target.ServiceProvider.QueryComponents(out ICharacterController humanCc);
|
|
|
|
var playerPos = humanCc.ViewPosition;
|
|
|
|
var zombiePos = characterController.Position;
|
|
|
|
navMeshAgent.SetDestination(playerPos);
|
|
|
|
navMeshAgent.radius = Mathf.Clamp(Vector3.Distance(playerPos, zombiePos) * 0.1f, 0.64f, 1.6f);
|
|
|
|
if(_attackIntervals.GetOrCreate(entity.Id).AllowUpdate)continue;
|
|
|
|
var distance = math.distance(playerPos.xz, zombiePos.xz);
|
|
|
|
if (distance < navMeshAgent.stoppingDistance*2)
|
|
{
|
|
Attack();
|
|
_meleeData.Initiator = entity.Id;
|
|
_meleeData.StartPosition = characterController.ViewPosition;
|
|
_meleeService.Add(_meleeData);
|
|
}
|
|
|
|
continue;
|
|
|
|
async void Attack()
|
|
{
|
|
using var _ = characterController.AllowMovement.GetDisableHandle();
|
|
|
|
var state = animancerComponent.Layers[1].Play(_animations.AttachClip, 0.2f);
|
|
state.Time = 0;
|
|
await state;
|
|
if (animancerComponent)
|
|
state.Stop();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public void Dispose()
|
|
{
|
|
_ticker.Remove(OnTick);
|
|
}
|
|
}
|
|
|
|
}
|