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 stageList; public static IEventAggregator EventAggregator = new EventAggregator(); private readonly CompositeDisposable _disposables = new CompositeDisposable(); /// /// This method is used in a weird way that Assertion Error can not be caught. /// /// public override async System.Threading.Tasks.Task StartAsync() { // await Awaiters.NextFrame; _clickableCounter = 0; BlockClick(); _data = GContext.container.Resolve(); _data.HasBeenOpened = true; _mainPanel = (await UIManager.Instance.ShowUILoad(UITypes.EventWinterShootingPanel)).GetComponent(); // _mainPanel.Init(); GContext.container.Resolve().Reset(); EventAggregator.GetEvent().Subscribe(_ => UnblockClick()).AddTo(_disposables); EventAggregator.GetEvent().Subscribe(_ => BlockClick()).AddTo(_disposables); EventAggregator.GetEvent().Subscribe(OnRewardPanelClose).AddTo(_disposables); GContext.OnEvent().Subscribe(_ => UnblockClick()).AddTo(_disposables); GContext.OnEvent().Subscribe(_ => BlockClick()).AddTo(_disposables); ClearStages(); GContext.Publish(new EndTransition()); // await LoadStageAsync(); LoadStage(); UnblockClick(); GContext.OnEvent().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(); 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($"Event tracking:"); Debug.Log($" round: {_data.RoundCount + 1}"); Debug.Log($" stage: {_data.CurrentStageIdx + 1}"); Debug.Log($" target: {_data.GetHitTargetCount()}"); Debug.Log($" is_over: {(rewardIndex == 0 ? 1 : 0)}"); Debug.Log($" drop_list: {_data.CurrentStage.DropId[rewardIndex]}"); Debug.Log($" reward_hook: {eventTrackingHook}"); Debug.Log($" combine_id: {(_data.RoundCount + 1) * 10000 + (_data.CurrentStageIdx + 1) * 100 + _data.GetHitTargetCount()}"); */ #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 e, Action a) { EventAggregator.GetEvent().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 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() .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().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 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 rewards, bool doesShowFinal, float delay) { await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(delay)); var finalRewardPopup = (await UIManager.Instance.ShowUI(UITypes.ShootingRangeFinalRewardPopup)) .GetComponent(); 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().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($"Block to: {_clickableCounter}."); } private void UnblockClick() { _clickableCounter--; // Debug.Log($"Unblock to: {_clickableCounter}."); } protected override void OnDestroy() { RedPointManager.Instance.SetRedPointState(EventShootingRangeData.EntranceRedPointId, _data.DoNeedEntranceRedPoint); _disposables?.Dispose(); Debug.Log("Exit ShootingRangeAct."); // GContext.container.Resolve().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; }