Net.Like.Xue.Tokyo/Assets/Artists/Scripts/GodMode.cs

261 lines
8.9 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using BITKit;
using BITKit.Entities;
using BITKit.Tween;
using BITKit.UX;
using Cysharp.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Net.Project.B.Emoji;
using Net.Project.B.Health;
using Net.Project.B.UX;
using Project.B.CharacterController;
using Project.B.Entities;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UIElements;
using Object = UnityEngine.Object;
namespace Net.Like.Xue.Tokyo
{
public class GodMode:IDisposable
{
private readonly IUXHud _hud;
private readonly IEntitiesService _entitiesService;
private readonly IHealthService _healthService;
private readonly IMainTicker _ticker;
private readonly IAfterTicker _afterTicker;
private readonly ValidHandle _allow = new();
private readonly ILogger<GodMode> _logger;
private readonly IPlayerFactory _playerFactory;
private readonly ScriptableYangdunData _data;
private bool _allowGodMode;
private bool _allowNfc;
[UXBindPath("god_mode-banner")]
private VisualElement _godModeBanner;
[UXBindPath("nfc-texture")]
private VisualElement _nfcTexture;
[UXBindPath("game_over-banner")]
private VisualElement _gameOverBanner;
private readonly List<Transform> _followVfx=new();
private int _currentNfcIndex;
public GodMode(IMainTicker ticker, IHealthService healthService, ILogger<GodMode> logger, IEntitiesService entitiesService, IUXHud hud, IAfterTicker afterTicker, IPlayerFactory playerFactory)
{
_ticker = ticker;
_healthService = healthService;
_logger = logger;
_entitiesService = entitiesService;
_hud = hud;
_afterTicker = afterTicker;
_playerFactory = playerFactory;
_ticker.Add(OnTick);
_afterTicker.Add(AfterTick);
_healthService.OnHealthPlus += OnHealthPlus;
_allow.AddListener(OnAllow);
_data = _entitiesService.QueryComponents<ScriptableYangdunData>()[0];
_hud.OnInitiated += OnInitiated;
_playerFactory.OnEntityCreated += OnEntityCreated;
}
private UniTask OnEntityCreated(string arg1, IEntity arg2)
{
arg2.ServiceProvider.QueryComponents(out IHealthComponent healthComponent);
healthComponent.OnHealthChanged += OnHealthChanged;
return UniTask.CompletedTask;
}
private void OnHealthChanged(int arg1, int arg2)
{
_gameOverBanner.SetActive(arg2<0);
_hud.InCinematicMode.SetDisableElements(this,arg2<0);
}
private void AfterTick(float obj)
{
if(!_allowNfc)return;
foreach (var (_,characterController) in _entitiesService.QueryComponents<LocalPlayerComponent,ICharacterController>())
{
_nfcTexture.SetPosition(characterController.Position + new float3(0,characterController.Height,0));
}
}
private void OnInitiated()
{
if(_hud is not UIToolKitPanel panel)return;
UXUtils.Inject(this,panel.RootVisualElement);
_godModeBanner.RemoveFromClassList("active");
_godModeBanner.SetActive(false);
_gameOverBanner.SetActive(false);
_hud.InCinematicMode.RemoveElement(this);
_nfcTexture.schedule.Execute(() =>
{
if (!_allowNfc)return;
_nfcTexture.style.backgroundImage = new(_data.NfcSprites[_currentNfcIndex++%_data.NfcSprites.Length]);
}).Every(41);
_nfcTexture.SetActive(false);
}
private void OnAllow(bool allow)
{
_logger.LogInformation(allow ? "开启无敌" : "关闭无敌");
_godModeBanner.SetActive(allow);
_godModeBanner.EnableInClassList("active",allow);
_nfcTexture.SetActive(_allowNfc=false);
if (!allow)
{
foreach (var transform in _followVfx)
{
Object.Destroy(transform.gameObject);
}
_followVfx.Clear();
return;
}
foreach (var (_, emojiService,gameObject,characterController) in _entitiesService
.QueryComponents<LocalPlayerComponent, IEmojiService<AnimationClip>,GameObject,ICharacterController>())
{
emojiService.Play(new EmojiData<AnimationClip>()
{
Clip = _data.BoostAnimation
});
{
var groundVfx = Object.Instantiate(_data.GroundVfx.gameObject, characterController.Position,characterController.Rotation);
{
if (groundVfx.TryGetComponent<ParticleSystem>(out var vfx))
{
vfx.Play(true);
}
}
DestroyAfter(groundVfx.transform, 3);
}
{
gameObject.TryGetComponent<Animator>(out var animator);
foreach (var (humanBone,particleSystems) in _data.BoneVfx)
{
var bone = animator.GetBoneTransform(humanBone);
if (!bone)
{
_logger.LogWarning($"在{animator.gameObject.name}上没有找到骨骼:{humanBone}");
continue;
}
foreach (var particleSystem in particleSystems)
{
var bodyVfx = Object.Instantiate(particleSystem.gameObject, bone.position, bone.rotation);
if (!bodyVfx.TryGetComponent<ParticleSystem>(out var vfx)) continue;
vfx.Play(true);
DestroyAfter(bodyVfx.transform,5);
//vfx.Stop(withChildren: true, stopBehavior: ParticleSystemStopBehavior.StopEmitting);
}
}
foreach (var (humanBone,particleSystems) in _data.FollowVfx)
{
var bone = animator.GetBoneTransform(humanBone);
if (!bone)
{
_logger.LogWarning($"在{animator.gameObject.name}上没有找到骨骼:{humanBone}");
continue;
}
foreach (var particleSystem in particleSystems)
{
var bodyVfx = Object.Instantiate(particleSystem.gameObject, bone.position, bone.rotation);
bodyVfx.transform.SetParentConstraint(bone);
if (!bodyVfx.TryGetComponent<ParticleSystem>(out var vfx)) continue;
vfx.Play(true);
_followVfx.Add(bodyVfx.transform);
}
}
}
}
}
private int OnHealthPlus(int arg1, int arg2, int arg3, object arg4)
{
if (_allow.Allow)
{
return 0;
}
return arg3;
}
protected virtual async void DestroyAfter(Transform transform,float time)
{
try
{
var ct = transform.GetCancellationTokenOnDestroy();
await UniTask.Delay(TimeSpan.FromSeconds(time),cancellationToken: ct);
await BITween.Lerp(x => transform.localScale = x, Vector3.one, default, 1, Vector3.Lerp, ct);
Object.Destroy(transform.gameObject);
}
catch (OperationCanceledException)
{
}
}
private void OnTick(float obj)
{
if (Keyboard.current is { homeKey: { wasPressedThisFrame: true } })
{
_allow.SetElements(this,_allowGodMode=!_allowGodMode);
}
if (Keyboard.current is { endKey: { wasPressedThisFrame: true } })
{
_nfcTexture.SetActive(_allowNfc=!_allowNfc);
}
}
public void Dispose()
{
_ticker.Remove(OnTick);
_afterTicker.Remove(AfterTick);
}
}
}