BITFALL/Assets/Artists/Scripts/MeleeService/MeleeService.cs

173 lines
4.8 KiB
C#
Raw Normal View History

2023-08-27 02:58:19 +08:00
using System;
2024-02-21 01:40:53 +08:00
using System.Buffers;
2023-08-27 02:58:19 +08:00
using System.Collections;
using System.Collections.Generic;
using System.Linq;
2023-11-15 23:54:54 +08:00
using BITFALL.Combat;
2023-08-27 02:58:19 +08:00
using BITKit;
using BITKit.Entities;
using BITKit.Entities.Melee;
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Triggers;
using Unity.Collections;
using UnityEngine;
2024-02-21 01:40:53 +08:00
using UnityEngine.Pool;
2023-08-27 02:58:19 +08:00
using UnityEngine.VFX;
2023-12-15 20:03:44 +08:00
namespace BITFALL.Combat
2023-08-27 02:58:19 +08:00
{
[Serializable]
public class MeleeServiceSingleton : IMeleeService
{
public void Melee(MeleeCommand command) => MeleeService.Melee(command);
}
2023-11-15 23:54:54 +08:00
2023-08-27 02:58:19 +08:00
public class MeleeService : MonoBehaviour,IMeleeService
{
internal static MeleeService Singleton;
[RuntimeInitializeOnLoadMethod]
private static void Initialize()
{
Queue.Clear();
}
private static readonly Queue<MeleeCommand> Queue = new();
public static void Melee(MeleeCommand command)=>Queue.Enqueue(command);
[SerializeField] private LayerMask detectLayer;
2023-10-24 23:37:59 +08:00
[SerializeReference, SubclassSelector] private IDamageService damageService;
2023-08-27 02:58:19 +08:00
private void Awake()
{
Singleton = this;
}
private void FixedUpdate()
{
if (Queue.TryDequeue(out var command) is false) return;
var colliders = Physics.OverlapSphere(command.Position, command.Range,detectLayer);
2023-11-15 23:54:54 +08:00
var _damaged = new Dictionary<ulong, IUnityEntity>();
var hits = colliders
.Where(x => x.GetComponent<IDamagable>() is not null)
2024-02-21 01:40:53 +08:00
//.Where(x => MathV.IsForward(command.Position, command.Forward, x.transform.position))
.Where(x=>MathV.InFovRange(command.Position,command.Forward,x.transform.position,75))
.Select(x => x.GetComponent<IDamagable>())
.OrderBy(ByDistance)
2023-11-15 23:54:54 +08:00
.Where(damageable =>damageable.UnityEntity?.Id != command.PlayerId)
.Where(damageable =>
{
if (command.IgnoreTags is null
|| !(command.IgnoreTags?.Length > 0)
|| damageable.UnityEntity is null
|| !damageable.UnityEntity.TryGetComponent<ITag>(out var iTags)) return true;
return !MathE.Contains(iTags.GetTags(), command.IgnoreTags);
})
.Where(x => x.UnityEntity is null || _damaged.TryAdd(x.UnityEntity.Id, x.UnityEntity))
2023-12-30 17:37:48 +08:00
.Where(InSight)
2023-11-15 23:54:54 +08:00
;
var damageCount = 0;
if (command.Limit is 0)
2023-11-15 23:54:54 +08:00
{
command.Limit = 1;
2023-11-15 23:54:54 +08:00
}
foreach (var x in hits)
2023-08-27 02:58:19 +08:00
{
2023-10-20 19:31:12 +08:00
try
2023-08-27 02:58:19 +08:00
{
2023-11-15 23:54:54 +08:00
var damageable = x;
2023-10-30 01:25:53 +08:00
2023-11-15 23:54:54 +08:00
if (command.ForceHitStun)
2023-08-27 02:58:19 +08:00
{
2023-11-15 23:54:54 +08:00
if (damageable is not null && damageable.UnityEntity is not null && damageable.UnityEntity.TryGetComponent<IMeleeCombat>(out var combat))
{
combat.HitStun();
}
2023-10-20 19:31:12 +08:00
}
2023-11-15 23:54:54 +08:00
2023-10-24 23:37:59 +08:00
var damageMsg =
new DamageMessage()
2023-10-20 19:31:12 +08:00
{
2023-10-30 01:25:53 +08:00
Initiator = UnityEntitiesService.Get(command.PlayerId) as IUnityEntity,
2023-10-24 23:37:59 +08:00
DamageType = new MeleeDamageMessage
2023-10-20 19:31:12 +08:00
{
},
2023-10-30 01:25:53 +08:00
Target = damageable.UnityEntity,
2023-10-24 23:37:59 +08:00
Damage = command.Damage is 0 ? 64 : command.Damage,
Hit = damageable,
2023-11-30 00:23:23 +08:00
Position = command.Position,
Rotation = Quaternion.LookRotation(command.Forward)
2023-10-24 23:37:59 +08:00
};
2023-10-24 23:37:59 +08:00
if (command.PlayerId !=default)
{
2023-10-30 01:25:53 +08:00
damageMsg.Initiator = UnityEntitiesService.Get(command.PlayerId) as IUnityEntity;
2023-10-24 23:37:59 +08:00
}
if (damageable.Health is not null && damageable.Health.IsAlive && damageCount < command.Limit)
{
damageService.Execute(damageMsg);
damageCount++;
}
2023-10-24 23:37:59 +08:00
2023-10-20 19:31:12 +08:00
damageable.Rigidbody.AddForceAtPositionAsync(command.Force, command.Position, ForceMode.Impulse)
.Forget();
2024-02-21 01:40:53 +08:00
if (x.As<MonoBehaviour>()!.TryGetComponent<ITag>(out var _tag))
2023-08-27 02:58:19 +08:00
{
2024-02-21 01:40:53 +08:00
var tags = _tag.GetTags();
var list = ArrayPool<string>.Shared.Rent(tags.Length+1);
list[^1] = "Melee";
//帮我Copy一下
Array.Copy(tags, 0, list, 0, tags.Length);
2023-10-20 19:31:12 +08:00
DI.Get<VFXService>().Spawn(new Location
{
2024-02-21 01:40:53 +08:00
//position =x.Rigidbody? x.Rigidbody.position:x.As<MonoBehaviour>().transform.position,
position = x.As<MonoBehaviour>().transform.position
2023-10-20 19:31:12 +08:00
//rotation = Quaternion.identity,
2024-02-21 01:40:53 +08:00
}, list);
ArrayPool<string>.Shared.Return(list);
2023-10-20 19:31:12 +08:00
}
}
catch (UnassignedReferenceException e)
{
2023-11-15 23:54:54 +08:00
Debug.LogWarning(x);
2023-10-20 19:31:12 +08:00
Debug.LogException(e);
2023-08-27 02:58:19 +08:00
}
2023-12-30 17:37:48 +08:00
2023-08-27 02:58:19 +08:00
}
return;
2023-12-30 17:37:48 +08:00
bool InSight(IDamagable arg)
{
if (arg is Component component)
{
var ray = new Ray(command.Position, (Vector3)component.transform.position - (Vector3)command.Position);
if (Physics.Raycast(ray, out var hit, command.Range, LayerMask.GetMask("Default")))
{
return hit.collider == component.GetComponent<Collider>();
}
}
return true;
}
float ByDistance(IDamagable arg)
{
if (arg is Component component)
{
return Vector3.Distance(component.transform.position, command.Position);
}
return 0;
}
2023-08-27 02:58:19 +08:00
}
2023-12-30 17:37:48 +08:00
2023-08-27 02:58:19 +08:00
void IMeleeService.Melee(MeleeCommand command) => Melee(command);
}
}