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
|
{
|
/// <summary>
|
/// An object that manages user interaction with the game. Its responsibilities deal with
|
/// <list type="bullet">
|
/// <item>
|
/// <description>Building towers</description>
|
/// </item>
|
/// <item>
|
/// <description>Selecting towers and units</description>
|
/// </item>
|
/// </list>
|
/// </summary>
|
[RequireComponent(typeof(Camera))]
|
public class EndlessGameUI : Singleton<EndlessGameUI>
|
{
|
/// <summary>
|
/// The states the UI can be in
|
/// </summary>
|
public enum State
|
{
|
/// <summary>
|
/// The game is in its normal state. Here the player can pan the camera, select units and towers
|
/// </summary>
|
Normal,
|
|
/// <summary>
|
/// The game is in 'build mode'. Here the player can pan the camera, confirm or deny placement
|
/// </summary>
|
Building,
|
|
/// <summary>
|
/// The game is Paused. Here, the player can restart the level, or quit to the main menu
|
/// </summary>
|
Paused,
|
|
/// <summary>
|
/// The game is over and the level was failed/completed
|
/// </summary>
|
GameOver,
|
|
/// <summary>
|
/// The game is in 'build mode' and the player is dragging the ghost tower
|
/// </summary>
|
BuildingWithDrag
|
}
|
|
/// <summary>
|
/// Gets the current UI state
|
/// </summary>
|
public State state { get; private set; }
|
|
/// <summary>
|
/// The currently selected tower
|
/// </summary>
|
public LayerMask placementAreaMask;
|
|
/// <summary>
|
/// 兵线层对应的Mask.
|
/// </summary>
|
public LayerMask waveLineMask;
|
|
/// <summary>
|
/// 战场区域Mask.
|
/// </summary>
|
public LayerMask battleAreaMask;
|
|
/// <summary>
|
/// The layer for tower selection
|
/// </summary>
|
public LayerMask towerSelectionLayer;
|
|
/// <summary>
|
/// The physics layer for moving the ghost around the world
|
/// when the placement is not valid
|
/// </summary>
|
public LayerMask ghostWorldPlacementMask;
|
|
public readonly int MAX_TOWERNUM = 20;
|
|
/// <summary>
|
/// The radius of the sphere cast
|
/// for checking ghost placement
|
/// </summary>
|
public float sphereCastRadius = 1;
|
|
/// <summary>
|
/// 随机购买塔防的按钮.
|
/// </summary>
|
public Button randomTowerBtn;
|
|
public Button SkillTowerBtn;
|
|
/// <summary>
|
/// 飘血数字对应的prefab.
|
/// </summary>
|
public TextMoveDoTween bloodText;
|
|
/// <summary>
|
/// 中毒飘字.
|
/// </summary>
|
public TextMoveDoTween bloodPoison;
|
|
/// <summary>
|
/// 暴击飘字.
|
/// </summary>
|
public TextMoveDoTween bloodCrit;
|
|
/// <summary>
|
/// 减速飘字
|
/// </summary>
|
public Image SlowDownWord;
|
|
/// <summary>
|
/// 暴击飘字
|
/// </summary>
|
public Image CritWord;
|
|
/// <summary>
|
/// 冰冻飘字
|
/// </summary>
|
public Image FrostWord;
|
|
public Image RestrainWord;
|
|
/// <summary>
|
/// 购买塔防按钮上的Text.
|
/// </summary>
|
protected TextMeshProUGUI towerPriceText;
|
|
public bool tdBuyDisable { get; protected set; } = false;
|
|
/// <summary>
|
/// 鼠标在移动一个Tower之前,要隐藏的Tower数据和指针。
|
/// </summary>
|
protected Tower towerToMove = null;
|
|
/// <summary>
|
/// Fires when the <see cref="State"/> changes
|
/// should only allow firing when TouchUI is used
|
/// </summary>
|
public event Action<State, State> stateChanged;
|
|
/// <summary>
|
/// Fires off when the ghost was previously not valid but now is due to currency amount change
|
/// </summary>
|
public event Action ghostBecameValid;
|
|
/// <summary>
|
/// Fires when a tower is selected/deselected
|
/// </summary>
|
public event Action<Tower> selectionChanged;
|
|
/// <summary>
|
/// 成长骰子对应的Timer.
|
/// </summary>
|
protected List<Timer> listTowerTimer = new List<Timer>();
|
|
protected Dictionary<int, Tower> towerTimeDic = new Dictionary<int, Tower>();
|
|
/// <summary>
|
/// Placement area ghost tower is currently on
|
/// </summary>
|
IPlacementArea m_CurrentArea;
|
|
/// <summary>
|
/// Grid position ghost tower in on
|
/// </summary>
|
IntVector2 m_GridPosition;
|
|
/// <summary>
|
/// Our cached camera reference
|
/// </summary>
|
Camera m_Camera;
|
|
//Camera m_CameraBG;
|
|
|
/// <summary>
|
/// Current tower placeholder. Will be null if not in the <see cref="State.Building" /> state.
|
/// </summary>
|
TowerPlacementGhost m_CurrentTower;
|
|
public bool HasTower
|
{
|
get
|
{
|
return m_CurrentTower != null;
|
}
|
}
|
|
|
// TowerList用于简单记录相关的数据
|
protected List<Tower> m_listTower = new List<Tower>();
|
|
/// <summary>
|
/// Tracks if the ghost is in a valid location and the player can afford it
|
/// </summary>
|
bool m_GhostPlacementPossible;
|
|
/// <summary>
|
/// Gets the current selected tower
|
/// </summary>
|
public Tower currentSelectedTower { get; private set; }
|
|
/// <summary>
|
/// 拖动塔防时,原塔防的等级。
|
/// </summary>
|
protected int dragTowerLevel = 0;
|
|
/// <summary>
|
/// 选中Tower时候的鼠标点击坐标与Tower中心所在的屏幕坐标之间的偏移值.
|
/// </summary>
|
protected Vector2 selTowerOffset = new Vector2();
|
|
// 测试屏幕显示相关的倒计时.
|
protected bool bLoaded = false;
|
|
private Timer overTimer;
|
|
/// <summary>
|
/// 总兵线数
|
/// </summary>
|
public int TotalWaveLines { get; } = 5;
|
|
public IntVector2 currentGrid
|
{
|
get { return m_GridPosition; }
|
}
|
|
/// <summary>
|
/// Gets whether a tower has been selected
|
/// </summary>
|
public bool isTowerSelected
|
{
|
get { return currentSelectedTower != null; }
|
}
|
|
/// <summary>
|
/// 攻击塔位占的行数
|
/// </summary>
|
public int AttackRowNumbers { get; set; } = 2;
|
|
/// <summary>
|
/// 所有攻击塔位的摧毁信息,是否被摧毁,默认全部没有被摧毁
|
/// </summary>
|
private bool[,] TowerDestroyArr;
|
|
public event Action GameOverEvent;
|
|
/// <summary>
|
/// 塔升级特效预制体
|
/// </summary>
|
public GameObject TowerUpgradeEffectPrefab;
|
|
/// <summary>
|
/// 宝石出现特效预制体
|
/// </summary>
|
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;
|
/// <summary>
|
/// 保存所有生成或合成的塔的最小等级
|
/// </summary>
|
/// <value></value>
|
public int MinLevel;
|
|
public IPlacementArea selfTowerPlaceArea
|
{
|
get
|
{
|
if (m_CurrentArea == null)
|
{
|
GameObject placeObj = GameObject.FindGameObjectWithTag("PlaceTower");
|
if (placeObj != null)
|
m_CurrentArea = placeObj.GetComponent<IPlacementArea>();
|
}
|
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);
|
}
|
|
/// <summary>
|
/// 增加一个防塔的数据结构,测试数据
|
/// </summary>
|
/// <param name="t"></param>
|
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 void PlayBuffPS(int get_buffID)
|
{
|
//Debug.Log("开始播放特效");
|
int targetID = 0;
|
switch (get_buffID)
|
{
|
case 0:
|
//无特效
|
break;
|
case 1:
|
for (int i = 0; i < m_listTower.Count; i++)
|
{
|
m_listTower[i].CurrentTowerLevel.ShowBuffPS();
|
}
|
break;
|
case 2:
|
targetID = 101;
|
break;
|
case 3:
|
targetID = 201;
|
break;
|
case 4:
|
targetID = 301;
|
break;
|
}
|
if (targetID > 1)
|
{
|
for (int i = 0; i < m_listTower.Count; i++)
|
{
|
if (m_listTower[i].ElfId == targetID)
|
{
|
m_listTower[i].CurrentTowerLevel.ShowBuffPS();
|
}
|
}
|
}
|
|
}
|
|
/// <summary>
|
/// 根据塔位索引位置,查找位置上是否有对应的塔防数据。
|
/// </summary>
|
/// <param name="x"></param>
|
/// <param name="y"></param>
|
/// <returns></returns>
|
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;
|
}
|
|
/// <summary>
|
/// 根据塔位索引位置,查找位置上是否有对应的塔防数据。
|
/// </summary>
|
/// <param name="x"></param>
|
/// <param name="y"></param>
|
/// <returns></returns>
|
public int GetTowerNum()
|
{
|
int num = 0;
|
foreach (Tower lt in m_listTower)
|
{
|
if (lt.gridPosition.y == 0 || lt.gridPosition.y == 1)
|
{
|
num++;
|
}
|
}
|
return num;
|
}
|
|
public bool towerInList(Tower t)
|
{
|
return m_listTower.Contains(t);
|
}
|
|
/// <summary>
|
/// 设置已经上阵的所有塔的攻击状态,是否可以攻击
|
/// </summary>
|
/// <param name="canAttack"></param>
|
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();
|
}
|
|
/// <summary>
|
/// 清空缓存数据
|
/// </summary>
|
public void restartLevel()
|
{
|
m_listTower.Clear();
|
listTowerTimer.Clear();
|
towerTimeDic.Clear();
|
}
|
|
/// <summary>
|
/// 查找相同类型,相同段位的Tower
|
/// </summary>
|
/// <param name="t"></param>
|
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;
|
}
|
|
/// <summary>
|
/// Gets whether certain build operations are valid
|
/// </summary>
|
public bool isBuilding
|
{
|
get
|
{
|
return state == State.Building || state == State.BuildingWithDrag;
|
}
|
}
|
|
/// <summary>
|
/// Cancel placing the ghost
|
/// </summary>
|
public void CancelGhostPlacement()
|
{
|
if (m_CurrentTower)
|
Destroy(m_CurrentTower.gameObject);
|
m_CurrentTower = null;
|
SetState(State.Normal);
|
DeselectTower();
|
}
|
|
/// <summary>
|
/// Returns the GameUI to dragging mode with the curent tower
|
/// </summary>
|
/// /// <exception cref="InvalidOperationException">
|
/// Throws exception when not in build mode
|
/// </exception>
|
public void ChangeToDragMode()
|
{
|
if (!isBuilding)
|
{
|
throw new InvalidOperationException("Trying to return to Build With Dragging Mode when not in Build Mode");
|
}
|
SetState(State.BuildingWithDrag);
|
}
|
|
/// <summary>
|
/// Returns the GameUI to BuildMode with the current tower
|
/// </summary>
|
/// <exception cref="InvalidOperationException">
|
/// Throws exception when not in Drag mode
|
/// </exception>
|
public void ReturnToBuildMode()
|
{
|
if (!isBuilding)
|
{
|
throw new InvalidOperationException("Trying to return to Build Mode when not in Drag Mode");
|
}
|
SetState(State.Building);
|
}
|
|
/// <summary>
|
/// Changes the state and fires <see cref="stateChanged"/>
|
/// </summary>
|
/// <param name="newState">The state to change to</param>
|
/// <exception cref="ArgumentOutOfRangeException">thrown on an invalid state</exception>
|
void SetState(State newState)
|
{
|
if (state == newState)
|
{
|
return;
|
}
|
if (state == State.GameOver)
|
{
|
CommonDebugHelper.DebugError("已经游戏结束了,为什么还在修改状态");
|
return;
|
}
|
CommonDebugHelper.Debug($"设置了状态 state:{state} newState:{newState} ");
|
|
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);
|
}
|
}
|
|
/// <summary>
|
/// Called when the game is over
|
/// </summary>
|
public void GameOver()
|
{
|
CommonDebugHelper.Debug("游戏结束了");
|
|
SetState(State.GameOver);
|
}
|
|
/// <summary>
|
/// Pause the game and display the pause menu
|
/// </summary>
|
public void Pause()
|
{
|
SetState(State.Paused);
|
}
|
|
/// <summary>
|
/// Resume the game and close the pause menu
|
/// </summary>
|
public void Unpause()
|
{
|
SetState(State.Normal);
|
}
|
|
/// <summary>
|
/// Changes the mode to drag
|
/// </summary>
|
/// <param name="towerToBuild">
|
/// The tower to build
|
/// </param>
|
/// <exception cref="InvalidOperationException">
|
/// Throws exception when trying to change to Drag mode when not in Normal Mode
|
/// </exception>
|
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);
|
}
|
|
/// <summary>
|
/// 点击某一个塔防之后,开启拖动塔防的模式。
|
/// River: 修改为暂不删除原来的Tower,把原来的Tower隐藏掉.
|
/// </summary>
|
/// <param name="towerOld"></param>
|
public void startDragTower(Tower towerOld)
|
{
|
Tower newT = null;
|
foreach (Tower tower in EndlessLevelManager.instance.TowerLibrary)
|
{
|
if (tower.towerName != towerOld.towerName)
|
continue;
|
|
newT = tower;
|
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);
|
}
|
|
/// <summary>
|
/// Sets the UI into a build state for a given tower
|
/// River: 当界面上某一个塔防的按钮被按下后,需要调用的这个函数进入建造模式。
|
/// </summary>
|
/// <param name="towerToBuild">
|
/// The tower to build
|
/// </param>
|
/// <exception cref="InvalidOperationException">
|
/// Throws exception trying to enter Build Mode when not in Normal Mode
|
/// </exception>
|
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);
|
}
|
|
/// <summary>
|
/// 目标位置是否是可攻击属性的空塔位
|
/// </summary>
|
/// <param name="pinfo"></param>
|
/// <returns></returns>
|
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 as TowerPlacementGridEndless).isFreeAtackPos(m_GridPosition.x, m_GridPosition.y))
|
{
|
return true;
|
}
|
}
|
|
return false;
|
}
|
|
/// <summary>
|
/// 是否是可开启的AttackGrid塔位.
|
/// </summary>
|
/// <param name="pinfo"></param>
|
/// <returns></returns>
|
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;
|
}
|
|
/// <summary>
|
/// 目标位置是否有同等级同类型的Tower.
|
/// </summary>
|
/// <param name="pinfo"></param>
|
/// <returns></returns>
|
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 && sTower.IsStartBondage) return false;
|
|
if (sTower && sTower != towerToMove)
|
{
|
int testLvl = dragTowerLevel;
|
|
if (towerToMove && sTower.currentLevel == testLvl && sTower.towerName == towerToMove.towerName)
|
return true;
|
}
|
}
|
return false;
|
}
|
|
/// <summary>
|
/// 判断是否有不同类型的Tower,可以发生置换,仅限于火木水之间发生
|
/// </summary>
|
/// <param name="pinfo"></param>
|
/// <returns></returns>
|
protected bool IsSubstitute(PointerInfo pinfo)
|
{
|
if (!m_CurrentTower || !IsGhostAtValidPosition())
|
{
|
// 判断格子上的塔防:
|
UIPointer pointer = WrapPointer(pinfo);
|
Tower sTower = PickTowerInGrid(pointer);
|
|
// 泡泡禁锢状态不允许置换
|
if (sTower && sTower.IsStartBondage) return false;
|
|
if (sTower && sTower != towerToMove)
|
{
|
if (towerToMove)
|
return true;
|
}
|
}
|
|
return false;
|
}
|
|
/// <summary>
|
/// 判断是否有不同类型的Tower,可以发生置换,仅限于火木水之间发生
|
/// </summary>
|
/// <param name="pinfo"></param>
|
/// <returns></returns>
|
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;
|
}
|
|
/// <summary>
|
/// 获取目标格子上的塔防的名字数据
|
/// </summary>
|
/// <param name="pinfo"></param>
|
/// <returns></returns>
|
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 "";
|
}
|
|
/// <summary>
|
/// 提升所有塔的等级,如果现在塔的等级 < level,设置等级为 level,如果 > level 不做改变
|
/// </summary>
|
/// <param name="level">从0开始</param>
|
public void UpgradeAllTowerMinLevel(int level)
|
{
|
if (level < 0 || level > ElfUpgradeData.MaxTowerLevel - 1) return;
|
|
for (int i = 0; i < m_listTower.Count; ++i)
|
{
|
if (m_listTower[i].currentLevel < level)
|
{
|
m_listTower[i].currentLevel = level;
|
m_listTower[i].CurrentTowerLevel.SetShowLevel(level + 1);
|
m_listTower[i].CurrentTowerLevel.SetScale(level + 1);
|
PlayUpgradeEffect(m_listTower[i]);
|
}
|
}
|
GameConfig.IsUpgradeTowerLevel = true;
|
UpdateMinLevelArr();
|
EndlessRandomTower.instance.UpdateDescDisplay();
|
}
|
|
/// <summary>
|
/// 成长骰子升级为高一级别的随机骰子.
|
/// </summary>
|
/// <param name="tower"></param>
|
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);
|
}
|
|
/// <summary>
|
/// 破坏某一列的塔位数据
|
/// </summary>
|
/// <param name="yidx"></param>
|
/// <param name="opponent"></param>
|
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);
|
}
|
}
|
|
/// <summary>
|
/// 爱心数量为0,游戏结束
|
/// </summary>
|
private void AllHeartLose()
|
{
|
// 清理技能
|
EndlessBossSkillManager.instance.ClearSkillList();
|
EndlessBossHPManager.instance.SwitchHP(true);
|
EndlessBossHPManager.instance.SetCurrentHP(0);
|
EndlessLevelManager.instance.WaveManager.HideTunel();
|
|
// 停止所有兵线的出兵
|
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;//移动时候的虚像材质
|
|
/// <summary>
|
/// 查找可以合成的塔
|
/// </summary>
|
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<IntVector2> allTowerP = null;//排除不能合成的
|
// List<IntVector2> allPSTowerP = new List<IntVector2>();//需要播放升级动画的
|
|
if (towerToMove)
|
{
|
if (towerToMove.gridPosition.y == 0 || towerToMove.gridPosition.y == 1)
|
{
|
allTowerP = new List<IntVector2>();
|
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);
|
}
|
}
|
}
|
|
/// <summary>
|
/// 关闭所有标识
|
/// </summary>
|
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<IPlacementArea>() as TowerPlacementGridEndless).CloseCanPlaceRenderer();
|
}
|
}
|
|
Tower checkTowerPlaceTower;//移动时候查看鼠标是否检测到有塔
|
Tower bInAttackModeTower;//在合成区的塔
|
/// <summary>
|
/// 检查符合条件的塔
|
/// </summary>
|
/// <param name="pointerInfo"></param>
|
public void CheckTowerPlace(PointerInfo pointerInfo)
|
{
|
//return;
|
if (m_CurrentArea != null && m_CurrentArea is TowerPlacementGridEndless)
|
{
|
checkTowerPlaceTower = isFreeAttackGridOnDrag(pointerInfo);
|
|
//下面是为了设置一个虚拟的塔
|
if (checkTowerPlaceTower != null)
|
{
|
Debug.Log(checkTowerPlaceTower.name);
|
|
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);
|
}
|
}
|
}
|
|
|
m_CurrentTower.transform.position = (m_CurrentArea as TowerPlacementGridEndless).GridToWorld(checkTowerPlaceTower.gridPosition, m_CurrentTower.controller.dimensions);
|
|
}
|
}
|
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);
|
|
m_CurrentTower.transform.position = (m_CurrentArea as TowerPlacementGridEndless).GridToWorld(m_GridPosition, m_CurrentTower.controller.dimensions);
|
|
}
|
}
|
else
|
{
|
CloseCanPlace();
|
}
|
}
|
else
|
{
|
CloseCanPlace();
|
}
|
}
|
else
|
{
|
if (m_CurrentTower.controller.towerFeature == EFeatureTower.NULL)
|
{
|
dragTowerPlacement.CloseCanPlace();
|
}
|
}
|
}
|
|
public void CloseCanPlace()
|
{
|
dragTowerPlacement.CloseCanPlace();
|
if (bInAttackModeTower != null)
|
{
|
bInAttackModeTower.CurrentTowerLevel.SetCanPlace(false);
|
bInAttackModeTower = null;
|
}
|
}
|
|
TowerPlacementGridEndless dragTowerPlacement;
|
|
public void CheckTowerPlaceNew(PointerInfo pointerInfo)
|
{
|
//return;
|
if (m_CurrentArea != null && m_CurrentArea is TowerPlacementGridEndless)
|
{
|
if ((m_GridPosition.x >= 0) && (m_GridPosition.y >= 0))
|
{
|
if (m_GridPosition.y == 0 || m_GridPosition.y == 1)
|
{
|
//Debug.Log("未上阵区域,不管有没有塔,都强行吸附");
|
(m_CurrentArea as TowerPlacementGridEndless).CheckCanPlaceUpdate(m_GridPosition.x, m_GridPosition.y, true, "");
|
|
m_CurrentTower.SetGridPosition(m_GridPosition.x, m_GridPosition.y);
|
|
//m_CurrentTower.transform.position = (m_CurrentArea as TowerPlacementGridEndless).GridToWorld(m_GridPosition, m_CurrentTower.controller.dimensions);
|
|
}
|
else if (m_GridPosition.y == 2 || m_GridPosition.y == 3)
|
{
|
//Debug.Log("已上阵区域,如果是空格子就强行吸附,先判断是否有塔");
|
//pointerInfo.currentPosition += new Vector2(0, -25f);
|
checkTowerPlaceTower = isFreeAttackGridOnDrag(pointerInfo);
|
|
if (checkTowerPlaceTower != null)
|
{
|
//Debug.Log(checkTowerPlaceTower.name);
|
//Debug.Log($"checkTowerPlaceTower.name:{checkTowerPlaceTower.name} m_GridPosition:{m_GridPosition}");
|
|
if (m_CurrentTower.controller.towerFeature == EFeatureTower.NULL)
|
{
|
if (checkTowerPlaceTower.bInAttackMode)
|
{
|
//Debug.Log("检测到了塔");
|
//鼠标检测到了塔
|
(m_CurrentArea as TowerPlacementGridEndless).CheckCanPlaceUpdate(checkTowerPlaceTower.gridPosition.x, checkTowerPlaceTower.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);
|
}
|
}
|
}
|
m_CurrentTower.SetGridPosition(checkTowerPlaceTower.gridPosition.x, checkTowerPlaceTower.gridPosition.y);
|
|
//Debug.Log("未上阵区域,不管有没有塔,都强行吸附" + checkTowerPlaceTower.gridPosition);
|
|
//m_CurrentTower.transform.position = (m_CurrentArea as TowerPlacementGridEndless).GridToWorld(checkTowerPlaceTower.gridPosition, m_CurrentTower.controller.dimensions);
|
}
|
}
|
else if ((m_CurrentArea as TowerPlacementGridEndless).isFreeAtackPos(m_GridPosition.x, m_GridPosition.y))
|
{
|
//Debug.Log("空格子");
|
|
(m_CurrentArea as TowerPlacementGridEndless).CheckCanPlaceUpdate(m_GridPosition.x, m_GridPosition.y, true, towerToMove.towerName);
|
|
m_CurrentTower.SetGridPosition(m_GridPosition.x, m_GridPosition.y);
|
|
//m_CurrentTower.transform.position = (m_CurrentArea as TowerPlacementGridEndless).GridToWorld(m_GridPosition, m_CurrentTower.controller.dimensions);
|
|
}
|
else
|
{
|
|
//Debug.Log($"上阵区域 m_GridPosition:{m_GridPosition.x} {m_GridPosition.y} m_CurrentTower.controller.gridPosition:{m_CurrentTower.controller.gridPosition.x} {m_CurrentTower.controller.gridPosition.y}");
|
|
if (m_GridPosition == towerToMove.gridPosition)
|
{
|
//Debug.Log("在原来的地方");
|
|
(m_CurrentArea as TowerPlacementGridEndless).CheckCanPlaceUpdate(m_GridPosition.x, m_GridPosition.y, true, towerToMove.towerName);
|
|
//m_CurrentTower.transform.position = towerToMove.position;
|
m_CurrentTower.SetGridPosition(m_GridPosition.x, m_GridPosition.y);
|
|
}
|
else
|
{
|
//CloseCanPlace();
|
|
//Debug.Log("上阵区域,没有开放的塔位");
|
|
(m_CurrentArea as TowerPlacementGridEndless).CheckCanPlaceUpdate(m_GridPosition.x, m_GridPosition.y, true, "");
|
|
m_CurrentTower.SetGridPosition(m_GridPosition.x, m_GridPosition.y);
|
|
//m_CurrentTower.transform.position = (m_CurrentArea as TowerPlacementGridEndless).GridToWorld(m_GridPosition, m_CurrentTower.controller.dimensions);
|
}
|
}
|
}
|
}
|
|
}
|
else
|
{
|
dragTowerPlacement.CloseCanPlace();
|
m_CurrentTower.SetGridPosition(-1, -1);
|
//Debug.Log("没有检测到");
|
}
|
}
|
|
|
/// <summary>
|
/// 目标位置是否是可攻击属性的空塔位
|
/// </summary>
|
/// <param name="pinfo"></param>
|
/// <returns></returns>
|
protected Tower isFreeAttackGridOnDrag(PointerInfo pinfo)
|
{
|
// 判断格子上的塔防:
|
UIPointer pointer = WrapPointer(pinfo);
|
Tower sTower = PickTowerInGrid(pointer);
|
if (sTower != null)
|
{
|
if (towerToMove)
|
{
|
return sTower;
|
// if (towerToMove.bInAttackMode)
|
// {
|
// }
|
// else
|
// {
|
// if (sTower.currentLevel == dragTowerLevel && sTower.towerName == towerToMove.towerName)
|
// {
|
// //说明可以合成
|
// return sTower;
|
// }
|
// }
|
}
|
else
|
{
|
return null;
|
}
|
}
|
return null;
|
}
|
|
#endregion
|
|
/// <summary>
|
/// 推拽结束,如果判断HasTower==true 就强行释放
|
/// </summary>
|
public void EndDragCancelPlaceTower()
|
{
|
Debug.Log("强行释放了m_CurrentTower");
|
CancelPlaceTower(null);
|
}
|
|
/// <summary>
|
/// 拖动一个Tower之后,松开鼠标或者EndDrag.
|
/// 1: 目标点可合成,则直接合成。
|
/// 2: 目标点不管是空白,还是不能放置Tower,都要让当前的Tower返回到原来的TowerPlace
|
/// </summary>
|
/// <param name="pointerInfo"></param>
|
public void onEndTowerDrag(PointerInfo pointerInfo)
|
{
|
if (temporaryMat != null)
|
{
|
//移动虚像隐藏
|
temporaryMat.material = null;
|
}
|
|
if (!m_CurrentTower || !m_CurrentTower.controller)
|
{
|
CancelPlaceTower(pointerInfo);
|
return;
|
}
|
|
if (m_CurrentTower.controller.towerFeature != EFeatureTower.NULL)
|
{
|
Debug.LogError("只能移动3种塔");
|
return;
|
}
|
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;
|
}
|
|
if (m_CurrentTower.gridPositionX != -1)
|
{
|
IntVector2 moveV2 = new IntVector2(m_CurrentTower.gridPositionX, m_CurrentTower.gridPositionY);
|
//判断是否未开塔
|
if (!dragTowerPlacement.IsGridOpen(moveV2.x, moveV2.y))
|
{
|
//Debug.Log("未开塔");
|
CancelPlaceTower(pointerInfo);
|
|
}
|
else if (moveV2 == towerToMove.gridPosition)
|
{
|
//Debug.Log($"在原位 moveV2:{moveV2} towerToMove.gridPosition:{towerToMove.gridPosition}");
|
CancelPlaceTower(pointerInfo);
|
}
|
else
|
{
|
//判断是否有塔
|
Tower tmpT = null;
|
for (int i = 0; i < m_listTower.Count; i++)
|
{
|
if (m_listTower[i].gridPosition == moveV2)
|
{
|
tmpT = m_listTower[i];
|
break;
|
}
|
}
|
|
if (tmpT != null)
|
{
|
//Debug.Log("释放的时候有塔");
|
DragBuyTower(tmpT);
|
}
|
else
|
{
|
//Debug.Log("释放的时候是空格子");
|
DragBuyTower(moveV2);
|
}
|
}
|
}
|
else
|
{
|
//Debug.Log("不在区域内");
|
CancelPlaceTower(pointerInfo);
|
}
|
|
return;
|
|
// 判断目标位置是否有Tower且类型和等级一致,如果没有,则GhostTower删除,原Tower显示。
|
if (isValidateCombineTarget(pointerInfo))
|
{
|
//Debug.Log("目标位置是否有同等级同类型的Tower.");
|
TryPlaceTower(pointerInfo);
|
EndlessRandomTower.instance.UpdateDescDisplay();
|
}
|
else if (isFreeAttackGrid(pointerInfo))
|
{
|
//Debug.Log("isFreeAttackGrid:" + m_GridPosition);
|
|
if (!TryPlaceTower(pointerInfo, false))
|
{
|
CancelPlaceTower(pointerInfo);
|
Debug.Log("这里需要返回原位");
|
return;
|
}
|
|
// 删除towerToMove,确保塔防数据不再出现多个
|
if (towerToMove != null)
|
{
|
delTower(towerToMove);
|
towerToMove.showTower(true);
|
towerToMove.Sell();
|
towerToMove = null;
|
}
|
if (m_CurrentTower != null && m_CurrentTower.controller != null)
|
Destroy(m_CurrentTower.controller.gameObject);
|
}
|
else if (EndlessLevelManager.instanceExists && IsSubstitute(pointerInfo))
|
{
|
//Debug.Log("交换");
|
|
CheckCanChangePos(pointerInfo);
|
}
|
else
|
CancelPlaceTower(pointerInfo);
|
}
|
|
private bool CheckCanChangePos(PointerInfo pointerInfo)
|
{
|
// 可以发生置换
|
UIPointer pointer = WrapPointer(pointerInfo);
|
// 格子上的塔
|
Tower sTower = PickTowerInGrid(pointer);
|
if (sTower == null)
|
return false;
|
|
//Debug.Log("开始检测是否可以交换塔");
|
//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();
|
//Debug.Log($"newTower1:{newTower1.towerName} newTower2:{newTower2.towerName}");
|
|
TowerPlacementGridEndless.instance.PlayPutPs(newTower2.gridPosition.x, newTower2.gridPosition.y);
|
return true;
|
}
|
}
|
return false;
|
|
}
|
|
|
/// <summary>
|
/// 强制放置塔,主要是用于新手
|
/// </summary>
|
/// <param name="newTower"></param>
|
/// <param name="pos"></param>
|
/// <param name="level">塔的等级</param>
|
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<WaveLineSelEffect>();
|
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);
|
}
|
|
/// <summary>
|
/// 处理复制宝石塔防
|
/// </summary>
|
/// <param name="pointerInfo"></param>
|
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);
|
}
|
}
|
|
/// <summary>
|
/// Attempt to position a tower at the given location
|
/// </summary>
|
/// <param name="pointerInfo">The pointer we're using to position the tower</param>
|
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);
|
}
|
|
/// <summary>
|
/// 根据鼠标的点击信息来确认当前点击的位置是否有塔防模型。
|
/// </summary>
|
/// <param name="pointer"></param>
|
/// <returns></returns>
|
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<Tower>();
|
|
return controller;
|
}
|
|
private Vector2 dragOffect = new Vector2(0, -55f);
|
/// <summary>
|
/// Position the ghost tower at the given pointer
|
/// </summary>
|
/// <param name="pointerInfo">The pointer we're using to position the tower</param>
|
/// <param name="hideWhenInvalid">Optional parameter for configuring if the ghost is hidden when in an invalid location</param>
|
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");
|
}
|
// 我操,终于可以了!ATTENTION TO OPP:
|
PointerInfo tp = new PointerActionInfo();
|
tp.currentPosition = pointerInfo.currentPosition + dragOffect;
|
tp.previousPosition = pointerInfo.previousPosition;
|
tp.delta = pointerInfo.delta;
|
tp.startedOverUI = pointerInfo.startedOverUI;
|
|
UIPointer npt = new UIPointer
|
{
|
overUI = false,
|
pointer = tp,
|
overWaveLine = false,
|
ray = m_Camera.ScreenPointToRay(tp.currentPosition)
|
};
|
|
//UIPointer pointer = WrapPointer(tp);
|
// Do nothing if we're over UI
|
if (npt.overUI && hideWhenInvalid)
|
{
|
m_CurrentTower.Hide();
|
return;
|
}
|
MoveGhost(npt, hideWhenInvalid);
|
}
|
|
/// <summary>
|
/// Activates the tower controller UI with the specific information
|
/// </summary>
|
/// <param name="tower">
|
/// The tower controller information to use
|
/// </param>
|
/// <exception cref="InvalidOperationException">
|
/// Throws exception when selecting tower when <see cref="State" /> does not equal <see cref="State.Normal" />
|
/// </exception>
|
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);
|
}
|
|
/// <summary>
|
/// 在当前的PlaceArea内删除有相同LvL相同类型的防塔.
|
/// </summary>
|
/// <param name="tower"></param>
|
public bool deleteSameLvlTower(Tower tower)
|
{
|
Tower delTower = findSameLvlTower(tower);
|
if (delTower == null) return false;
|
Tower backT = currentSelectedTower;
|
currentSelectedTower = delTower;
|
SellSelectedTower();
|
currentSelectedTower = backT;
|
return true;
|
}
|
|
/// <summary>
|
/// Upgrades <see cref="currentSelectedTower" />, if possible
|
/// </summary>
|
/// <exception cref="InvalidOperationException">
|
/// Throws exception when selecting tower when <see cref="State" /> does not equal <see cref="State.Normal" />
|
/// or <see cref="currentSelectedTower" /> is null
|
/// </exception>
|
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();
|
}
|
|
/// <summary>
|
/// 当前的塔防随机升级为另一种塔防的种类。
|
/// </summary>
|
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;
|
}
|
|
/// <summary>
|
/// Sells <see cref="currentSelectedTower" /> if possible
|
/// </summary>
|
/// <exception cref="InvalidOperationException">
|
/// Throws exception when selecting tower when <see cref="State" /> does not equal <see cref="State.Normal" />
|
/// or <see cref="currentSelectedTower" /> is null
|
/// </exception>
|
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();
|
}
|
|
/// <summary>
|
/// Buys the tower and places it in the place that it currently is
|
/// </summary>
|
/// <exception cref="InvalidOperationException">
|
/// Throws exception if trying to buy towers in Build Mode
|
/// </exception>
|
public void BuyTower()
|
{
|
if (!isBuilding)
|
{
|
throw new InvalidOperationException("Trying to buy towers when not in Build Mode");
|
}
|
if (m_CurrentTower == null || !IsGhostAtValidPosition())
|
{
|
return;
|
}
|
PlaceTower();
|
}
|
|
/// <summary>
|
/// Used to buy the tower during the build phase
|
/// Checks currency and calls <see cref="PlaceGhost" />
|
/// <exception cref="InvalidOperationException">
|
/// Throws exception when not in a build mode or when tower is not a valid position
|
/// </exception>
|
/// </summary>
|
public bool BuyTower(UIPointer pointer, bool force = false)
|
{
|
if (!isBuilding) return false;
|
|
//Debug.Log("开始造塔" + m_GridPosition);
|
// 判断是否格子上重复放置塔防
|
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;
|
}
|
|
private void DragBuyTower(Tower 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
|
{
|
IntVector2 v1 = new IntVector2(towerToMove.gridPosition.x, towerToMove.gridPosition.y);
|
IntVector2 v2 = new IntVector2(sTower.gridPosition.x, sTower.gridPosition.y);
|
|
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();
|
//Debug.Log($"newTower1:{newTower1.towerName} newTower2:{newTower2.towerName}");
|
|
TowerPlacementGridEndless.instance.PlayPutPs(newTower2.gridPosition.x, newTower2.gridPosition.y);
|
}
|
}
|
|
private void DragBuyTower(IntVector2 dragGridPosition)
|
{
|
Tower controller = m_CurrentTower.controller;
|
Tower createdTower = Instantiate(controller);
|
createdTower.Initialize(m_CurrentArea, dragGridPosition, dragTowerLevel);
|
|
// ATTENTION TO FIX:是否应该加入List:
|
addTower(createdTower);
|
PlayToAttackEffect(createdTower.ElfId, createdTower.transform.position);
|
dragTowerLevel = 0;
|
CancelGhostPlacement();
|
|
// 删除towerToMove,确保塔防数据不再出现多个
|
if (towerToMove != null)
|
{
|
delTower(towerToMove);
|
towerToMove.showTower(true);
|
towerToMove.Sell();
|
towerToMove = null;
|
}
|
if (m_CurrentTower != null && m_CurrentTower.controller != null)
|
Destroy(m_CurrentTower.controller.gameObject);
|
}
|
|
/// <summary>
|
/// 播放升级特效
|
/// </summary>
|
/// <param name="worldPos"></param>
|
public void PlayUpgradeEffect(Tower newTower)
|
{
|
newTower.CurrentTowerLevel.PlayUpGradeEffect();
|
AudioSourceManager.Ins.Play(AudioEnum.Upgrade);
|
}
|
|
/// <summary>
|
/// Deselect the current tower and hides the UI
|
/// </summary>
|
public void DeselectTower()
|
{
|
if (currentSelectedTower != null)
|
{
|
currentSelectedTower.removed -= OnTowerDied;
|
}
|
|
currentSelectedTower = null;
|
|
if (selectionChanged != null)
|
{
|
selectionChanged(null);
|
}
|
}
|
|
/// <summary>
|
/// Checks the position of the <see cref="m_CurrentTower"/>
|
/// on the <see cref="m_CurrentArea"/>
|
/// </summary>
|
/// <returns>
|
/// True if the placement is valid
|
/// </returns>
|
/// <exception cref="InvalidOperationException">
|
/// Throws exception if the check is done in <see cref="State.Normal"/> state
|
/// </exception>
|
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;
|
}
|
|
/// <summary>
|
/// Checks if buying the ghost tower is possible
|
/// </summary>
|
/// <returns>
|
/// True if can purchase
|
/// </returns>
|
/// <exception cref="InvalidOperationException">
|
/// Throws exception if not in Build Mode or Build With Dragging mode
|
/// </exception>
|
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;
|
}
|
|
/// <summary>
|
/// Places a tower where the ghost tower is
|
/// </summary>
|
/// <exception cref="InvalidOperationException">
|
/// Throws exception if not in Build State or <see cref="m_CurrentTower"/> is not at a valid position
|
/// </exception>
|
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);
|
}
|
}
|
|
/// <summary>
|
/// 播放首次宝石出现特效
|
/// </summary>
|
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<ParticleSystem>();
|
|
if (ps == null)
|
ps = obj.transform.GetChild(0).GetComponent<ParticleSystem>();
|
|
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<ParticleSystem>();
|
|
if (ps == null)
|
ps = obj.transform.GetChild(0).GetComponent<ParticleSystem>();
|
|
ps.Play();
|
|
Destroy(obj, ps.main.duration);
|
}
|
|
/// <summary>
|
/// 播放宝石出现特效
|
/// </summary>
|
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<ParticleSystem>();
|
|
if (ps == null)
|
ps = obj.transform.GetChild(0).GetComponent<ParticleSystem>();
|
|
ps.Play();
|
Destroy(obj, ps.main.duration);
|
}
|
|
|
/// <summary>
|
/// 播放升级特效
|
/// </summary>
|
/// <param name="worldPos"></param>
|
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<ParticleSystem>();
|
|
if (ps == null)
|
ps = obj.transform.GetChild(0).GetComponent<ParticleSystem>();
|
|
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;
|
}
|
|
/// <summary>
|
/// 成功购买塔防后,更新价格,更新按钮,更新按钮上的塔防价格等等.
|
/// </summary>
|
protected void OnSuccessBuyTower()
|
{
|
var tpMgr = TowerPrice.instance;
|
if (!tpMgr) return;
|
|
// 价格更新
|
tpMgr.onTowerBuySuccess();
|
|
if (!towerPriceText)
|
{
|
towerPriceText = randomTowerBtn.transform.Find("cashText").GetComponent<TextMeshProUGUI>();
|
//towerPriceText1 = SkillTowerBtn.transform.Find("cashText").GetComponent<TextMeshProUGUI>();
|
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();
|
}
|
}
|
|
/// <summary>
|
/// 随机放置Tower按钮禁止使用,灰掉.
|
/// </summary>
|
public void disableRandomTowerBtn()
|
{
|
randomTowerBtn.GetComponent<EndlessRandomTower>().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;
|
}
|
|
/// <summary>
|
/// 随机购买Tower的按钮重设置为有效.
|
/// </summary>
|
public 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<EndlessRandomTower>().ChangeBtnClickNormal();
|
//randomTowerBtn.interactable = true;
|
}
|
tdBuyDisable = false;
|
}
|
|
/// <summary>
|
/// 游戏内向上飘血
|
/// </summary>
|
/// <param name="x"></param>
|
/// <param name="y"></param>
|
/// <param name="val"></param>
|
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<TextMoveDoTween>(bloodCrit.gameObject);
|
}
|
else if (poison)
|
{
|
tm = Poolable.TryGetPoolable<TextMoveDoTween>(bloodPoison.gameObject);
|
}
|
else
|
{
|
tm = Poolable.TryGetPoolable<TextMoveDoTween>(bloodText.gameObject);
|
}
|
if (tm)
|
{
|
tm.GetComponent<Transform>().SetParent(GameObject.Find("MainUI/TextPanel").GetComponent<Transform>(), true);
|
string bloodStr = "-";
|
bloodStr += ((Int64)val).ToString();
|
|
tm.moveBloodText(spos.x, spos.y, bloodStr, crit);
|
}
|
}
|
|
/// <summary>
|
/// 减速飘字
|
/// </summary>
|
public void FloatSlowDownWord(Vector3 worldPos)
|
{
|
Vector3 screenPos = m_Camera.WorldToScreenPoint(worldPos);
|
GameObject obj = Instantiate(SlowDownWord.gameObject);
|
obj.GetComponent<Transform>().SetParent(GameObject.Find("MainUI/TextPanel").GetComponent<Transform>(), false);
|
obj.GetComponent<TextMoveDoTween>().FloatSlowDownWord(screenPos.x, screenPos.y);
|
}
|
|
/// <summary>
|
/// 暴击飘字
|
/// </summary>
|
public void FloatCritWord(Vector3 worldPos)
|
{
|
Vector3 screenPos = m_Camera.WorldToScreenPoint(worldPos);
|
GameObject obj = Instantiate(CritWord.gameObject);
|
obj.GetComponent<Transform>().SetParent(GameObject.Find("MainUI/TextPanel").GetComponent<Transform>(), false);
|
obj.GetComponent<TextMoveDoTween>().FloatCritWord(screenPos.x, screenPos.y);
|
}
|
|
/// <summary>
|
/// 冰冻飘字
|
/// </summary>
|
/// <param name="worldPos"></param>
|
public void FloatFrostWord(Vector3 worldPos)
|
{
|
Vector3 screenPos = m_Camera.WorldToScreenPoint(worldPos);
|
GameObject obj = Instantiate(FrostWord.gameObject);
|
obj.GetComponent<Transform>().SetParent(GameObject.Find("MainUI/TextPanel").GetComponent<Transform>(), false);
|
obj.GetComponent<TextMoveDoTween>().FloatFrostWord(screenPos.x, screenPos.y);
|
}
|
|
/// <summary>
|
/// 克制飘字
|
/// </summary>
|
/// <param name="worldPos"></param>
|
public void FloatRestrainWord(Vector3 worldPos)
|
{
|
Vector3 screenPos = m_Camera.WorldToScreenPoint(worldPos);
|
GameObject obj = Instantiate(RestrainWord.gameObject);
|
obj.GetComponent<Transform>().SetParent(GameObject.Find("MainUI/TextPanel").GetComponent<Transform>(), false);
|
obj.GetComponent<TextMoveDoTween>().FloatRestrainWord(screenPos.x, screenPos.y);
|
}
|
|
private void Start()
|
{
|
// 获取相应的放置区域。
|
GameObject placeObj = GameObject.FindGameObjectWithTag("PlaceTower");
|
if (placeObj != null)
|
{
|
m_CurrentArea = placeObj.GetComponent<IPlacementArea>();
|
dragTowerPlacement = placeObj.GetComponent<IPlacementArea>() as TowerPlacementGridEndless;
|
}
|
//placeObj = GameObject.FindGameObjectWithTag("PlaceTowerOpponent");
|
EventCenter.Ins.Add((int)KTGMGemClient.EventType.EndlessHeartAllLose, AllHeartLose);
|
EventCenter.Ins.Add<int>((int)KTGMGemClient.EventType.PlayBuffPS, PlayBuffPS);
|
|
}
|
|
/// <summary>
|
/// 替换towerToMove的目标Tower,如果是使用towerToMove,则必须提前处理相应的指针。
|
/// </summary>
|
/// <param name="tow"></param>
|
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);
|
}
|
|
/// <summary>
|
/// 直接在IPlaceArea上随机放置一个Tower。这是随机放置塔防的入口类。这是入口的塔防类。
|
/// </summary>
|
/// <param name="tow"></param>
|
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<IPlacementArea>();
|
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;
|
|
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;
|
}
|
|
/// <summary>
|
/// Calculates whether the given pointer is over the current tower ghost
|
/// </summary>
|
/// <param name="pointerInfo">
|
/// The information used to check against the <see cref="m_CurrentTower"/>
|
/// </param>
|
/// <exception cref="InvalidOperationException">
|
/// Throws an exception if not in Build Mode
|
/// </exception>
|
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);
|
}
|
|
/// <summary>
|
/// Selects a tower beneath the given pointer if there is one
|
/// 选择塔防
|
/// </summary>
|
/// <param name="info">
|
/// The pointer information concerning the selector of the pointer
|
/// </param>
|
/// <exception cref="InvalidOperationException">
|
/// Throws an exception when not in <see cref="State.Normal"/>
|
/// </exception>
|
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;
|
}
|
Tower controller = output.collider.GetComponent<Tower>();
|
if (controller != null)
|
{
|
// 泡泡禁锢状态不允许拖动
|
if (controller.IsStartBondage) 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<Tower>();
|
if (controller != null)
|
controller.OnPressed();
|
}
|
}
|
|
/// <summary>
|
/// 鼠标选中一个Tower的时候,计算当前鼠标位置与当前Tower位置在屏幕上坐标位置的偏移量。
|
/// </summary>
|
/// <param name="info"></param>
|
/// <param name="tower"></param>
|
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;
|
}
|
|
/// <summary>
|
/// Gets the world position of the ghost tower
|
/// </summary>
|
/// <exception cref="InvalidOperationException">
|
/// Throws an exception when not in the Build Mode or
|
/// When a ghost tower does not exist
|
/// </exception>
|
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;
|
}
|
|
/// <summary>
|
/// Moves the ghost to the center of the screen
|
/// </summary>
|
/// <exception cref="InvalidOperationException">
|
/// Throws exception when not in build mode
|
/// </exception>
|
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);
|
}
|
}
|
|
/// <summary>
|
/// Set initial values, cache attached components
|
/// and configure the controls
|
/// </summary>
|
protected override void Awake()
|
{
|
base.Awake();
|
|
randomTowerBtn = transform.Find("BottomCanvas/Panel/TowerBuyBtn").GetComponent<Button>();
|
//DOTween.Init(true, true, LogBehaviour.Verbose).SetCapacity(200, 10);
|
|
state = State.Normal;
|
m_Camera = GameObject.Find("SceneCamera3D").GetComponent<Camera>();
|
//m_Camera = GameObject.Find("BackCamera").GetComponent<Camera>();
|
|
//m_Camera = GetComponent<Camera>();
|
TowerDestroyArr = new bool[5, AttackRowNumbers];
|
}
|
|
/// <summary>
|
/// Reset TimeScale if game is paused
|
/// </summary>
|
protected override void OnDestroy()
|
{
|
base.OnDestroy();
|
Time.timeScale = 1f;
|
}
|
|
/// <summary>
|
/// Subscribe to the level manager
|
/// </summary>
|
protected virtual void OnEnable()
|
{
|
if (EndlessLevelManager.instanceExists)
|
EndlessLevelManager.instance.Currency.currencyChanged += OnCurrencyChanged;
|
}
|
|
/// <summary>
|
/// Unsubscribe from the level manager
|
/// </summary>
|
protected virtual void OnDisable()
|
{
|
if (EndlessLevelManager.instanceExists)
|
EndlessLevelManager.instance.Currency.currencyChanged -= OnCurrencyChanged;
|
}
|
|
/// <summary>
|
/// Creates a new UIPointer holding data object for the given pointer position
|
/// </summary>
|
protected UIPointer WrapPointer(PointerInfo pointerInfo)
|
{
|
return new UIPointer
|
{
|
overUI = IsOverUI(pointerInfo),
|
pointer = pointerInfo,
|
overWaveLine = false,
|
ray = m_Camera.ScreenPointToRay(pointerInfo.currentPosition)
|
};
|
}
|
|
/// <summary>
|
/// Checks whether a given pointer is over any UI
|
/// </summary>
|
/// <param name="pointerInfo">The pointer to test</param>
|
/// <returns>True if the event system reports pointer being over UI</returns>
|
protected bool IsOverUI(PointerInfo pointerInfo)
|
{
|
int pointerId;
|
EventSystem currentEventSystem = EventSystem.current;
|
|
// Pointer id is negative for mouse, positive for touch
|
var cursorInfo = pointerInfo as MouseCursorInfo;
|
var mbInfo = pointerInfo as MouseButtonInfo;
|
var touchInfo = pointerInfo as TouchInfo;
|
|
if (cursorInfo != null)
|
{
|
pointerId = PointerInputModule.kMouseLeftId;
|
}
|
else if (mbInfo != null)
|
{
|
// LMB is 0, but kMouseLeftID = -1;
|
pointerId = -mbInfo.mouseButtonId - 1;
|
}
|
else if (touchInfo != null)
|
{
|
pointerId = touchInfo.touchId;
|
}
|
else
|
{
|
throw new ArgumentException("Passed pointerInfo is not a TouchInfo or MouseCursorInfo", "pointerInfo");
|
}
|
|
return currentEventSystem.IsPointerOverGameObject(pointerId);
|
}
|
|
WaveLineSelEffect currentEffect;
|
/// <summary>
|
/// Move the ghost to the pointer's position
|
/// </summary>
|
/// <param name="pointer">The pointer to place the ghost at</param>
|
/// <param name="hideWhenInvalid">Optional parameter for whether the ghost should be hidden or not</param>
|
/// <exception cref="InvalidOperationException">If we're not in the correct state</exception>
|
protected void MoveGhost(UIPointer pointer, bool hideWhenInvalid = true)
|
{
|
// 我操,终于可以了!ATTENTION TO OPP:
|
PointerInfo tp = new PointerActionInfo();
|
tp.currentPosition = pointer.pointer.currentPosition;
|
tp.previousPosition = pointer.pointer.previousPosition;
|
tp.delta = pointer.pointer.delta;
|
tp.startedOverUI = pointer.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)
|
};
|
|
|
m_GridPosition.x = -1;
|
m_GridPosition.y = -1;
|
|
//
|
// WORK START: 从这里开始,移动的时候与场景内的WaveSelEffect射线做碰撞。
|
// Raycast onto placement layer
|
PlacementAreaRaycast(ref npt);
|
//Debug.Log("npt.raycast:" + npt.raycast);
|
if (npt.raycast != null)
|
{
|
MoveGhostWithRaycastHit(npt.raycast.Value);
|
}
|
else
|
{
|
MoveGhostOntoWorld(npt.ray, hideWhenInvalid);
|
|
return;
|
// 根据技能塔的类型,来碰撞不同的数据:
|
// 火是列攻击:
|
if (m_CurrentTower.controller.towerFeature == EFeatureTower.Skill_Fire)
|
{
|
WavelineAreaRaycast(ref npt);
|
if (npt.overWaveLine)
|
{
|
WaveLineSelEffect selEff = npt.wavelineHit.Value.collider.GetComponent<WaveLineSelEffect>();
|
if (selEff != currentEffect)
|
{
|
if (currentEffect != null)
|
{
|
currentEffect.SetParticleSystem(false);
|
}
|
currentEffect = selEff;
|
currentEffect.SetParticleSystem(true);
|
}
|
//selEff.SetWaveLineSel(true);
|
}
|
else
|
{
|
if (currentEffect != null)
|
{
|
currentEffect.SetParticleSystem(false);
|
currentEffect = null;
|
}
|
}
|
}
|
// 炸弹是区域攻击显示:
|
else if (m_CurrentTower.controller.towerFeature == EFeatureTower.Skill_Bomb)
|
{
|
// 测试代码与战场区域碰撞,碰撞后显示攻击区域:
|
BattleAreaRaycast(ref npt);
|
if (npt.overWaveLine)
|
m_CurrentTower.fadeOutAttackArea();
|
}
|
|
}
|
}
|
|
/// <summary>
|
/// Move ghost with successful raycastHit onto m_PlacementAreaMask
|
/// </summary>
|
protected virtual void MoveGhostWithRaycastHit(RaycastHit raycast)
|
{
|
// We successfully hit one of our placement areas
|
// Try and get a placement area on the object we hit
|
m_CurrentArea = raycast.collider.GetComponent<IPlacementArea>();
|
if (m_CurrentArea == null)
|
{
|
Debug.LogError("There is not an IPlacementArea attached to the collider found on the m_PlacementAreaMask");
|
return;
|
}
|
m_GridPosition = m_CurrentArea.WorldToGrid(raycast.point, m_CurrentTower.controller.dimensions);
|
//Debug.Log("修改了m_GridPosition:" + m_GridPosition);
|
TowerFitStatus fits = m_CurrentArea.Fits(m_GridPosition, m_CurrentTower.controller.dimensions);
|
|
m_CurrentTower.Show();
|
m_GhostPlacementPossible = fits == TowerFitStatus.Fits && IsValidPurchase();
|
m_CurrentTower.Move(raycast.point,
|
//m_CurrentArea.GridToWorld(m_GridPosition, m_CurrentTower.controller.dimensions),
|
m_CurrentArea.transform.rotation,
|
m_GhostPlacementPossible);
|
}
|
|
/// <summary>
|
/// Move ghost with the given ray
|
/// </summary>
|
protected virtual void MoveGhostOntoWorld(Ray ray, bool hideWhenInvalid)
|
{
|
m_CurrentArea = null;
|
|
if (!hideWhenInvalid)
|
{
|
RaycastHit hit;
|
|
Physics.Raycast(ray, out hit, float.MaxValue);
|
// check against all layers that the ghost can be on
|
//Physics.SphereCast(ray, sphereCastRadius, out hit, float.MaxValue, ghostWorldPlacementMask);
|
if (hit.collider == null)
|
{
|
return;
|
}
|
m_CurrentTower.Show();
|
|
// ATTENTION TO FIX:什么情况下会导致Y值过高,然后闪烁出现?
|
Vector3 tvec3 = hit.point;
|
tvec3.y = 0.0f;
|
hit.point = tvec3;
|
|
m_CurrentTower.Move(hit.point, hit.collider.transform.rotation, false);
|
}
|
else
|
{
|
m_CurrentTower.Hide();
|
}
|
}
|
|
/// <summary>
|
/// Place the ghost at the pointer's position
|
/// </summary>
|
/// <param name="pointer">The pointer to place the ghost at</param>
|
/// <exception cref="InvalidOperationException">If we're not in the correct state</exception>
|
protected void PlaceGhost(UIPointer pointer)
|
{
|
//MoveGhost(pointer);
|
|
if (m_CurrentArea != null)
|
{
|
//Debug.Log("开始检测PlaceGhost:" + m_GridPosition);
|
|
TowerFitStatus fits = m_CurrentArea.Fits(m_GridPosition, m_CurrentTower.controller.dimensions);
|
|
if (fits == TowerFitStatus.Fits)
|
{
|
// Place the ghost
|
Tower controller = m_CurrentTower.controller;
|
Tower createdTower = Instantiate(controller);
|
createdTower.Initialize(m_CurrentArea, m_GridPosition, dragTowerLevel);
|
|
// ATTENTION TO FIX:是否应该加入List:
|
addTower(createdTower);
|
PlayToAttackEffect(createdTower.ElfId, createdTower.transform.position);
|
dragTowerLevel = 0;
|
CancelGhostPlacement();
|
}
|
}
|
}
|
|
/// <summary>
|
/// 播放宝石上阵特效
|
/// </summary>
|
/// <param name="ElfId">101 火,201 水,301 木</param>
|
/// <param name="worldPos">世界坐标</param>
|
public void PlayToAttackEffect(int ElfId, Vector3 worldPos)
|
{
|
string path = $"UI/DengChang_{ElfId}";
|
|
GameObject prefab = Resources.Load<GameObject>(path);
|
GameObject obj = Instantiate(prefab);
|
obj.transform.position = worldPos;
|
Vector3 pos = obj.transform.position;
|
pos.y += 5f;
|
obj.transform.position = pos;
|
|
ParticleSystem ps = obj.GetComponent<ParticleSystem>();
|
|
if (ps == null)
|
ps = obj.transform.GetChild(0).GetComponent<ParticleSystem>();
|
|
ps.Play();
|
Destroy(obj, ps.main.duration);
|
}
|
|
/// <summary>
|
/// Raycast onto tower placement areas
|
/// </summary>
|
/// <param name="pointer">The pointer we're testing</param>
|
protected void PlacementAreaRaycast(ref UIPointer pointer, bool force = false)
|
{
|
pointer.raycast = null;
|
|
if (pointer.overUI && (!force))
|
{
|
// Pointer is over UI, so no valid position
|
return;
|
}
|
|
// Raycast onto placement area layer
|
RaycastHit hit;
|
if (Physics.Raycast(pointer.ray, out hit, float.MaxValue, placementAreaMask))
|
{
|
pointer.raycast = hit;
|
}
|
}
|
|
/// <summary>
|
/// 是否会跟兵线层数据有碰撞发生.
|
/// </summary>
|
/// <param name="point"></param>
|
protected void WavelineAreaRaycast(ref UIPointer pointer)
|
{
|
RaycastHit hit;
|
if (Physics.Raycast(pointer.ray, out hit, float.MaxValue, waveLineMask))
|
{
|
pointer.wavelineHit = hit;
|
pointer.overWaveLine = true;
|
}
|
return;
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="pointer"></param>
|
protected void BattleAreaRaycast(ref UIPointer pointer)
|
{
|
RaycastHit hit;
|
if (Physics.Raycast(pointer.ray, out hit, float.MaxValue, battleAreaMask))
|
{
|
pointer.wavelineHit = hit;
|
pointer.overWaveLine = true;
|
}
|
|
return;
|
}
|
|
/// <summary>
|
/// 更新每一个
|
/// </summary>
|
protected void updateSceneTowerUpgradeStatus()
|
{
|
bool zeroTower = m_listTower.Count == 0;
|
}
|
|
/// <summary>
|
/// Modifies the valid rendering of the ghost tower once there is enough currency
|
/// </summary>
|
protected virtual void OnCurrencyChanged()
|
{
|
// 如果当前处于TowerBuy Disable的状态,根据Currency的值来判断是否应该重新开启RandomTowerBuy按钮.
|
if (tdBuyDisable)
|
{
|
enableRandomTowerBtn();
|
}
|
|
// 无法支付新的塔防价格,按钮变灰.
|
var tpMgr = TowerPrice.instance;
|
if (tpMgr.currentTowerPrice > EndlessLevelManager.instance.Currency.currentCurrency)
|
disableRandomTowerBtn();
|
|
// 处理场景内升级相关的内容
|
updateSceneTowerUpgradeStatus();
|
|
if (!isBuilding || m_CurrentTower == null || m_CurrentArea == null)
|
{
|
return;
|
}
|
TowerFitStatus fits = m_CurrentArea.Fits(m_GridPosition, m_CurrentTower.controller.dimensions);
|
bool valid = fits == TowerFitStatus.Fits && IsValidPurchase();
|
m_CurrentTower.Move(m_CurrentArea.GridToWorld(m_GridPosition, m_CurrentTower.controller.dimensions),
|
m_CurrentArea.transform.rotation,
|
valid);
|
if (valid && !m_GhostPlacementPossible && ghostBecameValid != null)
|
{
|
m_GhostPlacementPossible = true;
|
ghostBecameValid();
|
}
|
}
|
|
/// <summary>
|
/// Closes the Tower UI on death of tower
|
/// </summary>
|
protected void OnTowerDied(DamageableBehaviour targetable)
|
{
|
DeselectTower();
|
}
|
|
/// <summary>
|
/// Creates and hides the tower and shows the buildInfoUI
|
/// </summary>
|
/// <exception cref="ArgumentNullException">
|
/// Throws exception if the <paramref name="towerToBuild"/> is null
|
/// </exception>
|
void SetUpGhostTower([NotNull] Tower towerToBuild)
|
{
|
if (towerToBuild == null)
|
{
|
throw new ArgumentNullException("towerToBuild");
|
}
|
|
m_CurrentTower = Instantiate(towerToBuild.towerGhostPrefab);
|
m_CurrentTower.Initialize(towerToBuild);
|
}
|
|
/// <summary>
|
/// 处理GameUI的Update相关内容,目前的主要工作是处理成长骰子.
|
/// </summary>
|
private void Update()
|
{
|
if (overTimer != null)
|
overTimer.Tick(Time.deltaTime);
|
|
for (int ti = listTowerTimer.Count - 1; ti >= 0; ti--)
|
{
|
// 如果执行到,会在DelTower函数内删除对应的listTowerTimer.
|
listTowerTimer[ti].Tick(Time.deltaTime);
|
}
|
|
// 更新处理自己方光塔对应的攻击增加.
|
updateLightTowerAttRise();
|
}
|
|
/// <summary>
|
/// 更新火属性Tower对左右塔的攻击增加.
|
/// </summary>
|
protected void updateLightTowerAttRise()
|
{
|
int yRow = 2;
|
int maxTower = MAX_TOWERNUM / 3;
|
|
for (int ti = 0; ti < maxTower; ti++)
|
{
|
Tower tw = FindTowerWithGridIdx(ti, yRow);
|
if (tw)
|
tw.attackRise = 0.0f;
|
}
|
|
for (int ti = 0; ti < maxTower; ti++)
|
{
|
Tower tw = FindTowerWithGridIdx(ti, yRow);
|
if (tw == null) continue;
|
if (tw.towerFeature == EFeatureTower.LightTower)
|
{
|
int nidx = ti - 1;
|
if (nidx >= 0)
|
{
|
tw = FindTowerWithGridIdx(nidx, yRow);
|
if (tw)
|
tw.attackRise = 0.1f;
|
}
|
nidx = ti + 1;
|
if (nidx < maxTower)
|
{
|
tw = FindTowerWithGridIdx(nidx, yRow);
|
if (tw)
|
tw.attackRise = 0.1f;
|
}
|
}
|
}
|
}
|
}
|
}
|