using System.Collections.Generic; using System.Threading.Tasks; using asap.core; using DG.Tweening; using Game; using UI.Wheel; using UnityEngine; namespace UI.HookWheel { public class HookWheelRewardComponent : AbstractWheelRewardComponent { private Tweener _tweener; private int currentSegment; private int lastSegment; private float lastValue; protected override string StartSound => "audio_ui_hookwheel_arrow_spin_start"; protected override string LoopedSound => "audio_ui_hookwheel_arrow_spin_loop"; protected override string EndSound => "audio_ui_hookwheel_arrow_spin_end"; protected override void Awake() { base.Awake(); fx_spin = gameObject.FindChildGameObject("fx_ui_hookwheel_spin")?.gameObject; fx_arrow_spin = gameObject.FindChildGameObject("fx_ui_hookwheel_arrow_spin")?.gameObject; lightAni = gameObject.FindChildGameObject("p_light")?.GetComponent(); zhizhenTrans = gameObject.FindChildGameObject("zhizhen")?.GetComponent(); for (var i = 1; i <= 3; i++) { var key = $"fx_ui_hookwheel_reward_claim_0{i}"; if (_fxNameObjs.ContainsKey(key)) continue; var fx = gameObject.FindChildGameObject(key)?.gameObject; if (fx == null) continue; fx.SetActive(false); _fxNameObjs.Add(key, fx); } } protected override void Start() { base.Start(); lightAni.Play("light_idle"); } protected override void InitUI() { base.InitUI(); fx_spin.SetActive(false); fx_arrow_spin.SetActive(false); wheelClipLoop = lightAni?["light_spin_loop"]; } public override void SetData(List rewards) { for (var i = 0; i < rewards.Count && i < wheelRewardCells.Length; i++) wheelRewardCells[i].SetData(rewards[i]); } public override void ShowUI() { foreach (var rewardCell in wheelRewardCells) rewardCell.ShowUI(); } public RectTransform GetRewardFlySource(int index) { return (wheelRewardCells[index] as HookWheelRewardCell)?.RewardFlySource; } protected override void EffectStart() { base.EffectStart(); InitPointerAni(); _ = LightStarAni(); foreach (var fx in _fxNameObjs) fx.Value?.SetActive(false); fx_arrow_spin.SetActive(true); } protected override void EffectUpdate(float currentVelocity, float currentValue) { base.EffectUpdate(currentVelocity, currentValue); SetClipLoopSpeed(currentVelocity); PointerAni(currentValue, currentVelocity); } protected override async Task EffectEnd(IWheelReward reward) { fx_spin.SetActive(false); fx_arrow_spin.SetActive(false); if (_fxNameObjs.TryGetValue(reward.Fx, out var value)) value.SetActive(true); zhizhenTrans.rotation = Quaternion.Euler(0, 0, 0); if (!string.IsNullOrEmpty(reward.Audio)) GContext.Publish(new EventUISound(reward.Audio)); await base.EffectEnd(reward); lightAni.Play("light_idle"); } protected override async Task DelayShow() { await base.DelayShow(); fx_spin?.SetActive(true); } protected override void RevertTargetEndCallbcak() { base.RevertTargetEndCallbcak(); _ = LightEndAni(); } #region ui private GameObject fx_spin; private GameObject fx_arrow_spin; private Animation lightAni; private AnimationState wheelClipLoop; private Transform zhizhenTrans; private readonly Dictionary _fxNameObjs = new(); #endregion ui #region private private void SetClipLoopSpeed(float currentVelocity) { wheelClipLoop.speed = Mathf.Max(Mathf.Abs(currentVelocity / 360), 0.1f); } private async Task LightStarAni() { var time = lightAni["light_spin_start"].length; lightAni.Play("light_spin_start"); await Awaiters.Seconds(time); lightAni.Play("light_spin_loop"); } private async Task LightEndAni() { var remainingTime = wheelClipLoop.length * (1f - wheelClipLoop.normalizedTime); await Awaiters.Seconds(remainingTime); var clipEndTime = lightAni["light_spin_end"].length; lightAni.Play("light_spin_end"); await Awaiters.Seconds(clipEndTime); var clipRewardTime = lightAni["light_reward"].length; lightAni.Play("light_reward"); } #endregion private #region Pointer Animation private void InitPointerAni() { var currentValue = rewardContainer.eulerAngles.z; lastValue = currentValue; lastSegment = GetSegment(currentValue); } private void PointerAni(float currentValue, float currentVelocity) { currentSegment = GetSegment(currentValue); lastSegment = GetSegment(lastValue); var normalizeCurrentAngle = NormalizeAngle(currentValue); if (currentSegment != lastSegment) { var direction = GetCrossDirection(lastSegment, currentSegment); var time = wheelAngle / currentVelocity; var pointerTargetAngle = Mathf.Abs(Mathf.Clamp01(normalizeCurrentAngle / wheelAngle) * pointerAngle); zhizhenTrans.DORotate(new Vector3(0, 0, direction * pointerTargetAngle), time) .OnComplete(() => { _tweener?.Kill(); _tweener = zhizhenTrans.DORotate(Vector3.zero, revertAngleTime); }); } lastValue = currentValue; } private int GetSegment(float angle) { var normalizedAngle = NormalizeAngle(angle); return Mathf.FloorToInt(normalizedAngle / SegmentAngle); } private float NormalizeAngle(float angle) { angle %= FULL_CIRCLE; if (angle < 0) angle += FULL_CIRCLE; return angle; } private int GetCrossDirection(int fromSegment, int toSegment) { var diff = toSegment - fromSegment; if ((fromSegment == MaxSegment && toSegment == 0) || (fromSegment == 0 && toSegment == MaxSegment)) diff = -diff; return diff < 0 ? 1 : -1; } #endregion Pointer Animation } }