BITFALL/Assets/Artists/Scripts/UX/UXHud.cs

431 lines
15 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using BITFALL.Entities;
using BITFALL.Entities.Armor;
using BITFALL.Entities.Equipment;
using BITFALL.Guns;
using BITFALL.Player.Equip;
using BITFALL.Player.Inventory;
using BITFALL.Player.Movement;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEngine.InputSystem;
using BITKit;
using BITKit.UX;
using BITKit.Entities;
using BITKit.Entities.Player;
using BITKit.SceneManagement;
using BITKit.Selection;
using BITKit.Steamwork;
using BITKit.Tween;
using Cysharp.Threading.Tasks;
using UnityEditor;
using UnityEngine.InputSystem.Interactions;
using Image = UnityEngine.UI.Image;
namespace BITFALL.UX
{
public class UXHud : UIToolKitPanel
{
[Header(Constant.Header.Providers)]
[SerializeReference, SubclassSelector] private ISceneService sceneService;
[SerializeReference, SubclassSelector] private IPlayerService playerService;
[SerializeReference, SubclassSelector] private ISteamService steamService;
[Header(Constant.Header.Components)]
[SerializeField] private UXImage crosshairImage;
[SerializeField] private UXImage crosshairParentImage;
[SerializeField] private UXLabel playerNameLabel;
[SerializeField] private UXImage playerAvatarImage;
[SerializeField] private UXElement playerInfo;
[SerializeField] private UXBar healthBar;
[SerializeField] private UXBar lerpHealthBar;
[SerializeField] private UXBar staminaBar;
[SerializeField] private UXBar armorBar;
[Header(Constant.Header.Input)]
[SerializeField] private InputActionReference inventoryAction;
[SerializeField] private InputActionReference returnAction;
[SerializeField] private InputActionReference inspectAction;
[SerializeField] private InputActionReference radialMenuAction;
[Header(Constant.Header.Input)]
[SerializeField] private InputActionReference interactiveAction;
[Inject]
private IHealth _health;
[Inject]
private IEntityMovement _entityMovement;
[Inject]
private IPlayerMovement _playerMovement;
[Inject]
private IEquipService _equipService;
[Inject]
private IEntityEquipment _equipment;
[Inject]
private ISelector _selector;
[Inject]
private IArmor _armor;
[Inject]
private IKnockdown _knockdown;
[Inject]
private IPlayerInventory _playerInventory;
[UXBindPath("count-label")]
private Label countLabel;
[UXBindPath("injury-container")]
private VisualElement injuryContainer;
[UXBindPath("bloody-container")]
private VisualElement bloodyContainer;
[UXBindPath("knocked-fill")]
private VisualElement knockedFill;
[UXBindPath("health-fill")]
private VisualElement healthFill;
[UXBindPath("money-label")]
private Label moneyLabel;
private VisualElement[] swayElements;
private float _currentHealthLerp;
protected CancellationTokenSource bloodyScreenCancellationTokenSource;
private string _interactiveKey="F";
protected override void Start()
{
base.Start();
sceneService.OnSceneLoaded += x=>Entry();
playerService.OnPlayerInitialized += OnPlayerInitializedLocalPlayer;
BITKit.UX.UXUtils.Inject(this);
bloodyContainer.SetOpacity(0);
injuryContainer.SetOpacity(0);
swayElements = document.rootVisualElement.Query(className: "swap").ToList().ToArray();
}
protected override void OnPanelEntry()
{
base.OnPanelEntry();
inputActionGroup.RegisterCallback(returnAction, OnReturn);
inputActionGroup.RegisterCallback(inventoryAction, OnInventory);
inputActionGroup.RegisterCallback(inspectAction, OnInspect);
inputActionGroup.RegisterCallback(radialMenuAction, OnRadialMenu);
}
protected override void OnPanelExit()
{
base.OnPanelExit();
inputActionGroup.UnRegisterCallback(returnAction, OnReturn);
inputActionGroup.UnRegisterCallback(inventoryAction, OnInventory);
inputActionGroup.UnRegisterCallback(inspectAction, OnInspect);
inputActionGroup.UnRegisterCallback(radialMenuAction, OnRadialMenu);
}
private void OnInspect(InputAction.CallbackContext obj)
{
switch (obj,_equipment)
{
case ({interaction:HoldInteraction,performed:true}, {CurrentItem: not null}):
UXInventoryInspector.Entry(_equipment.CurrentItem);
break;
}
}
private static void OnRadialMenu(InputAction.CallbackContext obj)
{
// Debug.Log(obj);
switch (obj)
{
case {interaction:HoldInteraction,performed:true}:
UXService.Entry<UXRadialMenu>();
break;
case {interaction:HoldInteraction,canceled:true}:
break;
}
}
private void OnDestroy()
{
playerService.OnPlayerInitialized -= OnPlayerInitializedLocalPlayer;
}
public void OnSelect(ISelectable selectable)
{
}
public void OnInactive(ISelectable selectable)
{
//seleableLabel.SetActive(false);
UXOnScreenPrompts.Release(_interactiveKey);
}
private async void OnPlayerInitializedLocalPlayer(IUnityEntity unityEntity)
{
unityEntity.Inject(this);
_health.OnDamageRelease += OnDamageRelease;
_health.OnSetAlive += OnSetAlive;
_health.OnSetHealthPoint += OnSetHP;
_selector.OnInactive += OnInactive;
_selector.OnSelected += OnSelect;
_armor.OnArmorChanged += x => armorBar.Set(x);
_armor.OnEquipArmor += x =>
{
armorBar.Set(_armor.Armor);
armorBar.SetActive(true);
};
_knockdown.OnKnockdown+=OnKnockdown;
_knockdown.OnRevive+=OnRevive;
_armor.OnUnEquipArmor += x => armorBar.SetActive(false);
if (steamService.IsInitialized)
{
playerNameLabel.Set(steamService.Name);
var avatar = await steamService.GetAvatarAsync(cancellationToken);
playerAvatarImage.SetTexture(avatar);
}
_equipService = unityEntity.Get<IEquipService>();
armorBar.SetActive(_armor.TryGetCurrentArmor(out _));
OnSetHP(_health.HealthPoint);
OnSetAlive(_health.IsAlive);
OnInactive(null);
OnRevive();
_interactiveKey = interactiveAction.GetKeyMap();
}
private void OnRevive()
{
knockedFill.SetActive(false);
healthFill.SetActive(true);
}
private void OnKnockdown()
{
knockedFill.SetActive(true);
healthFill.SetActive(false);
}
private void OnDamageRelease(DamageMessage message)
{
bloodyScreenCancellationTokenSource?.Cancel();
bloodyScreenCancellationTokenSource = new CancellationTokenSource();
destroyCancellationToken.Register(bloodyScreenCancellationTokenSource.Cancel);
var tweenSequence = BITween.CreateSequence();
tweenSequence.Append(
BITween.MoveToForward(
bloodyContainer.SetOpacity,
0,
1,
0.25f,
bloodyScreenCancellationTokenSource.Token)
);
tweenSequence.Append(
BITween.MoveToForward(
bloodyContainer.SetOpacity,
1,
0,
0.5f,
bloodyScreenCancellationTokenSource.Token)
);
tweenSequence.Play(bloodyScreenCancellationTokenSource.Token).Forget();
}
private void OnInventory(InputAction.CallbackContext context)
{
if(playerService.LocalPlayer is null) return;
if(_health.IsAlive is false) return;
if(context is {interaction:PressInteraction,performed:true})
UXService.Entry<UXInventory>();
}
private void Update()
{
if (_health is not null)
{
_currentHealthLerp =
Mathf.MoveTowards(_currentHealthLerp, _health.HealthPoint * 0.01f, Time.deltaTime * 5).Fix();
_currentHealthLerp = Mathf.Clamp(_currentHealthLerp, 0, 1);
lerpHealthBar.SetDirect(_currentHealthLerp, _health.HealthPoint.ToString());
staminaBar.Set(_playerMovement.Stamina * 0.01f);
staminaBar.visualElement.parent.SetActive(_playerMovement.Stamina is not 100);
crosshairImage.visualElement.SetActive(_equipService.AllowAttack);
crosshairImage.visualElement.transform.scale =
Vector3.one *
Mathf.Lerp(1.25f, 1, _equipService.Stable);
if (_health.HealthPoint < 50)
{
injuryContainer.SetOpacity(
0.8f + Mathf.Sin(Time.time * 10) * 0.2f
);
}
if (_selector.TryGetCurrentSelectable(out var selectable))
{
UXOnScreenPrompts.Get(_interactiveKey,
selectable.Transform.TryGetComponent<IDescription>(out var description)
? description.Name
: "互动");
// switch (selectable,selectable.Transform.GetComponentInChildren<ICondition>())
// {
// case (not null, { } condition):
// if (condition.Allow)
// {
// UXOnScreenPrompts.Get(_interactiveKey,
// selectable.Transform.TryGetComponent<IDescription>(out var description)
// ? description.Name
// : "互动");
// }
// else
// {
// UXOnScreenPrompts.Get(_interactiveKey,
// selectable.Transform.TryGetComponent<IDescription>(out var description)
// ? description.Name
// : $"互动\t{condition.Reason}");
// }
// break;
// case (not null, null):
// {
// UXOnScreenPrompts.Get(_interactiveKey,
// selectable.Transform.TryGetComponent<IDescription>(out var description)
// ? description.Name
// : "互动");
// }
// break;
// }
}
}
if (_knockdown is {IsKnockdown:true})
{
knockedFill.style.width = new StyleLength(Length.Percent(_knockdown.KnockedHealth));
}
countLabel.SetVisible(false);
if (_playerInventory is not null)
{
moneyLabel.text = _playerInventory.Money.ToString();
}
if (_equipment is not null)
{
if (_equipment.CurrentItem is not null)
{
switch (_equipment.CurrentItem)
{
case var x when x.TryGetProperty<IClip>(out var clip):
countLabel.text = clip.ToString();
countLabel.SetVisible(true);
break;
case var x when x.TryGetProperty<ICount>(out var count):
countLabel.text = count.Count.ToString();
countLabel.SetVisible(true);
break;
}
}
}
}
private void LateUpdate()
{
if (playerService.LocalPlayer is null) return;
if(_equipService is null) return;
var currentCrosshairOpacity = crosshairParentImage.visualElement.style.opacity.value;
crosshairParentImage.visualElement.style.opacity =
_equipService.AllowScope?0:
Mathf.Lerp(currentCrosshairOpacity, _equipService.Zoom.Allow ? 0 : 1, Time.deltaTime * 5);
{
var crossHairElement = crosshairImage.visualElement;
var pos = crossHairElement.GetPosition();
var targetPos = crossHairElement.GetScreenPosition(_entityMovement.FocusPoint);
crossHairElement.SetPosition(
Vector2.Lerp(pos, targetPos, 8 * Time.deltaTime)
);
}
{
var movementVelocity = _entityMovement.LocomotionBasedVelocity * 16;
var velocity =
-_entityMovement.AngularVelocity * 10
-new Vector3(-movementVelocity.z,movementVelocity.x);
var newPos = new Vector3()
{
x = velocity.y,
y = velocity.x,
};
foreach (var x in swayElements)
{
var currentPos = x.transform.position;
newPos = Vector3.Lerp(currentPos, newPos, Time.deltaTime * 10);
x.transform.position = newPos;
}
}
}
private static void OnReturn(InputAction.CallbackContext context)
{
if (context is {interaction:PressInteraction,performed:true})
UXService.Entry<UXMenu>();
}
private void OnSetAlive(bool alive)
{
if (alive is false)
{
Entry();
}
crosshairImage.SetActive(alive);
crosshairParentImage.SetActive(alive);
playerInfo.SetActive(alive);
OnRevive();
}
private void OnSetHP(int hp)
{
healthBar.Set(Mathf.Clamp(hp,0,100) * 0.01f);
injuryContainer.SetOpacity(
hp< 60 ? Mathf.InverseLerp(40,60,hp) : 0
);
}
}
}