Files
2026-05-26 16:15:54 +08:00

330 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using asap.core;
using GameCore;
using UniRx;
using UnityEngine;
using UnityEngine.Assertions;
public class ShootingRangeAct : AGameAct
{
private EventShootingRangeData _data;
public const int AmmoCost = 1;
private WinterShootingRangePanel _mainPanel;
private int _clickableCounter;
[SerializeField] private List<ShootingRound> stageList;
public static IEventAggregator EventAggregator = new EventAggregator();
private readonly CompositeDisposable _disposables = new CompositeDisposable();
/// <summary>
/// This method is used in a weird way that Assertion Error can not be caught.
/// </summary>
/// <returns></returns>
public override async System.Threading.Tasks.Task<bool> StartAsync()
{
// await Awaiters.NextFrame;
_clickableCounter = 0;
BlockClick();
_data = GContext.container.Resolve<EventShootingRangeData>();
_data.HasBeenOpened = true;
_mainPanel = (await UIManager.Instance.ShowUILoad(UITypes.EventWinterShootingPanel)).GetComponent<WinterShootingRangePanel>();
// _mainPanel.Init();
GContext.container.Resolve<IDeferredRewardStashService>().Reset();
EventAggregator.GetEvent<EventPanelClose>().Subscribe(_ => UnblockClick()).AddTo(_disposables);
EventAggregator.GetEvent<EventPanelOpen>().Subscribe(_ => BlockClick()).AddTo(_disposables);
EventAggregator.GetEvent<EventRewardPanelClose>().Subscribe(OnRewardPanelClose).AddTo(_disposables);
GContext.OnEvent<DeferredRewardStashPanel.EventStashPanelClose>().Subscribe(_ => UnblockClick()).AddTo(_disposables);
GContext.OnEvent<DeferredRewardStashPanel.EventStashPanelOpen>().Subscribe(_ => BlockClick()).AddTo(_disposables);
ClearStages();
GContext.Publish(new EndTransition());
// await LoadStageAsync();
LoadStage();
UnblockClick();
GContext.OnEvent<EventShootingRangeDebug>().Subscribe(DebugShootingRange).AddTo(this);
return await base.StartAsync();
}
private void Update()
{
if (_clickableCounter == 0 && Input.GetMouseButtonDown(0))
{
if (_data.RemainingTime.TotalSeconds <= -5)
_mainPanel.OnClickClose();
BlockClick();
var target = SelectTarget()?.GetComponent<ShootingTarget>();
if (!target || _data.IsTargetHit(target.targetIdx))
{
UnblockClick();
return;
}
ShootWithoutDisplay(target.targetIdx, out var rewardIndex, out var rewards);
if (rewardIndex == -1)
{
UnblockClick();
return;
}
int eventTrackingHook = rewards.Where(reward => reward.id == 1001).Sum(reward => (int)reward.count);
/*
Debug.Log($"<color=#fe231b>Event tracking:</color>");
Debug.Log($"<color=#fe231b> round: {_data.RoundCount + 1}</color>");
Debug.Log($"<color=#fe231b> stage: {_data.CurrentStageIdx + 1}</color>");
Debug.Log($"<color=#fe231b> target: {_data.GetHitTargetCount()}</color>");
Debug.Log($"<color=#fe231b> is_over: {(rewardIndex == 0 ? 1 : 0)}</color>");
Debug.Log($"<color=#fe231b> drop_list: {_data.CurrentStage.DropId[rewardIndex]}</color>");
Debug.Log($"<color=#fe231b> reward_hook: {eventTrackingHook}</color>");
Debug.Log($"<color=#fe231b> combine_id: {(_data.RoundCount + 1) * 10000 + (_data.CurrentStageIdx + 1) * 100 + _data.GetHitTargetCount()}</color>");
*/
#if AGG
using (var e = GEvent.GameEvent("event_shooting"))
{
e.AddContent("round", _data.RoundCount + 1)
.AddContent("stage", _data.CurrentStageIdx + 1)
.AddContent("target", _data.GetHitTargetCount())
.AddContent("is_over", rewardIndex == 0 ? 1 : 0)
.AddContent("drop_list", _data.CurrentStage.DropId[rewardIndex])
.AddContent("reward_hook", eventTrackingHook)
.AddContent("combine_id",
(_data.RoundCount + 1) * 10000 + (_data.CurrentStageIdx + 1) * 100 + _data.GetHitTargetCount());
}
#endif
#if UNITY_EDITOR
if (Input.GetKeyDown(KeyCode.R))
{
_data.ResetData();
}
#endif
bool isFinal = _data.IsFinalStage;
if (rewardIndex == 0)
_data.SwitchToNextStage();
_data.UploadData();
Display(target, rewardIndex == 0, isFinal, rewards);
}
}
/*public static void SubscribeEvent<T>(T e, Action<T> a)
{
EventAggregator.GetEvent<T>().Subscribe(a).AddTo(Disposables);
}*/
private void ClearStages()
{
Assert.IsTrue(_data.CurrentStageIdx >= 0 && _data.CurrentStageIdx < stageList.Count,
$"Stage index {_data.CurrentStageIdx} is out of range {stageList.Count}");
Debug.Log("Load Stage start.");
foreach (var stage in stageList)
{
stage.Hide();
}
}
private async System.Threading.Tasks.Task LoadStageAsync()
{
await stageList[_data.CurrentStageIdx].ShowAsync();
}
private void LoadStage()
{
stageList[_data.CurrentStageIdx].Show();
}
private GameObject SelectTarget()
{
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out var hit) && hit.collider.CompareTag("ShootingTarget"))
return hit.collider.gameObject;
return null;
}
private void ShootWithoutDisplay(int targetIdx, out int rewardIdx, out List<ItemData> rewards)
{
rewardIdx = -1;
rewards = null;
/*if (_data.IsGameDepleted)
{
Debug.Log("Game depleted.");
return;
}*/
if (_data.AmmoCount < AmmoCost)
{
Debug.Log("Not enough ammo.");
// _mainPanel.ShowAmmoTip();
_mainPanel.OnClickSupply();
return;
}
_data.AddAmmo(-AmmoCost);
var processedWeightList = _data.CurrentStage.Weight.Select((w, i) => _data.IsRewardCollected(i) ? 0 : w).ToList();
processedWeightList[0] = _data.IsGrandPrizeAllowed ? processedWeightList[0] : 0;
rewardIdx = _data.PickRandomIndex(processedWeightList);
// Debug.Log($"Got reward No.{rewardIdx}, dropId {_data.CurrentStage.DropId[rewardIdx]}.");
rewards = GContext.container.Resolve<PlayerItemData>()
.GetItemDataByDropId(_data.CurrentStage.DropId[rewardIdx]);
foreach (var reward in rewards)
{
if (reward.id != _data.CycleItem.ItemId)
GContext.Publish(new DeferredRewardStashService.EventStashItem { Item = reward });
else
GContext.container.Resolve<PlayerItemData>().AddItem(reward);
}
_data.SetRewardCollected(rewardIdx);
_data.SetTargetHit(targetIdx);
}
[Tooltip("开镜动画出现延迟")][SerializeField] private float jiandaAimDelay;
[Tooltip("靶子碎裂延迟")][SerializeField] private float jiandaTargetBreakDelay;
[Tooltip("过关面板出现延迟")][SerializeField] private float jiandaRewardPanelPopupDelay;
[Tooltip("切换关卡延迟")][SerializeField] private float jiandaSwitchStageDelay;
[Tooltip("奖励出现并飞入延迟")]
[SerializeField]
private float jiandaRewardFlyDelay;
[Tooltip("雪人出现延迟")][SerializeField] private float jiandaSnowManPopupDelay;
[Tooltip("允许面板操作的延迟,从点击开始")]
[SerializeField]
private float jiandaUnblockDelay = 2.1f;
[Tooltip("奖励出现时,相对于靶子的,奖励位置偏移")]
[SerializeField]
private Vector2 jiandaRewardPositionOffset = new Vector2(0, 0);
private void Display(ShootingTarget target, bool needSwitchStage, bool isFinalStage,
List<ItemData> rewards)
{
if (needSwitchStage && rewards is null)
{
Debug.LogWarning($"Empty grand prize.");
return;
}
_mainPanel.UpdateAmmoCount(AmmoCost);
// var localHitPosition = _mainPanel.GetUiHitPosition(target.gameObject);
var localHitPosition = UIManager.Instance.WorldToScreen(target.transform.position);
_ = _mainPanel.ShowCrosshairAfterDelay(localHitPosition, jiandaAimDelay);
_ = target.PlayBreakAnimationWithDelay(jiandaTargetBreakDelay);
if (needSwitchStage)
{
_ = _mainPanel.ShowSnowmanAfterDelay(localHitPosition + jiandaRewardPositionOffset, jiandaSnowManPopupDelay);
_ = ShowRewardPopupWithDelay(rewards, isFinalStage, jiandaRewardPanelPopupDelay);
// Will unblock when panel is closed!
// Will receive event when panel is closed.
}
else
{
_ = System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(jiandaUnblockDelay))
.ContinueWith(_ => UnblockClick());
_ = _mainPanel.PlayRewardFlyWithDelay(rewards[0], localHitPosition + jiandaRewardPositionOffset, jiandaRewardFlyDelay);
// UnblockClick();
}
}
private async System.Threading.Tasks.Task ShowRewardPopupWithDelay(List<ItemData> rewards, bool doesShowFinal,
float delay)
{
await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(delay));
var finalRewardPopup = (await UIManager.Instance.ShowUI(UITypes.ShootingRangeFinalRewardPopup))
.GetComponent<ShootingRangeFinalRewardPopupPanel>();
finalRewardPopup.Init(rewards, doesShowFinal);
}
private void OnRewardPanelClose(EventRewardPanelClose e)
{
BlockClick();
if (e.IsFinalStage)
{
_mainPanel.OnClickClose();
}
else
{
_ = _mainPanel.MoveSnowmanAfterDelayAndUpdateTarget(0f);
for (int i = 0; i < e.Rewards.Length; i++)
{
_ = _mainPanel.PlayRewardFlyWithDelay(e.Rewards[i], e.RewardPositionList[i], 0f);
}
_ = SwitchStageWithDelay(jiandaSwitchStageDelay);
}
}
private async System.Threading.Tasks.Task SwitchStageWithDelay(float delay)
{
await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(delay));
ClearStages();
var panel = await UIManager.Instance.ShowUI(UITypes.ShootingRangeTransitionPanel);
await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(0.8f));
_mainPanel.UpdateAmmoCount();
_mainPanel.SetRewards();
panel.GetComponent<CloudTransitionPanel>().EndTransition(new EndTransition());
// await LoadStageAsync();
LoadStage();
UnblockClick();
}
private void LogRewardState()
{
Debug.Log("Checking reward status.");
for (int i = 0; i < _data.CurrentStage.DropId.Count; i++)
{
Debug.Log($" Reward {i}: {_data.IsRewardCollected(i)}");
}
// Debug.Log();
}
private void BlockClick()
{
_clickableCounter++;
// Debug.Log($"<color=#a6a6a6>Block to: {_clickableCounter}.</color>");
}
private void UnblockClick()
{
_clickableCounter--;
// Debug.Log($"<color=#a6a6a6>Unblock to: {_clickableCounter}.</color>");
}
protected override void OnDestroy()
{
RedPointManager.Instance.SetRedPointState(EventShootingRangeData.EntranceRedPointId,
_data.DoNeedEntranceRedPoint);
_disposables?.Dispose();
Debug.Log("Exit ShootingRangeAct.");
// GContext.container.Resolve<IDeferredRewardStashService>().Flush();
}
public class EventPanelClose
{
}
public class EventPanelOpen
{
}
public class EventRewardPanelClose
{
public bool IsFinalStage;
public ItemData[] Rewards;
public Vector2[] RewardPositionList;
}
public class EventAmmoBought
{
}
private void DebugShootingRange(EventShootingRangeDebug e)
{
_data.SwitchToStage(e.StageIdx);
ClearStages();
_ = LoadStageAsync();
}
}
public class EventShootingRangeDebug
{
public int StageIdx;
}