BITFALL/Assets/Artists/Scripts/Entities/Equipment/EntityEquipment.cs

255 lines
8.4 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BITKit;
using BITKit.Animations;
using BITKit.StateMachine;
using System.Linq;
using System.Security.Permissions;
using BITFALL;
using BITFALL.Entities.Equipment;
using BITFALL.Player.Equip;
using BITKit.Entities.Melee;
using BITKit.Entities.VFX;
using Cinemachine;
using Cysharp.Threading.Tasks;
namespace BITKit.Entities
{
public abstract class BITEquipBase<T> : StateBasedMonoBehaviour<T>, IEquipBase where T : IState
{
[Header(Constant.Header.Settings)]
[SerializeField] protected AssetableItem item;
[Header(Constant.Header.Components)]
[SerializeField] public UnityAnimator animator;
[SerializeField] protected EntityVFXPlayer vfxPlayer;
[SerializeField] protected EntityAnimator entityAnimator;
[SerializeField] private Renderer[] renderers;
[SerializeField] protected Transform cameraTransform;
[Header(Constant.Header.Services)]
[SerializeReference,SubclassSelector] protected IMeleeService meleeService;
public Entities.IEntity Entity { get; set; }
public Entity UnityEntity=>Entity as Entity;
public IBasicItem Item { get; set; }
public readonly InputActionGroup inputActionGroup = new()
{
allowGlobalActivation = true
};
protected readonly ValidHandle AllowRendering = new();
public virtual string AddressablePath => item.AddressablePath;
protected virtual Vector3 meleeForce => Transform.forward;
public bool IsEntered { get; set; }
private Quaternion _initialCameraRotation;
public virtual void Entry()
{
AllowRendering.AddElement(this);
inputActionGroup.allowInput.AddElement(this);
if (entityAnimator)
entityAnimator.enabled = true;
if (vfxPlayer)
vfxPlayer.enabled = true;
if (animator)
{
var animName = animator.animator.GetCurrentAnimatorStateInfo(0).shortNameHash;
animator.animator.Play(animName, -1, 0);
}
}
public virtual UniTask EntryAsync()
{
return UniTask.CompletedTask;
}
public virtual void Exit()
{
if (entityAnimator)
entityAnimator.enabled = false;
if (vfxPlayer)
vfxPlayer.enabled = false;
inputActionGroup.allowInput.RemoveElement(this);
}
public virtual UniTask ExitAsync()
{
AllowRendering.RemoveElement(this);
if (cameraTransform is not null)
{
cameraTransform.localPosition = default;
cameraTransform.localRotation = _initialCameraRotation;
}
return UniTask.CompletedTask;
}
public virtual void OnAwake()
{
AllowRendering.AddListener(x => renderers.ForEach(y =>
{
y.enabled = x;
animator.enabled = x;
}));
AllowRendering.Invoke();
if (cameraTransform is not null)
_initialCameraRotation = cameraTransform.localRotation;
Initialize();
inputActionGroup.allowInput.Invoke();
}
public virtual void OnDestroy()
{
inputActionGroup.Dispose();
}
public virtual void OnStart() { }
public virtual void OnUpdate(float deltaTime) { }
public virtual bool IsSupportItem(IBasicItem item) =>item is not null && item.AddressablePath == AddressablePath;
public virtual void PlayAudio(string eventName) { }
public virtual void EquipEvent(string eventName){}
public virtual void AnimationEvent(string eventName)
{
if (IsEntered is false) return;
if (item is not AssetableEquip equip) return;
switch (eventName)
{
case "Melee":
case "Attack":
meleeService.Melee(new MeleeCommand
{
PlayerId = Entity.Id,
Position = Transform.position,
Force = meleeForce * equip.MeleeForce,
Range = equip.MeleeRange,
Damage = equip.MeleeDamage,
Forward = UnityEntity.transform.forward
});
break;
case "HeavyAttack":
meleeService.Melee(new MeleeCommand
{
PlayerId = Entity.Id,
Position = Transform.position,
Force = meleeForce * equip.HeavyMeleeForce,
Range = equip.HeavyMeleeRange,
Damage = equip.HeavyMeleeDamage,
Forward = UnityEntity.transform.forward
});
break;
}
}
}
[CustomType(typeof(IEquipService))]
[CustomType(typeof(IEntityEquipment))]
public class EntityEquipment : EntityBehavior,IEquipService,IEntityEquipment
{
public IOptional<float> Zoom { get; } = new Optional<float>(){Value = 1};
public float InitialFov;
[SerializeField] private CinemachineVirtualCamera virtualCamera;
[SerializeField] private Optional<int> overrideIndex;
public event Action<IBasicItem> OnEquip;
public event Action<IBasicItem> OnUnEquip;
public event Action<string> OnEquipAddressable;
public event Action<string> OnUnEquipAddressable;
private readonly EntryGroup<IEquipBase> equips = new();
protected IEquipBase entryComplete;
private PlayerConfig playerConfig;
private IBasicItem _currentItem;
[Inject(true)] private IHealth _health;
public override void OnAwake()
{
base.OnAwake();
equips.list = GetComponentsInChildren<IEquipBase>(true).ToList();
equips.OnEntry += OnEntry;
equips.OnExit += OnExit;
if (_health is not null)
{
_health.OnSetAlive += x =>
{
if (x is false)
EntryEquip(-1);
};
}
foreach (var x in equips.list)
{
x.Entity = UnityEntity;
x.OnAwake();
}
}
public override void OnStart()
{
base.OnStart();
foreach (var x in equips.list)
{
x.OnStart();
}
}
private void OnExit(IEquipBase obj)
{
OnUnEquipAddressable?.Invoke(obj.AddressablePath);
OnUnEquip?.Invoke(obj.Item);
//Debug.Log($"已退出:{obj.Item.Name}");
obj.Item = null;
}
private void OnEntry(IEquipBase obj)
{
OnEquipAddressable?.Invoke(obj.AddressablePath);
obj.Item = _currentItem;
OnEquip?.Invoke(obj.Item);
//Debug.Log($"已进入:{obj.Item.Name}");
}
public override void OnUpdate(float deltaTime)
{
if (equips.TryGetEntried(out entryComplete))
{
entryComplete.OnUpdate(deltaTime);
}
if (virtualCamera is not null)
{
var current = virtualCamera.m_Lens.FieldOfView;
current= Mathf.Lerp(current,Zoom.Allow ? InitialFov / Zoom.Value : PlayerConfig.Singleton.Fov , deltaTime * 5);
current = Mathf.Clamp(current, 10, PlayerConfig.Singleton.Fov);
virtualCamera.m_Lens.FieldOfView = current;
}
if (overrideIndex.Allow && (_health?.IsAlive ?? true))
{
EntryEquip(overrideIndex.Value);
}
}
public bool IsSupportItem(IBasicItem item)=> equips.list.Any(x => x.IsSupportItem(item));
public void EntryEquip(int index)=> equips.Entry(index);
public void EntryEquip(Func<string,bool> factory)=>equips.Entry(x=>factory.Invoke(x.AddressablePath));
public void EntryEquip(IBasicItem item)
{
_currentItem = item;
equips.Entry(x=>x.IsSupportItem(item));
}
}
}