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

431 lines
15 KiB
C#
Raw Normal View History

2023-08-23 01:59:40 +08:00
using System;
2023-06-08 14:09:50 +08:00
using System.Collections;
using System.Collections.Generic;
using System.Linq;
2023-12-15 00:08:02 +08:00
using System.Threading;
using BITFALL.Entities;
2023-10-20 22:46:14 +08:00
using BITFALL.Entities.Armor;
2023-12-03 17:35:43 +08:00
using BITFALL.Entities.Equipment;
using BITFALL.Guns;
2023-10-02 23:24:56 +08:00
using BITFALL.Player.Equip;
2024-01-03 00:27:12 +08:00
using BITFALL.Player.Inventory;
2023-10-20 19:31:12 +08:00
using BITFALL.Player.Movement;
2023-06-08 14:09:50 +08:00
using UnityEngine;
using UnityEngine.UIElements;
using UnityEngine.InputSystem;
using BITKit;
using BITKit.UX;
using BITKit.Entities;
2023-08-27 02:58:19 +08:00
using BITKit.Entities.Player;
2023-10-20 19:31:12 +08:00
using BITKit.SceneManagement;
using BITKit.Selection;
2023-09-01 14:33:54 +08:00
using BITKit.Steamwork;
2023-12-15 00:08:02 +08:00
using BITKit.Tween;
using Cysharp.Threading.Tasks;
2023-10-02 23:24:56 +08:00
using UnityEditor;
2023-10-24 23:37:59 +08:00
using UnityEngine.InputSystem.Interactions;
2023-11-30 00:23:23 +08:00
using Image = UnityEngine.UI.Image;
2023-08-27 02:58:19 +08:00
2023-06-08 14:09:50 +08:00
namespace BITFALL.UX
{
2023-10-20 19:31:12 +08:00
public class UXHud : UIToolKitPanel
2023-06-08 14:09:50 +08:00
{
2023-06-17 16:30:53 +08:00
[Header(Constant.Header.Providers)]
2023-10-20 19:31:12 +08:00
[SerializeReference, SubclassSelector] private ISceneService sceneService;
2023-09-01 14:33:54 +08:00
[SerializeReference, SubclassSelector] private IPlayerService playerService;
[SerializeReference, SubclassSelector] private ISteamService steamService;
[Header(Constant.Header.Components)]
[SerializeField] private UXImage crosshairImage;
2023-10-02 23:24:56 +08:00
[SerializeField] private UXImage crosshairParentImage;
2023-12-15 00:08:02 +08:00
2023-09-01 14:33:54 +08:00
[SerializeField] private UXLabel playerNameLabel;
[SerializeField] private UXImage playerAvatarImage;
2023-10-20 19:31:12 +08:00
[SerializeField] private UXElement playerInfo;
2023-09-01 14:33:54 +08:00
[SerializeField] private UXBar healthBar;
2023-10-20 19:31:12 +08:00
[SerializeField] private UXBar lerpHealthBar;
[SerializeField] private UXBar staminaBar;
2023-10-20 22:46:14 +08:00
[SerializeField] private UXBar armorBar;
2023-09-01 14:33:54 +08:00
2023-06-08 14:09:50 +08:00
[Header(Constant.Header.Input)]
2023-10-24 23:37:59 +08:00
[SerializeField] private InputActionReference inventoryAction;
[SerializeField] private InputActionReference returnAction;
2023-12-03 17:35:43 +08:00
[SerializeField] private InputActionReference inspectAction;
2024-01-03 00:27:12 +08:00
[SerializeField] private InputActionReference radialMenuAction;
[Header(Constant.Header.Input)]
[SerializeField] private InputActionReference interactiveAction;
2023-10-20 19:31:12 +08:00
[Inject]
2023-08-27 02:58:19 +08:00
private IHealth _health;
2023-10-20 19:31:12 +08:00
[Inject]
private IEntityMovement _entityMovement;
[Inject]
private IPlayerMovement _playerMovement;
[Inject]
2023-10-02 23:24:56 +08:00
private IEquipService _equipService;
2023-10-20 19:31:12 +08:00
[Inject]
2023-12-03 17:35:43 +08:00
private IEntityEquipment _equipment;
[Inject]
2023-10-20 19:31:12 +08:00
private ISelector _selector;
2023-10-20 22:46:14 +08:00
[Inject]
private IArmor _armor;
[Inject]
private IKnockdown _knockdown;
2024-01-03 00:27:12 +08:00
[Inject]
private IPlayerInventory _playerInventory;
2023-12-03 17:35:43 +08:00
2023-12-15 00:08:02 +08:00
[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")]
2024-01-03 00:27:12 +08:00
private VisualElement healthFill;
[UXBindPath("money-label")]
private Label moneyLabel;
2023-12-03 17:35:43 +08:00
2023-12-15 20:03:44 +08:00
private VisualElement[] swayElements;
2023-10-20 19:31:12 +08:00
private float _currentHealthLerp;
2023-12-15 00:08:02 +08:00
protected CancellationTokenSource bloodyScreenCancellationTokenSource;
private string _interactiveKey="F";
2024-01-03 00:27:12 +08:00
protected override void Start()
2023-06-08 14:09:50 +08:00
{
2024-01-03 00:27:12 +08:00
base.Start();
2023-06-08 14:09:50 +08:00
2023-10-20 19:31:12 +08:00
sceneService.OnSceneLoaded += x=>Entry();
2023-09-01 14:33:54 +08:00
2023-10-20 19:31:12 +08:00
playerService.OnPlayerInitialized += OnPlayerInitializedLocalPlayer;
2023-12-03 17:35:43 +08:00
BITKit.UX.UXUtils.Inject(this);
2023-12-15 00:08:02 +08:00
bloodyContainer.SetOpacity(0);
injuryContainer.SetOpacity(0);
2023-12-15 20:03:44 +08:00
swayElements = document.rootVisualElement.Query(className: "swap").ToList().ToArray();
2023-12-03 17:35:43 +08:00
}
2024-01-03 00:27:12 +08:00
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);
}
2023-12-03 17:35:43 +08:00
private void OnInspect(InputAction.CallbackContext obj)
{
switch (obj,_equipment)
{
case ({interaction:HoldInteraction,performed:true}, {CurrentItem: not null}):
UXInventoryInspector.Entry(_equipment.CurrentItem);
break;
}
2023-06-08 14:09:50 +08:00
}
2024-01-03 00:27:12 +08:00
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;
}
}
2023-08-12 01:43:24 +08:00
2023-08-23 01:59:40 +08:00
private void OnDestroy()
{
2023-08-27 02:58:19 +08:00
playerService.OnPlayerInitialized -= OnPlayerInitializedLocalPlayer;
2023-08-23 01:59:40 +08:00
}
2023-12-15 00:08:02 +08:00
2023-10-20 19:31:12 +08:00
public void OnSelect(ISelectable selectable)
2023-06-08 14:09:50 +08:00
{
2023-11-30 00:23:23 +08:00
2023-06-08 14:09:50 +08:00
}
public void OnInactive(ISelectable selectable)
{
//seleableLabel.SetActive(false);
UXOnScreenPrompts.Release(_interactiveKey);
2023-06-08 14:09:50 +08:00
}
2023-10-30 01:25:53 +08:00
private async void OnPlayerInitializedLocalPlayer(IUnityEntity unityEntity)
2023-06-08 14:09:50 +08:00
{
2023-10-30 01:25:53 +08:00
unityEntity.Inject(this);
2023-12-15 00:08:02 +08:00
_health.OnDamageRelease += OnDamageRelease;
2023-10-20 19:31:12 +08:00
2023-08-27 02:58:19 +08:00
_health.OnSetAlive += OnSetAlive;
2023-09-01 14:33:54 +08:00
_health.OnSetHealthPoint += OnSetHP;
2023-10-20 19:31:12 +08:00
_selector.OnInactive += OnInactive;
_selector.OnSelected += OnSelect;
2023-10-20 22:46:14 +08:00
_armor.OnArmorChanged += x => armorBar.Set(x);
_armor.OnEquipArmor += x =>
{
armorBar.Set(_armor.Armor);
armorBar.SetActive(true);
};
_knockdown.OnKnockdown+=OnKnockdown;
_knockdown.OnRevive+=OnRevive;
2023-10-20 22:46:14 +08:00
_armor.OnUnEquipArmor += x => armorBar.SetActive(false);
2023-10-20 19:31:12 +08:00
if (steamService.IsInitialized)
{
playerNameLabel.Set(steamService.Name);
var avatar = await steamService.GetAvatarAsync(cancellationToken);
playerAvatarImage.SetTexture(avatar);
}
2023-10-02 23:24:56 +08:00
2023-10-30 01:25:53 +08:00
_equipService = unityEntity.Get<IEquipService>();
2023-10-20 19:31:12 +08:00
2023-10-20 22:46:14 +08:00
armorBar.SetActive(_armor.TryGetCurrentArmor(out _));
2023-10-20 19:31:12 +08:00
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);
2023-06-08 14:09:50 +08:00
}
2023-12-15 00:08:02 +08:00
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();
}
2023-08-27 02:58:19 +08:00
private void OnInventory(InputAction.CallbackContext context)
2023-06-08 14:09:50 +08:00
{
2023-08-27 02:58:19 +08:00
if(playerService.LocalPlayer is null) return;
if(_health.IsAlive is false) return;
2023-10-24 23:37:59 +08:00
if(context is {interaction:PressInteraction,performed:true})
2023-08-27 02:58:19 +08:00
UXService.Entry<UXInventory>();
2023-06-08 14:09:50 +08:00
}
2023-09-01 14:33:54 +08:00
2023-10-20 19:31:12 +08:00
private void Update()
{
if (_health is not null)
{
_currentHealthLerp =
Mathf.MoveTowards(_currentHealthLerp, _health.HealthPoint * 0.01f, Time.deltaTime * 5).Fix();
2023-10-20 19:31:12 +08:00
_currentHealthLerp = Mathf.Clamp(_currentHealthLerp, 0, 1);
lerpHealthBar.SetDirect(_currentHealthLerp, _health.HealthPoint.ToString());
2023-10-20 19:31:12 +08:00
staminaBar.Set(_playerMovement.Stamina * 0.01f);
2023-10-31 18:07:15 +08:00
2023-10-20 19:31:12 +08:00
staminaBar.visualElement.parent.SetActive(_playerMovement.Stamina is not 100);
2023-10-31 18:07:15 +08:00
crosshairImage.visualElement.SetActive(_equipService.AllowAttack);
2023-10-31 18:07:15 +08:00
crosshairImage.visualElement.transform.scale =
Vector3.one *
Mathf.Lerp(1.25f, 1, _equipService.Stable);
2023-12-15 00:08:02 +08:00
if (_health.HealthPoint < 50)
{
injuryContainer.SetOpacity(
0.8f + Mathf.Sin(Time.time * 10) * 0.2f
);
2023-12-15 00:08:02 +08:00
}
2023-11-30 00:23:23 +08:00
if (_selector.TryGetCurrentSelectable(out var selectable))
{
UXOnScreenPrompts.Get(_interactiveKey,
selectable.Transform.TryGetComponent<IDescription>(out var description)
2023-11-30 00:23:23 +08:00
? 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;
// }
2023-11-30 00:23:23 +08:00
}
2023-10-20 19:31:12 +08:00
}
2023-12-03 17:35:43 +08:00
if (_knockdown is {IsKnockdown:true})
{
knockedFill.style.width = new StyleLength(Length.Percent(_knockdown.KnockedHealth));
}
2023-12-03 17:35:43 +08:00
countLabel.SetVisible(false);
2024-01-03 00:27:12 +08:00
if (_playerInventory is not null)
{
moneyLabel.text = _playerInventory.Money.ToString();
}
2023-12-03 17:35:43 +08:00
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;
}
}
}
2023-10-20 19:31:12 +08:00
}
2023-09-01 14:33:54 +08:00
private void LateUpdate()
{
if (playerService.LocalPlayer is null) return;
2023-10-20 19:31:12 +08:00
2023-11-30 00:23:23 +08:00
2023-10-02 23:24:56 +08:00
if(_equipService is null) return;
var currentCrosshairOpacity = crosshairParentImage.visualElement.style.opacity.value;
2023-11-02 20:58:55 +08:00
crosshairParentImage.visualElement.style.opacity =
_equipService.AllowScope?0:
Mathf.Lerp(currentCrosshairOpacity, _equipService.Zoom.Allow ? 0 : 1, Time.deltaTime * 5);
2023-12-15 00:08:02 +08:00
{
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,
};
2023-12-15 20:03:44 +08:00
foreach (var x in swayElements)
{
var currentPos = x.transform.position;
newPos = Vector3.Lerp(currentPos, newPos, Time.deltaTime * 10);
x.transform.position = newPos;
}
2023-12-15 00:08:02 +08:00
}
2023-09-01 14:33:54 +08:00
}
2023-08-27 02:58:19 +08:00
private static void OnReturn(InputAction.CallbackContext context)
{
2024-01-03 00:27:12 +08:00
if (context is {interaction:PressInteraction,performed:true})
2023-10-20 19:31:12 +08:00
UXService.Entry<UXMenu>();
2023-08-27 02:58:19 +08:00
}
private void OnSetAlive(bool alive)
2023-06-08 14:09:50 +08:00
{
2023-08-27 02:58:19 +08:00
if (alive is false)
{
Entry();
}
2023-10-20 19:31:12 +08:00
crosshairImage.SetActive(alive);
crosshairParentImage.SetActive(alive);
playerInfo.SetActive(alive);
OnRevive();
2023-06-08 14:09:50 +08:00
}
2023-09-01 14:33:54 +08:00
private void OnSetHP(int hp)
{
2023-10-20 19:31:12 +08:00
healthBar.Set(Mathf.Clamp(hp,0,100) * 0.01f);
2023-11-30 00:23:23 +08:00
2023-12-15 00:08:02 +08:00
injuryContainer.SetOpacity(
2023-12-15 20:03:44 +08:00
hp< 60 ? Mathf.InverseLerp(40,60,hp) : 0
2023-12-15 00:08:02 +08:00
);
2023-09-01 14:33:54 +08:00
}
2023-06-08 14:09:50 +08:00
}
}