using cfg.BI; using System; using PhxhSDK; using cfg.Prop; using UnityEngine; using System.Linq; using Framework.BI; using Framework.UI; using Gameplay.Level; using Framework.Event; using Framework.Manager; using Framework.Constants; using Event = cfg.BI.Event; using Cysharp.Threading.Tasks; using Gameplay.Level.Operation; using System.Collections.Generic; using Constants = Framework.Constants.Constants; namespace Gameplay.Manager { public class LevelManager : Singlenton, IUpdatable { private GameObject _destroyPlankRoot; private UndoOperation _undoOperation; private List _destroyPlanks; public UndoState CurUndoState; public float RemainingTime; public bool IsPause; public bool IsOver; public bool IsTimeEnd; public int Step; public float ElapsedTime; public Level.Level CurrentLevel { get; private set; } public int LastPassLevel = 0; public bool IsNewbieGuide; public bool IsFail2AddTime; public bool IsWatchAD; private int _levelLoseTime; private string _lastLevelID = ""; public string ADGetPropTips = ""; private GameObject _gfxUndo; private ParticleSystem _particleUndo; private GameObject _gfxOpenHole; private ParticleSystem _particleOpen; private GameObject _gfxWin; private ParticleSystem _particleWin; private GameObject _gfxBgSunny; //飞金币 public GameObject CoinObj; public Vector3 CoinTargetPos; public List GfxCoins; public bool CanGfxCoin; public class Coin { public GameObject CoinObj; private float _moveTime; private const float MoveSpawnInterval = 0.5f; private const float MoveSpeed = 300f; public Coin(GameObject obj) { CoinObj = obj; } public void Update(float deltaTime) { _moveTime += deltaTime; if (CoinObj && _moveTime > MoveSpawnInterval) { CoinObj.transform.position = Vector3.MoveTowards(CoinObj.transform.position, Instance.CoinTargetPos, MoveSpeed * Time.deltaTime); } if (CoinObj && CoinObj.transform.position.Equals(Instance.CoinTargetPos)) { CoinObj.SetActive(false); CoinObj.Destroy(); _moveTime = 0.0f; } } public void Release() { if (CoinObj) CoinObj.Destroy(); } } public async UniTask Init() { await InitUI(); RegisterEvent(); ReLoadLevelValue(); CurUndoState = new UndoState(); _undoOperation = new UndoOperation(); _destroyPlanks = new List(); GfxCoins = new List(); await InitGfx(); CoinObj = await AssetManager.Instance.LoadAssetAsync(string.Format(Constants.ItemPrefabPath, "GfxCoin")); } private async UniTask InitUI() { UIManager.Instance.CloseWindow(UIConstants.ImgLoading); await UIManager.Instance.OpenBgWindow(UIConstants.UILevelBg); } private async UniTask InitGfx() { _gfxUndo = await GfxManager.Instance.PreLoadGfx("gfx_undo"); _particleUndo = _gfxUndo.GetComponent(); _gfxOpenHole = await GfxManager.Instance.PreLoadGfx("gfx_openhole"); _particleOpen = _gfxOpenHole.GetComponent(); _gfxWin = await GfxManager.Instance.PreLoadGfx("gfx_win_firework"); _particleWin = _gfxWin.GetComponent(); await GfxManager.Instance.PreLoadGfx("gfx_bg_sunny"); _gfxBgSunny = await GfxManager.Instance.LoadGfx("gfx_bg_sunny"); } public void ReLoadLevelValue() { Step = 0; ElapsedTime = 0f; RemainingTime = LevelConstants.RemainingTime; } #region Game Start Part public async UniTask LoadLevel(string id) { if (IsLevelExist(id)) { CurrentLevel = new Level.Level(id); await CurrentLevel.Load(id); await UniTask.NextFrame(); } else { await CurrentLevel.Load(CurrentLevel.ID); await UniTask.NextFrame(); } if (!_lastLevelID.Equals(CurrentLevel.ID)) { DebugUtil.LogWarning("开启新关卡:{0}", CurrentLevel.ID); _lastLevelID = CurrentLevel.ID; _levelLoseTime = 0; } if (RandomProp != PropType.None) { switch (RandomProp) { case PropType.Undo: CurrentLevel.LevelData.undoCount++; break; case PropType.OpenHole: CurrentLevel.LevelData.openHoleCount++; break; } RandomProp = PropType.None; } } public bool IsLevelExist(string id) { var levels = LevelSelectManager.Instance.CurAllLevelDatas.Select(data => data.LevelID).ToList(); return levels.Contains(id); } public void ReportEnterLevel() { BIManager.Instance.TrackStringEventOnce(string.Format(LevelConstants.FteLevelEnter, CurrentLevel.GetLevelIndex())); } #endregion #region Game In Process Part private void HideGfx() { GfxManager.Instance.ReturnGfxObj("gfx_undo"); GfxManager.Instance.ReturnGfxObj("gfx_openhole"); GfxManager.Instance.ReturnGfxObj("gfx_bg_sunny"); GfxManager.Instance.ReturnGfxObj("gfx_win_firework"); } private void ShowGfx() { _gfxBgSunny.SetActive(true); } public void PushUndoState() { if (CurUndoState.LastModifiedKong == null || CurUndoState.PreModifiedKong == null) return; if (CurUndoState != null) { _undoOperation.UndoStack.Push(CurUndoState); CurUndoState = new UndoState(); } } public void Update(float deltaTime) { if (CurrentLevel != null) { CurrentLevel.Update(deltaTime); } if (_isGetPropSuccess) { _isGetPropSuccess = false; EventManager.Instance.Send(EventManager.EventName.WatchADSuccessToGetProp); } if (_isGetTimeSuccess) { _isGetTimeSuccess = false; EventManager.Instance.Send(EventManager.EventName.WatchADSuccessToGetTime); } if (_isGetRandomPropSuccess) { _isGetRandomPropSuccess = false; EventManager.Instance.Send(EventManager.EventName.WatchADSuccessToGetRandomProp); } if (GfxCoins != null) { foreach (var coin in GfxCoins) { coin.Update(deltaTime); } } /* if (GfxCoins != null && !GfxCoins[^1].Show) { EventManager.Instance.Send(EventManager.EventName.WinGfxFinish); } */ Time.timeScale = IsOver || IsPause ? 0f : 1f; } #endregion #region Game End Part public void CachePlank(string cachePlank) { PlankManager.Instance.GetPlank(cachePlank).Obj.SetActive(false); if (!_destroyPlanks.Contains(cachePlank)) { _destroyPlanks.Add(cachePlank); if (_destroyPlanks.Count.Equals(PlankManager.Instance.Planks.Count)) { foreach (var plank in PlankManager.Instance.Planks.Keys) { if (!_destroyPlanks.Contains(plank)) return; } EventManager.Instance.Send(EventManager.EventName.LevelGameWin); } } } private void WinGfxFinish() { } private void WinGame() { /*if (IsOver) return; IsOver = true;*/ GfxManager.Instance.ReturnGfxObj("gfx_bg_sunny", true); CommonUIUtils.DestroyScreenshot(); CommonUIUtils.CaptureScreenshot(); AudioManager.Instance.PlaySound(AudioType.SOUND, "S_Win", new UnityAudio(false)); GfxManager.Instance.ShowGfxOnce(_particleWin, _gfxWin); IsTimeEnd = true; if (IsNewbieGuide) { IsNewbieGuide = false; EventManager.Instance.Send(EventManager.EventName.NewBieGuideFinish); } ReportPassLevel(); var oldCoin = ShopManager.Instance.CurCoin; LevelSelectManager.Instance.SaveNewPassLevel(CurrentLevel.ID); BIManager.Instance.TrackEventLevel(Event.level_success); UIManager.Instance.OpenWindow(UIConstants.UIWinPanel, oldCoin); } private void LoseGame() { if (IsOver) return; IsOver = true; GfxManager.Instance.ReturnGfxObj("gfx_bg_sunny", true); CommonUIUtils.DestroyScreenshot(); CommonUIUtils.CaptureScreenshot(); BIManager.Instance.TrackEventLevel(Event.level_fail); _levelLoseTime++; DebugUtil.LogWarning("输掉关卡:{0},已经{1}次了", _lastLevelID, _levelLoseTime); if (_levelLoseTime >= 2 && ADManager.Instance.CanShow(103)) { AudioManager.Instance.PlaySound(AudioType.SOUND, "S_Reward", new UnityAudio(false)); UIManager.Instance.OpenWindow(UIConstants.UIADPOPUP); } else { AudioManager.Instance.PlaySound(AudioType.SOUND, "S_Lose", new UnityAudio(false)); UIManager.Instance.OpenWindow(UIConstants.UILosePanel); } } private void ReportPassLevel() { BIManager.Instance.TrackStringEventOnce(string.Format(LevelConstants.FteLevelSuccess, CurrentLevel.GetLevelIndex())); } #endregion #region Prop Function Part public bool PlayAnimation; public bool CanUndo() { return !IsNewbieGuide && _undoOperation.UndoStack.Count > 0; } public void SureUndo() { if (IsNewbieGuide) return; if (!CanUndo()) { IsPause = true; CommonUIUtils.DestroyScreenshot(); CommonUIUtils.CaptureScreenshot(); UIManager.Instance.OpenWindow(UIConstants.UITips, "Tip_Undo", () => { IsPause = false; }); } else { if (CurrentLevel.LevelData.undoCount > 0) { Undo(); } else { CommonUIUtils.DestroyScreenshot(); CommonUIUtils.CaptureScreenshot(); UIManager.Instance.OpenWindow(UIConstants.UIBuyGoods, PropType.Undo, Undo); } } } private void Undo() { if (_undoOperation.UndoStack.Count <= 0) return; try { BIManager.Instance.TrackEventLevel(Event.level_step_back, BIManager.Reason.ByUsingItem.ToString()); Step -= 1; CurrentLevel.LevelData.undoCount--; ShopManager.Instance.UseProp(PropType.Undo); EventManager.Instance.Send(EventManager.EventName.RefreshProp); var undoState = _undoOperation.UndoStack.Pop(); //改变表现 GfxManager.Instance.ShowGfxOnce(_particleUndo, _gfxUndo); AudioManager.Instance.PlaySound(AudioType.SOUND, "S_Undo", new UnityAudio(false)); var undoThumbtack = undoState.LastModifiedKong.LevelThumbtack; undoThumbtack.Obj.transform.position = undoState.PreModifiedKong.Obj.transform.position; foreach (var undo in undoState.AffectPlanks) { undo.Key.Obj.SetActive(true); undo.Key.StopDetect = false; } undoState.PreModifiedKong.LevelThumbtack = undoThumbtack; foreach (var plank in undoState.ReplacePlanks) { PlankManager.Instance.ReplaceAnchor(plank, undoState.LastModifiedKong.LevelThumbtack); } foreach (var undo in undoState.AffectPlanks) { undo.Key.Obj.transform.rotation = undo.Value.Value; undo.Key.Obj.transform.position = undo.Value.Key; if (undoState.RemoveH2DjPlanks.Contains(undo.Key)) PlankManager.Instance.AddHingJoint2D(undo.Key, undoState.PreModifiedKong.LevelThumbtack); } foreach (var plank in undoState.AddH2DjPlanks) { PlankManager.Instance.RemoveHingJoint2D(plank, undoState.LastModifiedKong.LevelThumbtack); } undoState.LastModifiedKong.LevelThumbtack = null; undoState.LastModifiedKong = null; undoState.PreModifiedKong = null; } catch (Exception e) { DebugUtil.LogError("LevelManager.Undo Fail. Error: {0}", e); } } public void SureAddTime() { if (IsNewbieGuide) return; if (CurrentLevel.LevelData.addTimeCount > 0) { AddTime(); } else { CommonUIUtils.DestroyScreenshot(); CommonUIUtils.CaptureScreenshot(); UIManager.Instance.OpenWindow(UIConstants.UIBuyGoods, PropType.AddTime, AddTime); } } private void AddTime() { BIManager.Instance.TrackEventLevel(Event.level_add_time, BIManager.Reason.ByUsingItem.ToString()); EventManager.Instance.Send(EventManager.EventName.AddTime); RemainingTime += LevelConstants.AddPropTime; CurrentLevel.LevelData.addTimeCount--; ShopManager.Instance.UseProp(PropType.AddTime); EventManager.Instance.Send(EventManager.EventName.RefreshProp); PlayAnimation = true; AudioManager.Instance.PlaySound(AudioType.SOUND, "S_AddTime", new UnityAudio(false)); } public bool CanOpenHole() { return !IsNewbieGuide && !KongManager.Instance.CanAddNewHole().Equals(Vector3.zero); } public void SureOpenHole() { if (IsNewbieGuide) return; if (!CanOpenHole()) { IsPause = true; CommonUIUtils.DestroyScreenshot(); CommonUIUtils.CaptureScreenshot(); UIManager.Instance.OpenWindow(UIConstants.UITips, "Tip_OpenHole", () => { IsPause = false; }); } else { if (CurrentLevel.LevelData.openHoleCount > 0) { OpenHoleAfterGfx(); } else { CommonUIUtils.DestroyScreenshot(); CommonUIUtils.CaptureScreenshot(); UIManager.Instance.OpenWindow(UIConstants.UIBuyGoods, PropType.OpenHole, OpenHoleAfterGfx); } } } private void OpenHoleAfterGfx() { var pos = KongManager.Instance.CanAddNewHole(); if (!pos.Equals(Vector3.zero)) { CurrentLevel.LevelData.openHoleCount--; ShopManager.Instance.UseProp(PropType.OpenHole); EventManager.Instance.Send(EventManager.EventName.RefreshProp); _gfxOpenHole.transform.position = pos; AudioManager.Instance.PlaySound(AudioType.SOUND, "S_OpenHole", new UnityAudio(false)); GfxManager.Instance.ShowGfxOnce(_particleOpen, _gfxOpenHole, OpenHole); } } private void OpenHole() { KongManager.Instance.AddNewHole(); BIManager.Instance.TrackEventLevel(Event.level_add_hole, BIManager.Reason.ByUsingItem.ToString()); } public void SureResetLevel() { if (IsNewbieGuide) return; IsPause = true; CommonUIUtils.DestroyScreenshot(); CommonUIUtils.CaptureScreenshot(); UIManager.Instance.OpenWindow(UIConstants.UITips, "Tip_Reset_Confirm", ResetLevel, () => { IsPause = false; }); return; if (CurrentLevel.LevelData.resetCount > 0) { GameStateManager.Instance.ChangeState(new LevelState(CurrentLevel.ID)); CurrentLevel.LevelData.resetCount--; BIManager.Instance.TrackEventLevel(Event.level_retry, BIManager.Reason.ClickOnLevelScene.ToString()); EventManager.Instance.Send(EventManager.EventName.RefreshProp); } } public void ResetLevel() { BIManager.Instance.TrackEventLevel(Event.level_retry, BIManager.Reason.ClickOnLevelScene.ToString()); GameStateManager.Instance.ChangeState(new LevelState(CurrentLevel.ID)); } #endregion #region AD Part private Action _adGetPropSuccess; private Action _adGetTimeSuccess; private Action _adGetRandomPropSuccess; private bool _isGetPropSuccess; private bool _isGetTimeSuccess; private bool _isGetRandomPropSuccess; private PropType _adProp; public PropType RandomProp = PropType.None; //失败获取随即道具 public void WatchADGetRandomProp(Action getSuccess, Action getFail) { _adGetRandomPropSuccess = getSuccess; BIManager.Instance.TrackEventLevel(Event.level_click_ad, "103"); BIManager.Instance.TrackEventLevelOnce(EventFirst.fte_level_click_ad, "103"); ADManager.Instance.ShowAdWithPreLoad(103, () => { _isGetRandomPropSuccess = true; }, getFail); } private void ADGetRandomProp() { while (RandomProp != PropType.Undo && RandomProp != PropType.OpenHole) { RandomProp = Utils.GetRandomEnum(); } BIManager.Instance.TrackEventLevel(Event.level_ad_show_success, "103", RandomProp.ToString()); BIManager.Instance.TrackEventLevelOnce(EventFirst.fte_level_ad_show_success, "103", RandomProp.ToString()); DebugUtil.LogWarning("获取到的道具是:{0}", RandomProp); _levelLoseTime = 0; _adGetRandomPropSuccess?.Invoke(); } //失败看广告获取时间 public void WatchADGetTime(Action getSuccess, Action getFail = null) { _adGetTimeSuccess = getSuccess; BIManager.Instance.TrackEventLevel(Event.level_click_ad, "102"); BIManager.Instance.TrackEventLevelOnce(EventFirst.fte_level_click_ad, "102"); ADManager.Instance.ShowAdWithPreLoad(102, () => { _isGetTimeSuccess = true; }, getFail); } private void ADGetTime() { BIManager.Instance.TrackEventLevel(cfg.BI.Event.level_add_time, BIManager.Reason.ClickOnLosePanel.ToString()); RemainingTime = 15f; IsOver = false; IsFail2AddTime = true; BIManager.Instance.TrackEventLevel(Event.level_ad_show_success, "102", "AddTime"); BIManager.Instance.TrackEventLevelOnce(EventFirst.fte_level_ad_show_success, "102", "AddTime"); AudioManager.Instance.PlaySound(AudioType.SOUND, "S_AddTime", new UnityAudio(false)); PlayAnimation = true; _adGetTimeSuccess?.Invoke(); } //关卡内看广告获取指定道具 public void WatchADGetProp(PropType prop, Action rewardSuccess, Action rewardFail = null) { _adProp = prop; _adGetPropSuccess = rewardSuccess; BIManager.Instance.TrackEventLevel(Event.level_click_ad, "101"); BIManager.Instance.TrackEventLevelOnce(EventFirst.fte_level_click_ad, "101"); ADManager.Instance.ShowAdWithPreLoad(101, () => { _isGetPropSuccess = true; }, rewardFail); } private void ADGetProp() { _adGetPropSuccess?.Invoke(); UIManager.Instance.OpenWindow(UIConstants.UITips, ADGetPropTips, () => { switch (_adProp) { case PropType.Undo: { Undo(); break; } case PropType.OpenHole: { OpenHoleAfterGfx(); break; } case PropType.AddTime: { AddTime(); break; } } IsPause = false; BIManager.Instance.TrackEventLevel(Event.level_ad_show_success, "101", _adProp.ToString()); BIManager.Instance.TrackEventLevelOnce(EventFirst.fte_level_ad_show_success, "101", _adProp.ToString()); IsWatchAD = true; EventManager.Instance.Send(EventManager.EventName.RefreshProp); }); DebugUtil.LogWarning("Use Prop: {0}", _adProp); } #endregion public void Release() { IsPause = false; IsOver = false; IsTimeEnd = false; IsFail2AddTime = false; IsWatchAD = false; foreach (var gfxCoin in GfxCoins) { gfxCoin.Release(); } CanGfxCoin = false; GfxCoins = null; ReleaseGfx(); UnRegisterEvent(); //ShopManager.Instance.SettleCoins(); KongManager.Instance.Release(); PlankManager.Instance.Release(); CommonUIUtils.DestroyScreenshot(); } private void ReleaseGfx() { GfxManager.Instance.ReturnGfxObj("gfx_undo", true); GfxManager.Instance.ReturnGfxObj("gfx_openhole", true); GfxManager.Instance.ReturnGfxObj("gfx_bg_sunny", true); GfxManager.Instance.ReturnGfxObj("gfx_win_firework", true); _gfxUndo = null; _particleUndo = null; _gfxOpenHole = null; _particleOpen = null; _gfxWin = null; _particleWin = null; _gfxBgSunny = null; } private void RegisterEvent() { EventManager.Instance.Register(EventManager.EventName.LevelGameWin, WinGame); EventManager.Instance.Register(EventManager.EventName.LevelGameLose, LoseGame); EventManager.Instance.Register(EventManager.EventName.WatchADSuccessToGetProp, ADGetProp); EventManager.Instance.Register(EventManager.EventName.WatchADSuccessToGetTime, ADGetTime); EventManager.Instance.Register(EventManager.EventName.WatchADSuccessToGetRandomProp, ADGetRandomProp); EventManager.Instance.Register(EventManager.EventName.HideGfx, HideGfx); EventManager.Instance.Register(EventManager.EventName.ShowGfx, ShowGfx); } private void UnRegisterEvent() { EventManager.Instance.Unregister(EventManager.EventName.LevelGameWin, WinGame); EventManager.Instance.Unregister(EventManager.EventName.LevelGameLose, LoseGame); EventManager.Instance.Unregister(EventManager.EventName.WatchADSuccessToGetProp, ADGetProp); EventManager.Instance.Unregister(EventManager.EventName.WatchADSuccessToGetTime, ADGetTime); EventManager.Instance.Unregister(EventManager.EventName.WatchADSuccessToGetRandomProp, ADGetRandomProp); EventManager.Instance.Unregister(EventManager.EventName.HideGfx, HideGfx); EventManager.Instance.Unregister(EventManager.EventName.ShowGfx, ShowGfx); } //Debug public void AddUndoProp() { CurrentLevel.LevelData.undoCount = 999; EventManager.Instance.Send(EventManager.EventName.RefreshProp); } } }