using Core.Health; using Core.Input; using Core.Utilities; using JetBrains.Annotations; using System; using System.Collections.Generic; using TMPro; using TowerDefense.Level; using TowerDefense.Towers; using TowerDefense.Towers.Placement; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; using TowerDefense.Nodes; using KTGMGemClient; namespace TowerDefense.UI.HUD { /// /// An object that manages user interaction with the game. Its responsibilities deal with /// /// /// Building towers /// /// /// Selecting towers and units /// /// /// [RequireComponent(typeof(Camera))] public class EndlessGameUI : Singleton { /// /// The states the UI can be in /// public enum State { /// /// The game is in its normal state. Here the player can pan the camera, select units and towers /// Normal, /// /// The game is in 'build mode'. Here the player can pan the camera, confirm or deny placement /// Building, /// /// The game is Paused. Here, the player can restart the level, or quit to the main menu /// Paused, /// /// The game is over and the level was failed/completed /// GameOver, /// /// The game is in 'build mode' and the player is dragging the ghost tower /// BuildingWithDrag } /// /// Gets the current UI state /// public State state { get; private set; } /// /// The currently selected tower /// public LayerMask placementAreaMask; /// /// 兵线层对应的Mask. /// public LayerMask waveLineMask; /// /// 战场区域Mask. /// public LayerMask battleAreaMask; /// /// The layer for tower selection /// public LayerMask towerSelectionLayer; /// /// The physics layer for moving the ghost around the world /// when the placement is not valid /// public LayerMask ghostWorldPlacementMask; public readonly int MAX_TOWERNUM = 20; /// /// The radius of the sphere cast /// for checking ghost placement /// public float sphereCastRadius = 1; /// /// 随机购买塔防的按钮. /// public Button randomTowerBtn; public Button SkillTowerBtn; /// /// 飘血数字对应的prefab. /// public TextMoveDoTween bloodText; /// /// 中毒飘字. /// public TextMoveDoTween bloodPoison; /// /// 暴击飘字. /// public TextMoveDoTween bloodCrit; /// /// 减速飘字 /// public Image SlowDownWord; /// /// 暴击飘字 /// public Image CritWord; /// /// 购买塔防按钮上的Text. /// protected TextMeshProUGUI towerPriceText; protected bool tdBuyDisable = false; /// /// 鼠标在移动一个Tower之前,要隐藏的Tower数据和指针。 /// protected Tower towerToMove = null; /// /// Fires when the changes /// should only allow firing when TouchUI is used /// public event Action stateChanged; /// /// Fires off when the ghost was previously not valid but now is due to currency amount change /// public event Action ghostBecameValid; /// /// Fires when a tower is selected/deselected /// public event Action selectionChanged; /// /// 成长骰子对应的Timer. /// protected List listTowerTimer = new List(); protected Dictionary towerTimeDic = new Dictionary(); /// /// Placement area ghost tower is currently on /// IPlacementArea m_CurrentArea; /// /// Grid position ghost tower in on /// IntVector2 m_GridPosition; /// /// Our cached camera reference /// Camera m_Camera; /// /// Current tower placeholder. Will be null if not in the state. /// TowerPlacementGhost m_CurrentTower; public bool HasTower { get { return m_CurrentTower != null; } } // TowerList用于简单记录相关的数据 protected List m_listTower = new List(); /// /// Tracks if the ghost is in a valid location and the player can afford it /// bool m_GhostPlacementPossible; /// /// Gets the current selected tower /// public Tower currentSelectedTower { get; private set; } /// /// 拖动塔防时,原塔防的等级。 /// protected int dragTowerLevel = 0; /// /// 选中Tower时候的鼠标点击坐标与Tower中心所在的屏幕坐标之间的偏移值. /// protected Vector2 selTowerOffset = new Vector2(); // 测试屏幕显示相关的倒计时. protected bool bLoaded = false; private Timer overTimer; /// /// 总兵线数 /// public int TotalWaveLines { get; } = 5; public IntVector2 currentGrid { get { return m_GridPosition; } } /// /// Gets whether a tower has been selected /// public bool isTowerSelected { get { return currentSelectedTower != null; } } /// /// 攻击塔位占的行数 /// public int AttackRowNumbers { get; set; } = 2; /// /// 所有攻击塔位的摧毁信息,是否被摧毁,默认全部没有被摧毁 /// private bool[,] TowerDestroyArr; public event Action GameOverEvent; /// /// 塔升级特效预制体 /// public GameObject TowerUpgradeEffectPrefab; /// /// 宝石出现特效预制体 /// public GameObject TowerAppearEffectPrefab; public GameObject TowerUpgradeEffectPrefabGuide;//新手导航特效Layer是UI public GameObject TowerAppearEffectPrefabGuide;//新手导航特效Layer是UI //首次购买宝石特效 public GameObject fireAppearEffect1; public GameObject fireAppearEffect2; public GameObject waterAppearEffect1; public GameObject waterAppearEffect2; public GameObject woodAppearEffect1; public GameObject woodAppearEffect2; /// /// 保存所有生成或合成的塔的最小等级 /// /// public int MinLevel; public IPlacementArea selfTowerPlaceArea { get { if (m_CurrentArea == null) { GameObject placeObj = GameObject.FindGameObjectWithTag("PlaceTower"); if (placeObj != null) m_CurrentArea = placeObj.GetComponent(); } return m_CurrentArea; } } private void UpdateMinLevelArr() { int min = -1; for (int i = 0; i < m_listTower.Count; ++i) { if (min == -1 || m_listTower[i].currentLevel < min) min = m_listTower[i].currentLevel; } MinLevel = Mathf.Max(min, 0); } /// /// 增加一个防塔的数据结构,测试数据 /// /// public void addTower(Tower t) { m_listTower.Add(t); UpdateMinLevelArr(); // 当前所在的位置是否攻击位置,随手瞎写:2 或者 3也就是前两排是上阵的 if (t.gridPosition.y >= 2) t.bInAttackMode = true; // ATTENTION TO FIX: 先写死,有一个简单的逻辑再说: if (m_listTower.Count >= MAX_TOWERNUM) disableRandomTowerBtn(); } /// /// 根据塔位索引位置,查找位置上是否有对应的塔防数据。 /// /// /// /// public Tower FindTowerWithGridIdx(int x, int y) { foreach (Tower lt in m_listTower) { if ((lt.gridPosition.x == x) && (lt.gridPosition.y == y)) return lt; } return null; } public bool towerInList(Tower t) { return m_listTower.Contains(t); } /// /// 设置已经上阵的所有塔的攻击状态,是否可以攻击 /// /// public void SetAttackingTowerState(bool canAttack) { foreach (Tower tower in m_listTower) { tower.CanAttack = canAttack; } } public void delTower(Tower t) { // 删除Tower有可能对应的Timer. foreach (var tdata in towerTimeDic) { if (tdata.Value == t) { // 先删除对应的timer数据: foreach (var timer in listTowerTimer) { if (tdata.Key == timer.timerID) { listTowerTimer.Remove(timer); break; } } // 删除字典并退出: towerTimeDic.Remove(tdata.Key); break; } } int tcnt = m_listTower.Count; m_listTower.Remove(t); if (tcnt == MAX_TOWERNUM) enableRandomTowerBtn(); } /// /// 清空缓存数据 /// public void restartLevel() { m_listTower.Clear(); listTowerTimer.Clear(); towerTimeDic.Clear(); } /// /// 查找相同类型,相同段位的Tower /// /// public Tower findSameLvlTower(Tower t) { Tower rest = null; foreach (Tower lt in m_listTower) { if (lt == t) continue; if ((lt.currentLevel == t.currentLevel) && (lt.towerName == t.towerName)) { return lt; } } return rest; } /// /// Gets whether certain build operations are valid /// public bool isBuilding { get { return state == State.Building || state == State.BuildingWithDrag; } } /// /// Cancel placing the ghost /// public void CancelGhostPlacement() { if (m_CurrentTower) Destroy(m_CurrentTower.gameObject); m_CurrentTower = null; SetState(State.Normal); DeselectTower(); } /// /// Returns the GameUI to dragging mode with the curent tower /// /// /// /// Throws exception when not in build mode /// public void ChangeToDragMode() { if (!isBuilding) { throw new InvalidOperationException("Trying to return to Build With Dragging Mode when not in Build Mode"); } SetState(State.BuildingWithDrag); } /// /// Returns the GameUI to BuildMode with the current tower /// /// /// Throws exception when not in Drag mode /// public void ReturnToBuildMode() { if (!isBuilding) { throw new InvalidOperationException("Trying to return to Build Mode when not in Drag Mode"); } SetState(State.Building); } /// /// Changes the state and fires /// /// The state to change to /// thrown on an invalid state void SetState(State newState) { if (state == newState) { return; } State oldState = state; if (oldState == State.Paused || oldState == State.GameOver) { Time.timeScale = 1f; } switch (newState) { case State.Normal: break; case State.Building: break; case State.BuildingWithDrag: break; case State.Paused: case State.GameOver: if (oldState == State.Building) CancelGhostPlacement(); Time.timeScale = 1f; break; default: throw new ArgumentOutOfRangeException("newState", newState, null); } state = newState; if (stateChanged != null) { stateChanged(oldState, state); } } /// /// Called when the game is over /// public void GameOver() { SetState(State.GameOver); } /// /// Pause the game and display the pause menu /// public void Pause() { SetState(State.Paused); } /// /// Resume the game and close the pause menu /// public void Unpause() { SetState(State.Normal); } /// /// Changes the mode to drag /// /// /// The tower to build /// /// /// Throws exception when trying to change to Drag mode when not in Normal Mode /// public void SetToDragMode([NotNull] Tower towerToBuild) { if (state != State.Normal) { throw new InvalidOperationException("Trying to enter drag mode when not in Normal mode"); } if (m_CurrentTower != null) { // Destroy current ghost CancelGhostPlacement(); } SetUpGhostTower(towerToBuild); SetState(State.BuildingWithDrag); } /// /// 点击某一个塔防之后,开启拖动塔防的模式。 /// River: 修改为暂不删除原来的Tower,把原来的Tower隐藏掉. /// /// public void startDragTower(Tower towerOld) { Tower newT = null; foreach (Tower tower in EndlessLevelManager.instance.TowerLibrary) { if (tower.towerName != towerOld.towerName) continue; newT = Instantiate(tower, transform); break; } // 从列表中删除Tower.并破坏Tower的外形。 dragTowerLevel = towerOld.currentLevel; // 尝试不再删除原来的Tower,而是尝试在合成成功后再删除原来的Tower towerOld.showTower(false); towerToMove = towerOld; // 先删除,再设置移动相关。 SetToDragMode(newT); if (towerOld.towerFeature == EFeatureTower.Skill_Bomb) m_CurrentTower.SetAttackArea(dragTowerLevel, towerOld.ElfId); } /// /// Sets the UI into a build state for a given tower /// River: 当界面上某一个塔防的按钮被按下后,需要调用的这个函数进入建造模式。 /// /// /// The tower to build /// /// /// Throws exception trying to enter Build Mode when not in Normal Mode /// public void SetToBuildMode([NotNull] Tower towerToBuild) { if (state != State.Normal) { throw new InvalidOperationException("Trying to enter Build mode when not in Normal mode"); } if (m_CurrentTower != null) { // Destroy current ghost CancelGhostPlacement(); } SetUpGhostTower(towerToBuild); SetState(State.Building); } /// /// 目标位置是否是可攻击属性的空塔位 /// /// /// protected bool isFreeAttackGrid(PointerInfo pinfo) { // 判断格子上的塔防: UIPointer pointer = WrapPointer(pinfo); Tower sTower = PickTowerInGrid(pointer); if (sTower != null) { return false; } if ((m_GridPosition.x >= 0) && (m_GridPosition.y >= 0)) { if (m_CurrentArea.isFreeAtackPos(m_GridPosition.x, m_GridPosition.y)) { return true; } } return false; } /// /// 是否是可开启的AttackGrid塔位. /// /// /// protected bool isWaitBuyAttackGrid(PointerInfo pinfo) { // 判断格子上的塔防: UIPointer pointer = WrapPointer(pinfo); Tower sTower = PickTowerInGrid(pointer); if (sTower != null) return false; if ((m_GridPosition.x >= 0) && (m_GridPosition.y >= 0)) { if (m_CurrentArea.isWaitBuyGrid(m_GridPosition.x, m_GridPosition.y)) return true; } return false; } /// /// 目标位置是否有同等级同类型的Tower. /// /// /// protected bool isValidateCombineTarget(PointerInfo pinfo) { // 判断是否格子上重复放置塔防 if (!m_CurrentTower || !IsGhostAtValidPosition()) { // 最大级别的Tower不能再合并了. if (towerToMove.IsMaxLevel) return false; // 判断格子上的塔防: UIPointer pointer = WrapPointer(pinfo); Tower sTower = PickTowerInGrid(pointer); // 泡泡禁锢状态不允许合并 if (sTower.IsBondage) return false; if (sTower && sTower != towerToMove) { int testLvl = dragTowerLevel; if (towerToMove && sTower.currentLevel == testLvl && sTower.towerName == towerToMove.towerName) return true; } } return false; } /// /// 判断是否有不同类型的Tower,可以发生置换,仅限于火木水之间发生 /// /// /// protected bool IsSubstitute(PointerInfo pinfo) { if (!m_CurrentTower || !IsGhostAtValidPosition()) { // 判断格子上的塔防: UIPointer pointer = WrapPointer(pinfo); Tower sTower = PickTowerInGrid(pointer); // 泡泡禁锢状态不允许置换 if (sTower.IsBondage) return false; if (sTower && sTower != towerToMove) { if (towerToMove && sTower.towerFeature == EFeatureTower.NULL && towerToMove.towerFeature == EFeatureTower.NULL && sTower.bInAttackMode && towerToMove.bInAttackMode) return true; } } return false; } /// /// 判断是否有不同类型的Tower,可以发生置换,仅限于火木水之间发生 /// /// /// protected bool IsSubstituteGuide(PointerInfo pinfo) { if (!m_CurrentTower || !IsGhostAtValidPosition()) { // 判断格子上的塔防: UIPointer pointer = WrapPointer(pinfo); Tower sTower = PickTowerInGrid(pointer); if (sTower && sTower != towerToMove) { if (towerToMove && sTower.towerFeature == EFeatureTower.NULL && towerToMove.towerFeature == EFeatureTower.NULL) return true; } } return false; } /// /// 获取目标格子上的塔防的名字数据 /// /// /// protected string getTargetTowerName(PointerInfo pinfo) { if (m_CurrentTower == null || !IsGhostAtValidPosition()) { // 获取目标格子上的塔防指针: UIPointer pointer = WrapPointer(pinfo); Tower sTower = PickTowerInGrid(pointer); if ((sTower != null) && (sTower != towerToMove)) { return sTower.towerName; } } return ""; } /// /// 成长骰子升级为高一级别的随机骰子. /// /// protected void growUpTower(Tower tower) { Tower newTower = EndlessRandomTower.instance.GetRandomTower(EFeatureTower.NULL); // 所有的Tower不能升级成为FeatureTower. int maxLoop = 20; while (newTower.towerFeature != EFeatureTower.NULL) { newTower = EndlessRandomTower.instance.GetRandomTower(EFeatureTower.NULL); maxLoop--; if (maxLoop <= 0) { newTower = EndlessRandomTower.instance.getRTower(); Debug.LogError("超级循环发生了."); break; } } // 成长为高一级别的骰子 DisplaceTower(newTower, tower, 1); } /// /// 破坏某一列的塔位数据 /// /// /// public void DestroyTowerGrid(int xidx) { // 这里的逻辑已经不走了 for (int i = 0; i < AttackRowNumbers; ++i) { if (TowerDestroyArr[xidx, i]) continue; Node newNode = EndlessLevelManager.instance.SwitchHomeBase(xidx); WaveLineAgentInsMgr[] agentInsMgrs = AgentInsManager.instance.GetWaveLineList(); for (int j = 0; j < agentInsMgrs[xidx].listAgent.Count; ++j) { agentInsMgrs[xidx].listAgent[j].ChangeNextNode(newNode); } TowerDestroyArr[xidx, i] = true; Tower tower = FindTowerWithGridIdx(xidx, 3 - i); if (tower) { delTower(tower); tower.Sell(); } if (m_CurrentArea != null) // 3 -> dimensions.y - 1 m_CurrentArea.SetDestroyedGrid(xidx, 3 - i); break; } bool isAllDestroyed = true; for (int i = 0; i < AttackRowNumbers; ++i) { if (!TowerDestroyArr[xidx, i]) { isAllDestroyed = false; break; } } // 该兵线的所有基地都被摧毁完毕,目前的逻辑只要有一条兵线两个基地都被摧毁就算游戏结束 if (isAllDestroyed) { // 停止所有兵线的出兵 for (int i = 0; i < TotalWaveLines; ++i) { EndlessLevelManager.instance.StopWaveLine(i); } // 让所有兵线上已经生成的所有agent播放一个死亡动画然后销毁 WaveLineAgentInsMgr[] waveLineAgentIns = AgentInsManager.instance.GetWaveLineList(); for (int i = 0; i < waveLineAgentIns.Length; ++i) { while (waveLineAgentIns[i].listAgent.Count > 0) { waveLineAgentIns[i].listAgent[0].PlayDeath(); } } GameOver(); overTimer = new Timer(1.2f, SafelyCallGameOverEvent); } } /// /// 爱心数量为0,游戏结束 /// private void AllHeartLose() { // 清理技能 EndlessBossSkillManager.instance.ClearSkillList(); EndlessBossHPManager.instance.SwitchHP(true); EndlessBossHPManager.instance.SetCurrentHP(0); // 停止所有兵线的出兵 for (int i = 0; i < TotalWaveLines; ++i) { EndlessLevelManager.instance.StopWaveLine(i); } // 让所有兵线上已经生成的所有agent播放一个死亡动画然后销毁 WaveLineAgentInsMgr[] waveLineAgentIns = AgentInsManager.instance.GetWaveLineList(); GameOver(); for (int i = 0; i < waveLineAgentIns.Length; ++i) { while (waveLineAgentIns[i].listAgent.Count > 0) { waveLineAgentIns[i].listAgent[0].PlayDeath(); } } overTimer = new Timer(1.2f, SafelyCallGameOverEvent); } private void SafelyCallGameOverEvent() { if (GameOverEvent != null) GameOverEvent(); overTimer = null; } #region 拖动时候给塔位一个标识 public MeshRenderer temporaryMat;//移动时候的虚像材质 /// /// 查找可以合成的塔 /// public void CheckAllCanPlace() { if (m_CurrentTower != null) { if (m_CurrentTower.controller.towerFeature == EFeatureTower.NULL) { // if (m_CurrentArea != null && m_CurrentTower.controller.gridPosition.y >= 2) // { // //修改为只要开启格子都可以放 // (m_CurrentArea as TowerPlacementGridEndless).CheckCanPlaceUpdate(m_CurrentTower.controller.gridPosition.x, m_CurrentTower.controller.gridPosition.y, false, ""); // //(m_CurrentArea as TowerPlacementGridEndless).PlayPS(allPSTowerP); // } return; List allTowerP = null;//排除不能合成的 // List allPSTowerP = new List();//需要播放升级动画的 if (towerToMove) { if (towerToMove.gridPosition.y == 0 || towerToMove.gridPosition.y == 1) { allTowerP = new List(); for (int i = 0; i < m_listTower.Count; i++) { if (m_listTower[i].bInAttackMode && towerToMove && m_listTower[i].currentLevel == dragTowerLevel && m_listTower[i].towerName == towerToMove.towerName) { // if (towerToMove.gridPosition != m_listTower[i].gridPosition) // //说明可以合成 // allPSTowerP.Add(m_listTower[i].gridPosition); } else { //把不符合条件的传进去 allTowerP.Add(m_listTower[i].gridPosition); } } } } if (m_CurrentArea != null) { //修改为只要开启格子都可以放 (m_CurrentArea as TowerPlacementGridEndless).CheckAllCanPlace(allTowerP); //(m_CurrentArea as TowerPlacementGridEndless).PlayPS(allPSTowerP); } } else if (m_CurrentTower.controller.towerFeature == EFeatureTower.Skill_Fire || m_CurrentTower.controller.towerFeature == EFeatureTower.Skill_Bomb) { //Debug.Log("需要激活兵线下方绿色标识"); EventCenter.Ins.BroadCast((int)KTGMGemClient.EventType.EndlessStartDragSkill, true); } } } /// /// 关闭所有标识 /// public void CloseCanPlaceRenderer() { if (m_CurrentTower && m_CurrentTower.controller && m_CurrentTower.controller.towerFeature == EFeatureTower.Skill_Fire || m_CurrentTower.controller.towerFeature == EFeatureTower.Skill_Bomb) { EventCenter.Ins.BroadCast((int)KTGMGemClient.EventType.EndlessStartDragSkill, false); } if (m_CurrentArea != null) (m_CurrentArea as TowerPlacementGridEndless).CloseCanPlaceRenderer(); else { GameObject placeObj = GameObject.FindGameObjectWithTag("PlaceTower"); if (placeObj != null) (placeObj.GetComponent() as TowerPlacementGridEndless).CloseCanPlaceRenderer(); } } Tower checkTowerPlaceTower;//移动时候查看鼠标是否检测到有塔 Tower bInAttackModeTower;//在合成区的塔 /// /// 检查符合条件的塔 /// /// public void CheckTowerPlace(PointerInfo pointerInfo) { //return; if (m_CurrentArea != null && m_CurrentArea is TowerPlacementGridEndless) { checkTowerPlaceTower = isFreeAttackGridOnDrag(pointerInfo); //下面是为了设置一个虚拟的塔 if (checkTowerPlaceTower != null) { if (m_CurrentTower.controller.towerFeature == EFeatureTower.NULL) { if (checkTowerPlaceTower.bInAttackMode) { //鼠标检测到了塔 (m_CurrentArea as TowerPlacementGridEndless).CheckCanPlaceUpdate(m_GridPosition.x, m_GridPosition.y, false, ""); } else { if (!towerToMove.bInAttackMode) { //没有上阵 if (bInAttackModeTower == null) { bInAttackModeTower = checkTowerPlaceTower; bInAttackModeTower.CurrentTowerLevel.SetCanPlace(true); } else if (bInAttackModeTower != checkTowerPlaceTower) { bInAttackModeTower.CurrentTowerLevel.SetCanPlace(false); bInAttackModeTower = checkTowerPlaceTower; bInAttackModeTower.CurrentTowerLevel.SetCanPlace(true); } } } } else if (m_CurrentTower.controller.towerFeature == EFeatureTower.Skill_Fire || m_CurrentTower.controller.towerFeature == EFeatureTower.Skill_Bomb) { //技能宝石没有上阵 if (bInAttackModeTower == null) { bInAttackModeTower = checkTowerPlaceTower; bInAttackModeTower.CurrentTowerLevel.SetCanPlace(true); } else if (bInAttackModeTower != checkTowerPlaceTower) { bInAttackModeTower.CurrentTowerLevel.SetCanPlace(false); bInAttackModeTower = checkTowerPlaceTower; bInAttackModeTower.CurrentTowerLevel.SetCanPlace(true); } } } else if ((m_GridPosition.x >= 0) && (m_GridPosition.y >= 0)) { //查看是否是一个空格子 if (m_CurrentArea.isFreeAtackPos(m_GridPosition.x, m_GridPosition.y)) { if (m_CurrentTower.controller.towerFeature == EFeatureTower.NULL) { //空格子 (m_CurrentArea as TowerPlacementGridEndless).CheckCanPlaceUpdate(m_GridPosition.x, m_GridPosition.y, true, towerToMove.towerName); } } else { CloseCanPlace(); } } else { CloseCanPlace(); } } else { if (m_CurrentTower.controller.towerFeature == EFeatureTower.NULL) { dragTowerPlacement.CloseCanPlace(); } } } void CloseCanPlace() { dragTowerPlacement.CloseCanPlace(); if (bInAttackModeTower != null) { bInAttackModeTower.CurrentTowerLevel.SetCanPlace(false); bInAttackModeTower = null; } } TowerPlacementGridEndless dragTowerPlacement; /// /// 目标位置是否是可攻击属性的空塔位 /// /// /// protected Tower isFreeAttackGridOnDrag(PointerInfo pinfo) { // 判断格子上的塔防: UIPointer pointer = WrapPointer(pinfo); Tower sTower = PickTowerInGrid(pointer); if (sTower != null) { // if (towerToMove && sTower.currentLevel == dragTowerLevel && sTower.towerName == towerToMove.towerName) // { // //说明可以合成 // return sTower; // } // else // { // return null; // } if (towerToMove) { if (towerToMove.bInAttackMode) { return sTower; } else { if (sTower.currentLevel == dragTowerLevel && sTower.towerName == towerToMove.towerName) { //说明可以合成 return sTower; } } } else { return null; } } return null; } #endregion /// /// 拖动一个Tower之后,松开鼠标或者EndDrag. /// 1: 目标点可合成,则直接合成。 /// 2: 目标点不管是空白,还是不能放置Tower,都要让当前的Tower返回到原来的TowerPlace /// /// public void onEndTowerDrag(PointerInfo pointerInfo) { bool bSkill = false; if (temporaryMat != null) { //移动虚像隐藏 temporaryMat.material = null; } if (!m_CurrentTower || !m_CurrentTower.controller) { CancelPlaceTower(pointerInfo); return; } if (m_CurrentTower.controller.towerFeature != EFeatureTower.NULL) bSkill = true; if (GameConfig.IsNewbie) { bool isCanChange = false; if (EndlessLevelManager.instanceExists && IsSubstituteGuide(pointerInfo)) { isCanChange = CheckCanChangePos(pointerInfo); } if (isCanChange) { GuideCtrl.Ins.DragDone(); Debug.Log("交换了位置"); } else { GuideCtrl.Ins.EndDrag5_1(); CancelPlaceTower(pointerInfo); Debug.Log("没有放置在火塔上"); } return; } // 判断目标位置是否有Tower且类型和等级一致,如果没有,则GhostTower删除,原Tower显示。 if (isValidateCombineTarget(pointerInfo)) { TryPlaceTower(pointerInfo); EndlessRandomTower.instance.UpdateDescDisplay(); } else if (isFreeAttackGrid(pointerInfo) && !bSkill) { if (!TryPlaceTower(pointerInfo, false)) { CancelPlaceTower(pointerInfo); Debug.Log("这里需要返回原位"); return; } // 删除towerToMove,确保塔防数据不再出现多个 if (towerToMove != null) { delTower(towerToMove); towerToMove.showTower(true); towerToMove.Sell(); towerToMove = null; } } else if (EndlessLevelManager.instanceExists && IsSubstitute(pointerInfo)) { CheckCanChangePos(pointerInfo); } // 当前是Skill塔位的状态. else if (bSkill) { if (SkillPlayEndDrag(pointerInfo)) { // 先释放掉当前的Ghost塔防. CancelGhostPlacement(); // 删除towerToMove,确保塔防数据不再出现多个 if (towerToMove != null) { delTower(towerToMove); towerToMove.showTower(true); towerToMove.Sell(); towerToMove = null; } } else CancelPlaceTower(pointerInfo); } else CancelPlaceTower(pointerInfo); } private bool CheckCanChangePos(PointerInfo pointerInfo) { // 可以发生置换 UIPointer pointer = WrapPointer(pointerInfo); // 格子上的塔 Tower sTower = PickTowerInGrid(pointer); if (sTower == null) return false; if (sTower.bInAttackMode == towerToMove.bInAttackMode) { IntVector2 v1 = new IntVector2(towerToMove.gridPosition.x, towerToMove.gridPosition.y); IntVector2 v2 = new IntVector2(sTower.gridPosition.x, sTower.gridPosition.y); if (m_CurrentArea == null) { CancelGhostPlacement(); towerToMove.showTower(true); return false; } else { Tower newTower1 = PlaceTowerForce(EndlessRandomTower.instance.getTowerByName(sTower.towerName), v1, sTower.currentLevel + 1, false); Tower newTower2 = PlaceTowerForce(m_CurrentTower.controller, v2, towerToMove.currentLevel + 1, false); if (towerToMove != null) { delTower(towerToMove); towerToMove.showTower(true); towerToMove.Sell(); towerToMove = null; } delTower(sTower); sTower.showTower(true); sTower.Sell(); sTower = null; CancelGhostPlacement(); newTower1.placementArea.Occupy(newTower1.gridPosition, newTower1.dimensions); newTower2.placementArea.Occupy(newTower2.gridPosition, newTower2.dimensions); //强制交换塔的时候检查自身充能条 newTower1.CheckCtrl(); newTower2.CheckCtrl(); return true; } } return false; } /// /// 强制放置塔,主要是用于新手 /// /// /// /// 塔的等级 public Tower PlaceTowerForce(Tower newTower, IntVector2 pos, int level, bool playEffect = true) { TowerPlacementGhost currentTower = Instantiate(newTower.towerGhostPrefab); currentTower.Initialize(newTower); Tower controller = currentTower.controller; Tower createdTower = Instantiate(controller); createdTower.PlayWaveLineFlash = playEffect; createdTower.Initialize(m_CurrentArea, pos, level - 1); if (playEffect) PlayUpgradeEffect(createdTower); addTower(createdTower); Destroy(currentTower.gameObject); return createdTower; } protected bool SkillPlayEndDrag(PointerInfo pointer) { // 我操,终于可以了!ATTENTION TO OPP: PointerInfo tp = new PointerActionInfo(); tp.currentPosition = pointer.currentPosition; tp.previousPosition = pointer.previousPosition; tp.delta = pointer.delta; tp.startedOverUI = pointer.startedOverUI; // River: 调整偏移值,用于鼠标移动塔防的时候,更加平滑。 tp.currentPosition.x += selTowerOffset.x; tp.currentPosition.y += selTowerOffset.y; UIPointer npt = new UIPointer { overUI = false, pointer = tp, overWaveLine = false, ray = m_Camera.ScreenPointToRay(tp.currentPosition) }; int sId = towerToMove.ElfId; int sLevel = towerToMove.currentLevel; // 火是列攻击: if (m_CurrentTower.controller.towerFeature == EFeatureTower.Skill_Fire) { WavelineAreaRaycast(ref npt); if (npt.overWaveLine) { WaveLineSelEffect selEff = npt.wavelineHit.Value.collider.GetComponent(); if (selEff) { // 播放特效,并处理伤害. EndlessWaveLineManager.instance.PlayWaveLineEffect(selEff.waveLineId); AgentInsManager.instance.ExecWavelineAttack(selEff.waveLineId, sId, sLevel, false); ++GameConfig.EndlessPortUseSkillTowerCount; return true; } } } // 炸弹是区域攻击显示: if (m_CurrentTower.controller.towerFeature == EFeatureTower.Skill_Bomb) { // 测试代码与战场区域碰撞,碰撞后显示攻击区域: BattleAreaRaycast(ref npt); if (npt.overWaveLine) { EndlessWaveLineManager.instance.PlayBattleAreaBombEffect(npt.wavelineHit.Value.point); AgentInsManager.instance.ExecBombAttack(npt.wavelineHit.Value.point, sId, sLevel, false); return true; } } return false; } protected void CancelPlaceTower(PointerInfo pointerInfo) { CancelGhostPlacement(); if (towerToMove) { towerToMove.showTower(true); towerToMove.CheckCtrl(); // 处理复制骰子: if (towerToMove.towerFeature == EFeatureTower.CopyCat) { CopyTargetTower(pointerInfo); } else { // 升级目标位置的塔防. currentSelectedTower = towerToMove; } towerToMove = null; } SetState(State.Normal); } /// /// 处理复制宝石塔防 /// /// protected void CopyTargetTower(PointerInfo pointerInfo) { string tstr = getTargetTowerName(pointerInfo); Tower targetTower = null; if (tstr.Length > 0) targetTower = EndlessRandomTower.instance.getTowerByName(tstr); currentSelectedTower = towerToMove; if (targetTower) { // 1:记录当前Tower的Level,删除当前的Tower. int towerLvl = currentSelectedTower.currentLevel + 1; int posx = currentSelectedTower.gridPosition.x; int posy = currentSelectedTower.gridPosition.y; currentSelectedTower.Sell(); delTower(currentSelectedTower); // 在目标位置放置新的Tower类型,只有零级。 RandomPlaceTower(targetTower, posx, posy, 0); } } /// /// Attempt to position a tower at the given location /// /// The pointer we're using to position the tower public bool TryPlaceTower(PointerInfo pointerInfo, bool force = false) { UIPointer pointer = WrapPointer(pointerInfo); // Do nothing if we're over UI if (pointer.overUI && !force) { Debug.Log("在UI上了,直接返回"); return false; } return BuyTower(pointer, force); } /// /// 根据鼠标的点击信息来确认当前点击的位置是否有塔防模型。 /// /// /// protected Tower PickTowerInGrid(UIPointer pointer) { RaycastHit output; bool hasHit = Physics.Raycast(pointer.ray, out output, float.MaxValue, towerSelectionLayer); if (!hasHit || pointer.overUI) { return null; } var controller = output.collider.GetComponent(); return controller; } /// /// Position the ghost tower at the given pointer /// /// The pointer we're using to position the tower /// Optional parameter for configuring if the ghost is hidden when in an invalid location public void TryMoveGhost(PointerInfo pointerInfo, bool hideWhenInvalid = true) { if (m_CurrentTower == null) { return; //throw new InvalidOperationException("Trying to move the tower ghost when we don't have one"); } UIPointer pointer = WrapPointer(pointerInfo); // Do nothing if we're over UI if (pointer.overUI && hideWhenInvalid) { m_CurrentTower.Hide(); return; } MoveGhost(pointer, hideWhenInvalid); } /// /// Activates the tower controller UI with the specific information /// /// /// The tower controller information to use /// /// /// Throws exception when selecting tower when does not equal /// public void SelectTower(Tower tower) { if (state != State.Normal) { throw new InvalidOperationException("Trying to select whilst not in a normal state"); } DeselectTower(); currentSelectedTower = tower; if (currentSelectedTower != null) { currentSelectedTower.removed += OnTowerDied; } startDragTower(tower); } /// /// 在当前的PlaceArea内删除有相同LvL相同类型的防塔. /// /// public bool deleteSameLvlTower(Tower tower) { Tower delTower = findSameLvlTower(tower); if (delTower == null) return false; Tower backT = currentSelectedTower; currentSelectedTower = delTower; SellSelectedTower(); currentSelectedTower = backT; return true; } /// /// Upgrades , if possible /// /// /// Throws exception when selecting tower when does not equal /// or is null /// public void UpgradeSelectedTower() { if (state != State.Normal) { throw new InvalidOperationException("Trying to upgrade whilst not in Normal state"); } if (currentSelectedTower == null) { throw new InvalidOperationException("Selected Tower is null"); } if (currentSelectedTower.IsMaxLevel) { return; } currentSelectedTower.UpgradeTower(); DeselectTower(); } /// /// 当前的塔防随机升级为另一种塔防的种类。 /// protected bool randomUpgradeTower() { if (state != State.Normal) { throw new InvalidOperationException("Trying to upgrade whilst not in Normal state"); } if (currentSelectedTower == null) { throw new InvalidOperationException("Selected Tower is null"); } if (currentSelectedTower.IsMaxLevel) return false; // 直接随机升级,零成本。 // 1:记录当前Tower的Level,删除当前的Tower. 2:从TowerLib中随机找一个高一级别的Tower. string towerName = currentSelectedTower.towerName; if (currentSelectedTower.towerFeature == EFeatureTower.NULL && GameConfig.CreateRandomTower) towerName = ""; int towerLvl = currentSelectedTower.currentLevel + 1; int posx = currentSelectedTower.gridPosition.x; int posy = currentSelectedTower.gridPosition.y; currentSelectedTower.Sell(); delTower(currentSelectedTower); // 随机放置一个新的Tower EndlessRandomTower.instance.randomTower(posx, posy, towerLvl, towerName); DeselectTower(); return true; } /// /// Sells if possible /// /// /// Throws exception when selecting tower when does not equal /// or is null /// public void SellSelectedTower() { if (state != State.Normal) { throw new InvalidOperationException("Trying to sell tower whilst not in Normal state"); } if (currentSelectedTower == null) { throw new InvalidOperationException("Selected Tower is null"); } currentSelectedTower.Sell(); // 从列表中删除Tower. delTower(currentSelectedTower); DeselectTower(); } /// /// Buys the tower and places it in the place that it currently is /// /// /// Throws exception if trying to buy towers in Build Mode /// public void BuyTower() { if (!isBuilding) { throw new InvalidOperationException("Trying to buy towers when not in Build Mode"); } if (m_CurrentTower == null || !IsGhostAtValidPosition()) { return; } PlaceTower(); } /// /// Used to buy the tower during the build phase /// Checks currency and calls /// /// Throws exception when not in a build mode or when tower is not a valid position /// /// public bool BuyTower(UIPointer pointer, bool force = false) { if (!isBuilding) return false; // 判断是否格子上重复放置塔防 if (!m_CurrentTower || !IsGhostAtValidPosition()) { // 判断格子上的塔防: Tower sTower = PickTowerInGrid(pointer); if (sTower) { Tower curTower = m_CurrentTower.controller; int testLvl = dragTowerLevel; if ((sTower.currentLevel == testLvl) && (sTower.towerName == curTower.towerName)) { // 先释放掉当前的Ghost塔防. CancelGhostPlacement(); // 升级目标位置的塔防. currentSelectedTower = sTower; SetState(State.Normal); // 新的代码,合并升级为随机塔防类型. randomUpgradeTower(); } } else { // 放置攻击塔位 PlacementAreaRaycast(ref pointer); if (!pointer.raycast.HasValue || pointer.raycast.Value.collider == null) { CancelGhostPlacement(); return false; } PlaceGhost(pointer); } return true; } // 这是判断是否超出了格子 PlacementAreaRaycast(ref pointer, force); if (!pointer.raycast.HasValue || pointer.raycast.Value.collider == null) { CancelGhostPlacement(); return false; } bool successfulPurchase = EndlessLevelManager.instance.Currency.TryPurchase(0); if (successfulPurchase) { PlaceGhost(pointer); } return true; } /// /// 播放升级特效 /// /// public void PlayUpgradeEffect(Tower newTower) { newTower.CurrentTowerLevel.PlayUpGradeEffect(); } /// /// Deselect the current tower and hides the UI /// public void DeselectTower() { if (currentSelectedTower != null) { currentSelectedTower.removed -= OnTowerDied; } currentSelectedTower = null; if (selectionChanged != null) { selectionChanged(null); } } /// /// Checks the position of the /// on the /// /// /// True if the placement is valid /// /// /// Throws exception if the check is done in state /// public bool IsGhostAtValidPosition(bool opponent = false) { if (m_CurrentTower == null || m_CurrentArea == null) return false; TowerFitStatus fits = m_CurrentArea.Fits(m_GridPosition, m_CurrentTower.controller.dimensions); return fits == TowerFitStatus.Fits; } /// /// Checks if buying the ghost tower is possible /// /// /// True if can purchase /// /// /// Throws exception if not in Build Mode or Build With Dragging mode /// public bool IsValidPurchase() { if (!isBuilding) { throw new InvalidOperationException("Trying to check ghost position when not in a build mode"); } if (m_CurrentTower == null || m_CurrentArea == null) return false; return true; } /// /// Places a tower where the ghost tower is /// /// /// Throws exception if not in Build State or is not at a valid position /// public void PlaceTower(int lvl = 0, bool isUpgrade = false, bool opponent = false, bool isFirstAppear = false) { if (!isBuilding) throw new InvalidOperationException("Trying to place tower when not in a Build Mode"); if (lvl <= 0) { if (!IsGhostAtValidPosition(opponent)) throw new InvalidOperationException("Trying to place tower on an invalid area"); } if (m_CurrentArea == null) return; Tower createdTower = Instantiate(m_CurrentTower.controller); createdTower.opponentSide = opponent; createdTower.Initialize(m_CurrentArea, m_GridPosition, lvl); // River: 内部缓存数据,用于后期容易找到数据. addTower(createdTower); CancelGhostPlacement(); if (isFirstAppear) { PlayFirstAppearEffect(createdTower.towerName, createdTower.transform.position); } else if (!isUpgrade) { PlayAppearEffect(createdTower.transform.position); } else { PlayUpgradeEffect(createdTower); } // 处理成长骰子,复制骰子等等功能. if (lvl == 0) { ProcessFeatureTower(createdTower); } } /// /// 播放首次宝石出现特效 /// public void PlayFirstAppearEffect(string towerName, Vector3 worldPos) { if (towerName.StartsWith("GrowUpTower")) { //火元素 PlayAppearEffect(worldPos, fireAppearEffect1); PlayAppearEffect(worldPos, fireAppearEffect2); if (Application.platform == RuntimePlatform.WindowsEditor) { //UnityEditor.EditorApplication.isPaused = true; } } else if (towerName.StartsWith("BlinkTower")) { //木元素 PlayAppearEffect(worldPos, woodAppearEffect1); PlayAppearEffect(worldPos, woodAppearEffect2); } else if (towerName.StartsWith("CopyCatTower")) { //水元素 PlayAppearEffect(worldPos, waterAppearEffect1); PlayAppearEffect(worldPos, waterAppearEffect2); } } void PlayAppearEffect(Vector3 worldPos, GameObject prefab) { GameObject obj = Instantiate(prefab); obj.transform.position = worldPos; Vector3 pos = obj.transform.position; pos.y += 5f; obj.transform.position = pos; ParticleSystem ps = obj.GetComponent(); if (ps == null) ps = obj.transform.GetChild(0).GetComponent(); ps.Play(); Destroy(obj, ps.main.duration); } public void PlayAppearEffectGuide(Vector3 worldPos) { GameObject obj = Instantiate(TowerAppearEffectPrefabGuide); obj.transform.position = worldPos; Vector3 pos = obj.transform.position; pos.y += 5f; obj.transform.position = pos; ParticleSystem ps = obj.GetComponent(); if (ps == null) ps = obj.transform.GetChild(0).GetComponent(); ps.Play(); Destroy(obj, ps.main.duration); } /// /// 播放宝石出现特效 /// public void PlayAppearEffect(Vector3 worldPos) { GameObject obj = Instantiate(TowerAppearEffectPrefab); obj.transform.position = worldPos; Vector3 pos = obj.transform.position; pos.y += 5f; obj.transform.position = pos; ParticleSystem ps = obj.GetComponent(); if (ps == null) ps = obj.transform.GetChild(0).GetComponent(); ps.Play(); Destroy(obj, ps.main.duration); } /// /// 播放升级特效 /// /// public void GuidePlayUpgradeEffect(Vector3 position) { // 在sTower的位置播放升级特效 GameObject obj = Instantiate(TowerUpgradeEffectPrefabGuide); obj.transform.position = position; Vector3 pos = obj.transform.position; pos.y += 5f; obj.transform.position = pos; ParticleSystem ps = obj.GetComponent(); if (ps == null) ps = obj.transform.GetChild(0).GetComponent(); ps.Play(); Destroy(obj, ps.main.duration); } protected void ProcessFeatureTower(Tower ctower) { if (ctower.towerFeature == EFeatureTower.GrowUp) { Timer timer = new Timer(10.0f, () => { growUpTower(ctower); }); listTowerTimer.Add(timer); towerTimeDic.Add(timer.timerID, ctower); } else if (ctower.towerFeature == EFeatureTower.CopyCat) { } return; } /// /// 成功购买塔防后,更新价格,更新按钮,更新按钮上的塔防价格等等. /// protected void OnSuccessBuyTower() { var tpMgr = TowerPrice.instance; if (!tpMgr) return; // 价格更新 tpMgr.onTowerBuySuccess(); if (!towerPriceText) { towerPriceText = randomTowerBtn.transform.Find("cashText").GetComponent(); //towerPriceText1 = SkillTowerBtn.transform.Find("cashText").GetComponent(); if (towerPriceText) towerPriceText.text = tpMgr.currentTowerPrice.ToString(); // if (towerPriceText1) // towerPriceText1.text = tpMgr.currentTowerPrice.ToString(); } else { towerPriceText.text = tpMgr.currentTowerPrice.ToString(); //towerPriceText1.text = tpMgr.currentTowerPrice.ToString(); } // 无法支付新的塔防价格,按钮变灰. if (tpMgr.currentTowerPrice > EndlessLevelManager.instance.Currency.currentCurrency) { disableRandomTowerBtn(); } } /// /// 随机放置Tower按钮禁止使用,灰掉. /// protected void disableRandomTowerBtn() { randomTowerBtn.GetComponent().ChangeBtnClick(); //randomTowerBtn.interactable = false; if (towerPriceText) { towerPriceText.color = new Color(0.5f, 0.5f, 0.5f); //towerPriceText1.color = new Color(0.5f, 0.5f, 0.5f); } tdBuyDisable = true; } /// /// 随机购买Tower的按钮重设置为有效. /// protected void enableRandomTowerBtn() { // ATTENTION TO FIX: 再次判断是因为有的地方是直接调用 if ((TowerPrice.instance.currentTowerPrice > EndlessLevelManager.instance.Currency.currentCurrency) || (m_listTower.Count >= MAX_TOWERNUM)) return; if (towerPriceText) { towerPriceText.color = new Color(1.0f, 1.0f, 1.0f); //towerPriceText1.color = new Color(1.0f, 1.0f, 1.0f); } if (randomTowerBtn) { randomTowerBtn.GetComponent().ChangeBtnClickNormal(); //randomTowerBtn.interactable = true; } tdBuyDisable = false; } /// /// 游戏内向上飘血 /// /// /// /// public void generateBloodText(Vector3 wpos, float val, bool crit = false, bool doubleHit = false, bool poison = false) { if (Mathf.FloorToInt(val) == 0) return; Vector3 spos = m_Camera.WorldToScreenPoint(wpos); TextMoveDoTween tm; if (crit) { tm = Poolable.TryGetPoolable(bloodCrit.gameObject); } else if (poison) { tm = Poolable.TryGetPoolable(bloodPoison.gameObject); } else { tm = Poolable.TryGetPoolable(bloodText.gameObject); } if (tm) { tm.GetComponent().SetParent(GameObject.Find("MainUI/TextPanel").GetComponent(), true); string bloodStr = "-"; bloodStr += ((Int64)val).ToString(); tm.moveBloodText(spos.x, spos.y, bloodStr, crit); } } /// /// 减速飘字 /// public void FloatSlowDownWord(Vector3 worldPos) { Vector3 screenPos = m_Camera.WorldToScreenPoint(worldPos); GameObject obj = Instantiate(SlowDownWord.gameObject); obj.GetComponent().SetParent(GameObject.Find("MainUI/TextPanel").GetComponent(), false); obj.GetComponent().FloatSlowDownWord(screenPos.x, screenPos.y); } /// /// 暴击飘字 /// public void FloatCritWord(Vector3 worldPos) { Vector3 screenPos = m_Camera.WorldToScreenPoint(worldPos); GameObject obj = Instantiate(CritWord.gameObject); obj.GetComponent().SetParent(GameObject.Find("MainUI/TextPanel").GetComponent(), false); obj.GetComponent().FloatCritWord(screenPos.x, screenPos.y); } private void Start() { // 获取相应的放置区域。 GameObject placeObj = GameObject.FindGameObjectWithTag("PlaceTower"); if (placeObj != null) { m_CurrentArea = placeObj.GetComponent(); dragTowerPlacement = placeObj.GetComponent() as TowerPlacementGridEndless; } placeObj = GameObject.FindGameObjectWithTag("PlaceTowerOpponent"); EventCenter.Ins.Add((int)KTGMGemClient.EventType.EndlessHeartAllLose, AllHeartLose); } /// /// 替换towerToMove的目标Tower,如果是使用towerToMove,则必须提前处理相应的指针。 /// /// public void DisplaceTower(Tower newTower, Tower oldTower, int lvl = 0) { // 先记录oldTower的位置信息: int posx = oldTower.gridPosition.x; int posy = oldTower.gridPosition.y; bool opponent = oldTower.opponentSide; int newLvl = oldTower.currentLevel + 1; if (newLvl > 4) newLvl = 4; delTower(oldTower); oldTower.showTower(true); oldTower.Sell(); // 减化成长塔位对应的代码,用于不再影响目前正处于建设状态的塔位. if (m_CurrentArea == null) return; IntVector2 ivec; ivec.x = posx; ivec.y = posy; Tower createdTower = Instantiate(newTower); createdTower.opponentSide = opponent; createdTower.Initialize(m_CurrentArea, ivec, newLvl); // River: 内部缓存数据,用于后期容易找到数据. addTower(createdTower); } /// /// 直接在IPlaceArea上随机放置一个Tower。这是随机放置塔防的入口类。这是入口的塔防类。 /// /// public bool RandomPlaceTower(Tower tow, int posx = -1, int posy = -1, int lvl = 0, int forceCost = -1, bool isUpgrade = false, bool isFirstAppear = false) { // 获取IPlaceArea. if (m_CurrentArea == null) { GameObject placeObj = GameObject.FindGameObjectWithTag("PlaceTower"); if (placeObj == null) return false; // 获取相应的放置区域。 m_CurrentArea = placeObj.GetComponent(); if (m_CurrentArea == null) return false; } bool zeroCost = false; if (posx < 0 && posy < 0) { IntVector2 tvec = m_CurrentArea.getFreePos(1, 1); if (tvec.x < 0 && tvec.y < 0) return false; m_GridPosition.x = tvec.x; m_GridPosition.y = tvec.y; } else { m_GridPosition.x = posx; m_GridPosition.y = posy; zeroCost = true; } // 购买成功,才会继续放置塔防: if (tow.towerGhostPrefab == null) { return false; } // River: 修改Cost为全局统一维护的数据 int cost = TowerPrice.instance.currentTowerPrice; if (zeroCost) cost = 0; if (forceCost != -1) cost = forceCost; bool successfulPurchase = EndlessLevelManager.instance.Currency.TryPurchase(cost); if (!successfulPurchase) return false; EndlessRandomTower.instance.UpdateDescDisplay(); SetUpGhostTower(tow); //Debug.Log("设置影子塔防."); m_CurrentTower.Show(); if (successfulPurchase) { ++GameConfig.EndlessBuyTowerCount; // 删除towerToMove,确保塔防数据不再出现多个 if (zeroCost && (towerToMove != null)) { delTower(towerToMove); towerToMove.showTower(true); towerToMove.Sell(); towerToMove = null; } // 塔防购买成功后的相关更新: if (!zeroCost) OnSuccessBuyTower(); SetState(State.Building); PlaceTower(lvl, isUpgrade, false, isFirstAppear); } return true; } /// /// Calculates whether the given pointer is over the current tower ghost /// /// /// The information used to check against the /// /// /// Throws an exception if not in Build Mode /// public bool IsPointerOverGhost(PointerInfo pointerInfo) { if (state != State.Building) { throw new InvalidOperationException("Trying to tap on ghost tower when not in Build Mode"); } UIPointer uiPointer = WrapPointer(pointerInfo); RaycastHit hit; return m_CurrentTower.ghostCollider.Raycast(uiPointer.ray, out hit, float.MaxValue); } /// /// Selects a tower beneath the given pointer if there is one /// 选择塔防 /// /// /// The pointer information concerning the selector of the pointer /// /// /// Throws an exception when not in /// public void TrySelectTower(PointerInfo info) { if (state != State.Normal) { //throw new InvalidOperationException("Trying to select towers outside of Normal state"); return; } UIPointer uiPointer = WrapPointer(info); RaycastHit output; // River: Raycast的碰撞是游戏内物品的Collider进行碰撞检测的 bool hasHit = Physics.Raycast(uiPointer.ray, out output, float.MaxValue, towerSelectionLayer); if (!hasHit || uiPointer.overUI) { //Debug.Log("没有点中或者点中了UI:" + hasHit.ToString() + "," + uiPointer.overUI.ToString()); return; } var controller = output.collider.GetComponent(); if (controller != null) { // 泡泡禁锢状态不允许拖动 if (controller.IsBondage) return; SelectTower(controller); } // 计算偏移值. CalSelTowerScreenOffset(info, controller); } public void OnPressed(PointerInfo info) { UIPointer uiPointer = WrapPointer(info); RaycastHit output; bool hasHit = Physics.Raycast(uiPointer.ray, out output, float.MaxValue, towerSelectionLayer); if (uiPointer.overUI) return; if (hasHit) { Tower controller = output.collider.GetComponent(); if (controller != null) controller.OnPressed(); } } /// /// 鼠标选中一个Tower的时候,计算当前鼠标位置与当前Tower位置在屏幕上坐标位置的偏移量。 /// /// /// protected void CalSelTowerScreenOffset(PointerInfo info, Tower tower) { Vector3 towerCentPos = m_Camera.WorldToScreenPoint(tower.transform.position); selTowerOffset.x = towerCentPos.x - info.currentPosition.x; selTowerOffset.y = towerCentPos.y - info.currentPosition.y; } /// /// Gets the world position of the ghost tower /// /// /// Throws an exception when not in the Build Mode or /// When a ghost tower does not exist /// public Vector3 GetGhostPosition() { if (!isBuilding) { throw new InvalidOperationException("Trying to get ghost position when not in a Build Mode"); } if (m_CurrentTower == null) { throw new InvalidOperationException("Trying to get ghost position for an object that does not exist"); } return m_CurrentTower.transform.position; } /// /// Moves the ghost to the center of the screen /// /// /// Throws exception when not in build mode /// public void MoveGhostToCenter() { if (state != State.Building) { throw new InvalidOperationException("Trying to move ghost when not in Build Mode"); } // try to find a valid placement Ray ray = m_Camera.ScreenPointToRay(new Vector2(Screen.width * 0.5f, Screen.height * 0.5f)); RaycastHit placementHit; if (Physics.SphereCast(ray, sphereCastRadius, out placementHit, float.MaxValue, placementAreaMask)) { MoveGhostWithRaycastHit(placementHit); } else { MoveGhostOntoWorld(ray, false); } } /// /// Set initial values, cache attached components /// and configure the controls /// protected override void Awake() { base.Awake(); randomTowerBtn = transform.Find("BottomCanvas/Panel/TowerBuyBtn").GetComponent