859 lines
30 KiB
C#
859 lines
30 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace TBTK{
|
|
|
|
|
|
public enum _GridType{ SquareGrid, HexGrid, }
|
|
public enum _GridColliderType{ Master, Individual, }
|
|
|
|
|
|
[RequireComponent(typeof(GridGenerator))] [ExecuteInEditMode]
|
|
public class GridManager : MonoBehaviour {
|
|
|
|
#if UNITY_EDITOR
|
|
public static bool inspector=false;
|
|
#endif
|
|
|
|
public bool generateGridOnStart=false;
|
|
public bool generateUnitOnStart=false;
|
|
public bool generateCollectibleOnStart=false;
|
|
|
|
|
|
[Space(8)]
|
|
public _GridType gridType;
|
|
public static _GridType GetGridType(){ return instance.cacheGridType; }
|
|
|
|
public static bool IsSquareGrid(){ return GetGridType()==_GridType.SquareGrid; }
|
|
public static bool IsHexGrid(){ return GetGridType()==_GridType.HexGrid; }
|
|
|
|
public _GridColliderType colliderType;
|
|
public static bool UseMasterCollider(){ return instance.cacheColliderType==_GridColliderType.Master; }
|
|
public static bool UseIndividualCollider(){ return instance.cacheColliderType==_GridColliderType.Individual; }
|
|
|
|
|
|
public enum _RangeCalculation{ ByNode, ByDistance }
|
|
public _RangeCalculation rangeCalculation;
|
|
|
|
|
|
public bool enableDiagonalNeighbour=false;
|
|
public static bool EnableDiagonalNeighbour(){ return instance.cacheDiagonalNeighbour; }
|
|
|
|
|
|
public float nodeSize=1;
|
|
//public static float GetBaseNodeSize(){ return instance.cacheNodeSize; }
|
|
|
|
public float nodeSpacing=0.1f;
|
|
public static float GetNodeSpacing(){ return instance.cacheNodeSpacing; }
|
|
|
|
public static float GetNodeSize(bool addSpacing=true){ return instance._GetNodeSize(addSpacing); }
|
|
public float _GetNodeSize(bool addSpacing=true){
|
|
return cacheNodeSize * (IsHexGrid() ? 1.15f : 1) + (addSpacing ? cacheNodeSpacing : 0);
|
|
}
|
|
|
|
|
|
public static void ResetGrid(){
|
|
for(int x=0; x<instance.grid.Count; x++){
|
|
for(int z=0; z<instance.grid[x].Count; z++){
|
|
instance.grid[x][z].ResetListState();
|
|
}
|
|
}
|
|
}
|
|
|
|
[Space(8)]
|
|
public int dimensionX=50; public static int DimensionX(){ return instance.cacheDimensionX; }
|
|
public int dimensionZ=50; public static int DimensionZ(){ return instance.cacheDimensionZ; }
|
|
public float unwalkableRate=0.1f;
|
|
public float obstacleRate=0.1f;
|
|
public float wallRate=0.2f;
|
|
|
|
[Space(8)] //we need ListWrapper because unity will not serialize a list of list (grid)
|
|
public List<ListWrapper> gridT =new List<ListWrapper>();
|
|
public List<List<Node>> grid=new List<List<Node>>();
|
|
[HideInInspector] public float offsetX;
|
|
[HideInInspector] public float offsetZ;
|
|
|
|
public float GetOffsetX(){
|
|
if(IsSquareGrid()) offsetX=DimensionX()*GetNodeSize()*.5f-GetNodeSize()*.5f;
|
|
if(IsHexGrid()) offsetX=DimensionX()*GetNodeSize()*GridGenerator.spaceXHex/2f-0.5f*GetNodeSize()*GridGenerator.spaceXHex;
|
|
return offsetX;
|
|
}
|
|
public float GetOffsetZ(){
|
|
if(IsSquareGrid()) offsetZ=DimensionZ()*GetNodeSize()*.5f-nodeSize*.5f;
|
|
if(IsHexGrid()) offsetZ=DimensionZ()*GetNodeSize()*GridGenerator.spaceZHex/2f-0.5f*GetNodeSize()*GridGenerator.spaceZHex;
|
|
return offsetZ;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HideInInspector] public _GridType cacheGridType;
|
|
[HideInInspector] public _GridColliderType cacheColliderType;
|
|
[HideInInspector] public bool cacheDiagonalNeighbour;
|
|
[HideInInspector] public float cacheNodeSize;
|
|
[HideInInspector] public float cacheNodeSpacing;
|
|
[HideInInspector] public int cacheDimensionX;
|
|
[HideInInspector] public int cacheDimensionZ;
|
|
|
|
public void CacheGridSetting(){
|
|
cacheGridType=gridType;
|
|
cacheColliderType=colliderType;
|
|
cacheDiagonalNeighbour=enableDiagonalNeighbour;
|
|
cacheNodeSize=nodeSize;
|
|
cacheNodeSpacing=nodeSpacing;
|
|
cacheDimensionX=dimensionX;
|
|
cacheDimensionZ=dimensionZ;
|
|
}
|
|
|
|
|
|
[Space(8)] public GameObject masterColliderObj;
|
|
public void SetupMasterCollider(){
|
|
if(!UseMasterCollider()){
|
|
if(masterColliderObj!=null) masterColliderObj.SetActive(false);
|
|
return;
|
|
}
|
|
|
|
if(masterColliderObj==null){
|
|
masterColliderObj=GameObject.CreatePrimitive(PrimitiveType.Quad);
|
|
masterColliderObj.transform.parent=transform;
|
|
masterColliderObj.transform.position=Vector3.zero;
|
|
masterColliderObj.transform.rotation=Quaternion.Euler(90, 0, 0);
|
|
masterColliderObj.name="Collider"; masterColliderObj.layer=30;
|
|
masterColliderObj.GetComponent<MeshRenderer>().enabled=false;
|
|
}
|
|
|
|
masterColliderObj.transform.localScale=new Vector3(DimensionX()*GetNodeSize(), DimensionZ()*GetNodeSize(), 1);
|
|
masterColliderObj.SetActive(true);
|
|
}
|
|
|
|
|
|
public static List<Vector3> nodeDirList=new List<Vector3>();
|
|
public static void InitNodeDirList(){
|
|
nodeDirList=new List<Vector3>();
|
|
if(GridManager.IsHexGrid()){
|
|
nodeDirList.Add(new Vector3(.866f, 0, .5f));
|
|
nodeDirList.Add(new Vector3(0, 0, 1));
|
|
nodeDirList.Add(new Vector3(-.866f, 0, .5f));
|
|
nodeDirList.Add(new Vector3(-.866f, 0, -.5f));
|
|
nodeDirList.Add(new Vector3(0, 0, -1));
|
|
nodeDirList.Add(new Vector3(.866f, 0, -.5f));
|
|
}
|
|
else if(GridManager.IsSquareGrid()){
|
|
nodeDirList.Add(new Vector3(1, 0, 0));
|
|
nodeDirList.Add(new Vector3(0, 0, 1));
|
|
nodeDirList.Add(new Vector3(-1, 0, 0));
|
|
nodeDirList.Add(new Vector3(0, 0, -1));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public static void SetupFogOfWar(){ instance._SetupFogOfWar(); }
|
|
public void _SetupFogOfWar(){
|
|
if(!GameControl.EnableFogOfWar()) return;
|
|
|
|
List<Unit> unitList=new List<Unit>( UnitManager.GetAllUnits() );
|
|
for(int i=0; i<unitList.Count; i++){
|
|
if(unitList[i].playableUnit) continue;
|
|
unitList.RemoveAt(i); i-=1;
|
|
}
|
|
|
|
for(int x=0; x<grid.Count; x++){
|
|
for(int z=0; z<grid[x].Count; z++){
|
|
bool visible=false;
|
|
for(int i=0; i<unitList.Count; i++){
|
|
visible=CheckLOS(unitList[i].node, grid[x][z], unitList[i].GetSight());
|
|
if(visible) break;
|
|
}
|
|
grid[x][z].SetVisible(visible);
|
|
}
|
|
}
|
|
|
|
GridIndicator.ShowFog();
|
|
}
|
|
public static bool CheckLOS(Node node1, Node node2, int sight, bool debugging=false){
|
|
if(debugging) Debug.Log("CheckLOS "+node1.GetPos()+" "+node2.GetPos()+" "+GridManager.GetDistance(node1, node2));
|
|
|
|
if(GridManager.GetDistance(node1, node2)>sight) return false;
|
|
|
|
if(debugging) Debug.Log(" ___ CheckLOS ");
|
|
|
|
List<Node> nList1=new List<Node>{ node1 };
|
|
List<Node> nList2=new List<Node>{ node2 };
|
|
|
|
if(GameControl.EnableSideStepping()){
|
|
if(GridManager.IsSquareGrid()){
|
|
nList1.AddRange(GetSideStepNeighbours(node1, node2));
|
|
nList2.AddRange(GetSideStepNeighbours(node2, node1));
|
|
}
|
|
else{
|
|
nList1.AddRange(node1.GetNeighbourList(true)); //n1 is the origin node,
|
|
//nList2.AddRange(node2.GetNeighbourList(true));
|
|
}
|
|
}
|
|
|
|
if(debugging) Debug.Log(" ___ CheckLOS "+nList1.Count+" "+nList2.Count);
|
|
|
|
for(int i=0; i<nList1.Count; i++){
|
|
for(int n=0; n<nList2.Count; n++){
|
|
if(GridManager.GetDistance(nList1[i], nList2[n])>sight) continue;
|
|
bool visible=!LOSCast(nList1[i].GetPos(), nList2[n].GetPos());
|
|
if(debugging) Debug.DrawLine(nList1[i].GetPos(), nList2[n].GetPos(), visible ? Color.white : Color.red, 1);
|
|
if(visible) return true;
|
|
}
|
|
}
|
|
|
|
if(debugging) Debug.Log(" ___ CheckLOS pass all false");
|
|
|
|
return false;
|
|
}
|
|
public static bool LOSCast(Vector3 pos1, Vector3 pos2, bool debugging=false){
|
|
InitMask();
|
|
return Physics.Linecast(pos1+new Vector3(0, .1f, 0), pos2+new Vector3(0, .1f, 0), losMask);
|
|
}
|
|
private static LayerMask losMask; public static bool initMask;
|
|
public static void InitMask(){
|
|
if(initMask) return;
|
|
initMask=true;
|
|
losMask=1<<TBTK.GetLayerObsFullCover();
|
|
}
|
|
|
|
public static List<Node> GetSideStepNeighbours(Node srcNode, Node tgtNode){
|
|
List<Node> list=new List<Node>();
|
|
Node n1=GetSideStepNeighbour(srcNode, tgtNode, 1); if(n1!=null) list.Add(n1);
|
|
Node n2=GetSideStepNeighbour(srcNode, tgtNode, -1); if(n2!=null) list.Add(n2);
|
|
return list;
|
|
}
|
|
public static Node GetSideStepNeighbour(Node srcNode, Node tgtNode, float mul){
|
|
Vector3 dir=(tgtNode.GetPos()-srcNode.GetPos()).normalized;
|
|
Vector3 dirP=new Vector3(dir.z, 0, -dir.x);
|
|
|
|
Node neighbour=srcNode.GetNeighbourFromPos(srcNode.GetPos()+(mul*dirP)*GridManager.GetNodeSize());
|
|
if(neighbour!=null && !neighbour.IsBlocked(srcNode)) return neighbour;
|
|
|
|
return null;
|
|
}
|
|
|
|
public static void SetupFogOfWarForDeployment(List<Node> dNodeList, int factionID){
|
|
if(!GameControl.EnableFogOfWar()) return;
|
|
|
|
//Faction fac=UnitManager.GetFaction(UnitManager.GetDeployingFacIdx());
|
|
//List<Node> dNodeList=GetDeploymentNode(deployFacID);
|
|
|
|
List<Node> visibleList=new List<Node>();
|
|
|
|
for(int x=0; x<instance.grid.Count; x++){
|
|
for(int z=0; z<instance.grid[x].Count; z++){
|
|
Node node=instance.grid[x][z];
|
|
|
|
//Node node=instance.grid[x][z];
|
|
//node.SetVisible((node.unit!=null && node.unit.facID==factionID) || dNodeList.Contains(node));
|
|
|
|
if(dNodeList.Contains(node) || (node.unit!=null && node.unit.facID==factionID)){
|
|
List<Node> neighbours=node.GetNeighbourList();
|
|
for(int n=0; n<neighbours.Count; n++){
|
|
neighbours[n].SetVisible(true);
|
|
if(!visibleList.Contains(neighbours[n])) visibleList.Add(neighbours[n]);
|
|
}
|
|
|
|
node.SetVisible(true);
|
|
continue;
|
|
}
|
|
else node.SetVisible(visibleList.Contains(node));
|
|
}
|
|
}
|
|
}
|
|
|
|
private List<Node> scannedNodeList=new List<Node>(); //list of node under the effect of scan-fog-of-war ability
|
|
public static void AddScannedNode(Node node){ instance.scannedNodeList.Add(node); }
|
|
public static void EndTurn(){
|
|
for(int i=0; i<instance.scannedNodeList.Count; i++){
|
|
if(instance.scannedNodeList[i].IterateFogOfWarCD()){
|
|
instance.scannedNodeList.RemoveAt(i); i-=1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//public bool combineGridMesh;
|
|
//public static bool CombineGridMesh(){ return instance.combineGridMesh; }
|
|
|
|
private GridGenerator gridGenerator;
|
|
|
|
private static GridManager instance;
|
|
public static GridManager GetInstance(){ return instance; }
|
|
public void SetupInstance(){ instance=this; } //called by GridGenerator
|
|
|
|
public static void Init(){
|
|
if(instance==null) instance=(GridManager)FindObjectOfType(typeof(GridManager));
|
|
|
|
instance.gridGenerator=instance.transform.GetComponent<GridGenerator>();
|
|
instance.gridGenerator.Init();
|
|
instance.InitGrid();
|
|
|
|
if(Application.isPlaying){// && instance.combineGridMesh){
|
|
CombineMeshes cm=instance.gridGenerator.gridParent.GetComponent<CombineMeshes>();
|
|
if(cm!=null) cm.Combine();
|
|
}
|
|
|
|
GridIndicator indicator=(GridIndicator)FindObjectOfType(typeof(GridIndicator));
|
|
indicator.Awake();
|
|
}
|
|
|
|
void InitGrid(){
|
|
InitNodeDirList();
|
|
|
|
for(int i=0; i<gridT.Count; i++) grid.Add(gridT[i].list);
|
|
if(Application.isPlaying) gridT.Clear();
|
|
|
|
if(Application.isPlaying && generateGridOnStart) gridGenerator.Generate();
|
|
|
|
for(int x=0; x<grid.Count; x++){
|
|
for(int z=0; z<grid[x].Count; z++){
|
|
if(grid[x][z].unit!=null) grid[x][z].unit.node=grid[x][z];
|
|
//if(grid[x][z].collectible!=null) grid[x][z].collectible.node=grid[x][z];
|
|
}
|
|
}
|
|
|
|
for(int x=0; x<grid.Count; x++){
|
|
for(int z=0; z<grid[x].Count; z++){
|
|
grid[x][z].SetupNeighbour();
|
|
}
|
|
}
|
|
|
|
for(int x=0; x<grid.Count; x++){
|
|
for(int z=0; z<grid[x].Count; z++){
|
|
grid[x][z].SetupWall();
|
|
}
|
|
}
|
|
|
|
if(Application.isPlaying){
|
|
if(generateUnitOnStart) gameObject.GetComponent<GridGenerator>().GenerateUnit();
|
|
if(generateCollectibleOnStart) gameObject.GetComponent<GridGenerator>().GenerateCollectible();
|
|
}
|
|
|
|
if(Application.isPlaying && GameControl.EnableCoverSystem()) instance.StartCoroutine(InitGrid_Delayed());
|
|
}
|
|
private IEnumerator InitGrid_Delayed(){
|
|
yield return null;
|
|
|
|
for(int x=0; x<grid.Count; x++){
|
|
for(int z=0; z<grid[x].Count; z++){
|
|
grid[x][z].InitCover();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Update(){
|
|
if(instance==null && !Application.isPlaying){
|
|
instance=this;
|
|
InitGrid();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public static List<List<Node>> GetGrid(){ return instance.grid; }
|
|
public static int GetNodeCount(){ return instance.dimensionX * instance.dimensionZ ; }
|
|
|
|
public static Node GetNode(int x, int z){
|
|
if(x<0 || x>=instance.grid.Count) return null;
|
|
if(z<0 || z>=instance.grid[x].Count) return null;
|
|
|
|
return instance.grid[x][z];
|
|
}
|
|
public static Node GetNode(Vector3 point, GameObject obj){
|
|
if(UseIndividualCollider()){
|
|
for(int x=0; x<instance.grid.Count; x++){
|
|
for(int z=0; z<instance.grid[x].Count; z++){
|
|
if(instance.grid[x][z].GetObjT().gameObject==obj) return instance.grid[x][z];
|
|
}
|
|
}
|
|
}
|
|
|
|
if(IsSquareGrid()){
|
|
Vector2 coor=new Vector2(point.x+instance.offsetX, point.z+instance.offsetZ)/GetNodeSize();
|
|
return GetNode((int)Mathf.Round(coor.x), (int)Mathf.Round(coor.y));
|
|
}
|
|
else{
|
|
Vector2 coor=new Vector2(point.x+instance.offsetX, point.z+instance.offsetZ)/GetNodeSize();
|
|
int x=(int)Mathf.Round(coor.x/GridGenerator.spaceXHex);
|
|
coor.x/=GridGenerator.spaceXHex;
|
|
|
|
float offset=(x%2==1 ? 0 : GridGenerator.spaceZHex*GetNodeSize()*0.5f);
|
|
coor.y=(coor.y)/GridGenerator.spaceZHex-offset*0.5f;
|
|
//Debug.Log(coor.x.ToString("f2")+" "+coor.y.ToString("f2")+" "+offset);
|
|
|
|
return GetNode((int)Mathf.Round(coor.x), (int)Mathf.Round(coor.y));
|
|
}
|
|
}
|
|
|
|
|
|
public static int GetDistance(Node n1, Node n2, bool searchAStar=false){
|
|
if(!searchAStar){
|
|
if(IsSquareGrid()){
|
|
if(EnableDiagonalNeighbour()){
|
|
float deltaX=Mathf.Abs(n1.idxX-n2.idxX);
|
|
float deltaZ=Mathf.Abs(n1.idxZ-n2.idxZ);
|
|
return (int)Mathf.Max(deltaX, deltaZ);
|
|
}
|
|
return (int)Mathf.Abs(n1.idxX-n2.idxX)+(int)Mathf.Abs(n1.idxZ-n2.idxZ);
|
|
}
|
|
else{
|
|
float x=Mathf.Abs(n1.x-n2.x);
|
|
float y=Mathf.Abs(n1.y-n2.y);
|
|
float z=Mathf.Abs(n1.z-n2.z);
|
|
return (int)((x + y + z)/2);
|
|
}
|
|
}
|
|
else return AStar.SearchWalkableNode(n1, n2).Count;
|
|
}
|
|
|
|
public static float GetAngle(Node n1, Node n2, bool round){ return GetAngle(n1.GetPos(), n2.GetPos(), round); }
|
|
public static float GetAngle(Vector3 p1, Vector3 p2, bool round){
|
|
float angle=Utility.Vector2ToAngle(new Vector2(p2.x-p1.x, p2.z-p1.z).normalized);
|
|
if(round){
|
|
if(IsSquareGrid()) angle=Utility.RoundAngleTo90(angle);
|
|
else if(IsHexGrid()) angle=Utility.RoundAngleTo60(angle);
|
|
}
|
|
return angle;
|
|
}
|
|
|
|
|
|
public static List<Node> GetDeploymentNode(int facID){ return instance._GetDeploymentNode(facID); }
|
|
public List<Node> _GetDeploymentNode(int facID){
|
|
List<Node> list=new List<Node>();
|
|
for(int x=0; x<grid.Count; x++){
|
|
for(int z=0; z<grid[x].Count; z++){
|
|
if(!grid[x][z].walkable || !grid[x][z].IsEmpty()) continue;
|
|
if(grid[x][z].deployFacID==facID) list.Add(grid[x][z]);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
|
|
public List<Node> walkableList=new List<Node>();
|
|
public List<Node> attackableList=new List<Node>();
|
|
public static List<Node> GetWalkableList(){ return instance.walkableList; }
|
|
public static List<Node> GetAttackableList(){ return instance.attackableList; }
|
|
|
|
public static void SelectUnit(Unit unit){ SetupWalkableList(unit); SetupAttackableList(unit); }
|
|
public static List<Node> SetupWalkableList(Unit unit){
|
|
instance.walkableList.Clear();
|
|
if(!unit.CanMove()) return null;
|
|
|
|
//instance.walkableList=GetNodesWithinDistance(unit.node, unit.GetMoveRange(), true, unit.canMovePastUnit, unit.canMovePastObs);
|
|
instance.walkableList=GetNodesWithinDistance(unit.node, unit.GetMoveRange(), true, AStar.BypassUnitCode(unit), unit.canMovePastObs);
|
|
|
|
for(int i=0; i<instance.walkableList.Count; i++){
|
|
if(instance.walkableList[i].unit!=null || instance.walkableList[i].HasObstacle()){
|
|
instance.walkableList.RemoveAt(i); i-=1;
|
|
}
|
|
}
|
|
|
|
return instance.walkableList;
|
|
}
|
|
public static List<Node> SetupAttackableList(Unit unit){
|
|
instance.attackableList=GetAttackableList(unit, unit.node);
|
|
return instance.attackableList;
|
|
//instance.attackableList.Clear();
|
|
//List<Node> list=GetNodesWithinDistance(unit.node, unit.GetAttackRange(), false);
|
|
//for(int i=0; i<list.Count; i++){
|
|
// if(list[i].unit!=null && list[i].unit.facID!=unit.facID) instance.attackableList.Add(list[i]);
|
|
//}
|
|
}
|
|
public static void ClearSelectUnit(){
|
|
GridIndicator.HideAll();
|
|
instance.walkableList=new List<Node>(); instance.attackableList=new List<Node>();
|
|
}
|
|
|
|
public static List<Node> GetAttackableList(Unit unit, Node tgtNode){
|
|
if(!unit.CanAttack()) return new List<Node>();
|
|
|
|
List<Node> list=GetNodesWithinDistance(tgtNode, unit.GetAttackRange(), false);
|
|
List<Node> tgtList=new List<Node>();
|
|
|
|
float minAttackRange=unit.GetAttackRangeMin();
|
|
float meleeAttackRange=unit.hasMeleeAttack ? unit.GetAttackRangeMelee() : 0;
|
|
|
|
for(int i=0; i<list.Count; i++){
|
|
if(list[i].unit==null) continue;
|
|
if(!list[i].IsVisible()) continue;
|
|
if(OnSameFac(list[i].unit, unit)) continue;
|
|
|
|
if(minAttackRange>0){
|
|
int dist=GridManager.GetDistance(list[i].unit.node, unit.node);
|
|
if(meleeAttackRange<=0){
|
|
if(minAttackRange>0 && dist<minAttackRange) continue;
|
|
}
|
|
else{
|
|
if(dist>meleeAttackRange && dist<minAttackRange) continue;
|
|
}
|
|
}
|
|
|
|
if(unit.requireLOSToAttack && !CheckLOS(tgtNode, list[i], unit.GetSight())) continue;
|
|
|
|
tgtList.Add(list[i]);
|
|
}
|
|
return tgtList;
|
|
}
|
|
|
|
|
|
public static bool CanMoveTo(Node node){ return instance.walkableList!=null && instance.walkableList.Contains(node); }
|
|
public static bool CanAttack(Node node){ return node.unit!=null && instance.attackableList!=null && instance.attackableList.Contains(node); }
|
|
|
|
public static void PreviewAttackableNode(Node node){ instance._PreviewAttackableNode(node); }
|
|
public void _PreviewAttackableNode(Node node){
|
|
bool preview=node!=null && GridManager.CanMoveTo(node);
|
|
preview&=(UnitManager.GetSelectedUnit()!=null && UnitManager.GetSelectedUnit().CanAttack());
|
|
|
|
if(preview) GridIndicator.PreviewHostile(GetAttackableList(UnitManager.GetSelectedUnit(), node));
|
|
else GridIndicator.ClearPreviewHostile();
|
|
}
|
|
|
|
|
|
|
|
public List<Node> abilityTargetList=new List<Node>();
|
|
public static bool InAbilityTargetList(Node node){ return instance.abilityTargetList.Contains(node); }
|
|
|
|
public static void SetupAbilityTargetList(Faction fac, Ability ability){
|
|
List<Node> list=new List<Node>();
|
|
for(int x=0; x<instance.grid.Count; x++) list.AddRange(instance.grid[x]);
|
|
SetupAbilityTargetList(ability, list, fac.factionID, null);
|
|
}
|
|
public static void SetupAbilityTargetList(Unit unit, Ability ability){
|
|
//Debug.Log("SetupAbilityTargetList "+ability.TargetStraightLineOnly());
|
|
|
|
if(ability.TargetCone()){
|
|
return;
|
|
}
|
|
if(ability.TargetStraightLineOnly()){
|
|
instance.abilityTargetList.Clear();
|
|
|
|
for(int i=0; i<(IsHexGrid() ? 6 : 4); i++){
|
|
float angle=IsHexGrid() ? (i*60)+30 : i*90 ;
|
|
List<Node> list=GetNodesInALine(unit.node, angle, ability.GetRange());
|
|
|
|
for(int n=0; n<list.Count; n++) list[n].abLineParent=list[list.Count-1];
|
|
|
|
if(ability.type==Ability._AbilityType.Charge){
|
|
for(int n=0; n<list.Count; n++){
|
|
Node prevNode=n==0 ? unit.node : list[n-1] ;
|
|
|
|
if(ability.targetType==Ability._TargetType.EmptyNode){
|
|
if(list[n].IsBlocked(prevNode)) break;
|
|
instance.abilityTargetList.Add(list[n]);
|
|
}
|
|
else if(ability.targetType==Ability._TargetType.AllNode){
|
|
if(list[n].IsBlocked(prevNode, AStar.BypassUnitCode(true))) break;
|
|
instance.abilityTargetList.Add(list[n]);
|
|
if(list[n].unit!=null) break;
|
|
}
|
|
else{
|
|
if(list[n].IsBlocked(prevNode, AStar.BypassUnitCode(true))) break;
|
|
if(list[n].unit==null) continue;
|
|
if(ability.targetType==Ability._TargetType.AllUnit) instance.abilityTargetList.Add(list[n]);
|
|
else if(ability.targetType==Ability._TargetType.HostileUnit && !OnSameFac(list[n].unit, unit)) instance.abilityTargetList.Add(list[n]);
|
|
else if(ability.targetType==Ability._TargetType.FriendlyUnit && OnSameFac(list[n].unit, unit)) instance.abilityTargetList.Add(list[n]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else instance.abilityTargetList.AddRange(list);
|
|
}
|
|
|
|
GridIndicator.ShowAbility(instance.abilityTargetList);
|
|
return;
|
|
}
|
|
|
|
List<Node> nodeList=GetNodesWithinDistance(unit.node, ability.GetRange());
|
|
SetupAbilityTargetList(ability, nodeList, unit.GetFacID(), unit.node);
|
|
}
|
|
public static void SetupAbilityTargetList(Ability ability, List<Node> list, int facID, Node origin){
|
|
instance.abilityTargetList.Clear();
|
|
|
|
int rangeMin=ability.GetRangeMin();
|
|
if(ability.isUnitAbility && rangeMin>0){
|
|
for(int i=0; i<list.Count; i++){
|
|
if(GetDistance(origin, list[i])<rangeMin){ list.RemoveAt(i); i-=1; }
|
|
}
|
|
}
|
|
|
|
if(ability.isUnitAbility && ability.requireLos && origin.unit!=null){
|
|
for(int i=0; i<list.Count; i++){
|
|
if(!CheckLOS(origin, list[i], origin.unit.GetSight())){ list.RemoveAt(i); i-=1; }
|
|
}
|
|
}
|
|
|
|
if(ability.targetType==Ability._TargetType.AllNode){
|
|
instance.abilityTargetList=list;
|
|
}
|
|
else if(ability.targetType==Ability._TargetType.AllUnit){
|
|
for(int i=0; i<list.Count; i++){
|
|
if(list[i].unit!=null) instance.abilityTargetList.Add(list[i]);
|
|
}
|
|
}
|
|
else if(ability.targetType==Ability._TargetType.HostileUnit){
|
|
for(int i=0; i<list.Count; i++){
|
|
if(list[i].unit!=null && list[i].unit.GetFacID()!=facID) instance.abilityTargetList.Add(list[i]);
|
|
}
|
|
}
|
|
else if(ability.targetType==Ability._TargetType.FriendlyUnit){
|
|
for(int i=0; i<list.Count; i++){
|
|
if(list[i].unit!=null && list[i].unit.GetFacID()==facID) instance.abilityTargetList.Add(list[i]);
|
|
}
|
|
}
|
|
else if(ability.targetType==Ability._TargetType.EmptyNode){
|
|
for(int i=0; i<list.Count; i++){
|
|
if(list[i].unit==null) instance.abilityTargetList.Add(list[i]);
|
|
}
|
|
}
|
|
|
|
if(!ability.isUnitAbility && ability.targetType==Ability._TargetType.AllNode){
|
|
GridIndicator.ShowAbility(new List<Node>());
|
|
}
|
|
else GridIndicator.ShowAbility(instance.abilityTargetList);
|
|
}
|
|
public static void ClearAbilityTargetList(bool resetIndicator){
|
|
GridIndicator.HideAbility();
|
|
instance.abilityTargetList.Clear();
|
|
|
|
if(resetIndicator){
|
|
GridIndicator.ShowMovable(GetWalkableList());
|
|
GridIndicator.ShowHostile(GetAttackableList());
|
|
}
|
|
}
|
|
|
|
public static List<Node> GetTargetNodeForNonTargetingFAbility(Ability ability){
|
|
List<Node> list=new List<Node>();
|
|
List<Unit> uList=UnitManager.GetAllUnitList();
|
|
|
|
//if(ability.targetType==Ability._TargetType.AllNode){
|
|
// for(int x=0; x<instance.grid.Count; x++) list.AddRange(instance.grid[x]);
|
|
//}
|
|
if(ability.targetType==Ability._TargetType.AllUnit){
|
|
for(int i=0; i<uList.Count; i++) list.Add(uList[i].node);
|
|
}
|
|
else if(ability.targetType==Ability._TargetType.HostileUnit){
|
|
for(int i=0; i<uList.Count; i++){ if(uList[i].GetFacID()!=ability.facID) list.Add(uList[i].node); }
|
|
}
|
|
else if(ability.targetType==Ability._TargetType.FriendlyUnit){
|
|
for(int i=0; i<uList.Count; i++){ if(uList[i].GetFacID()==ability.facID) list.Add(uList[i].node); }
|
|
}
|
|
//else if(ability.targetType==Ability._TargetType.EmptyNode){
|
|
// for(int x=0; x<instance.grid.Count; x++){
|
|
// for(int z=0; z<instance.grid[x].Count; z++){
|
|
// if(instance.grid[x][z].unit==null) list.Add(instance.grid[x][z]);
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
return list;
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<Node> testNodeList=new List<Node>();
|
|
void OnDrawGizmos22(){
|
|
Gizmos.color=Color.grey;
|
|
for(int i=0; i<testNodeList.Count; i++) Gizmos.DrawSphere(testNodeList[i].GetPos(), 0.4f);
|
|
}
|
|
|
|
public static List<Node> GetSurroundingNodes(Node srcNode, int range, bool walkableOnly=true){
|
|
List<Node> tgtList=GetNodesWithinDistance(srcNode, range, walkableOnly);
|
|
List<Node> exemptList=GetNodesWithinDistance(srcNode, range-1, walkableOnly);
|
|
|
|
for(int i=0; i<exemptList.Count; i++) tgtList.Remove(exemptList[i]);
|
|
|
|
return tgtList;
|
|
}
|
|
public static List<Node> GetNodesInACircle(Node srcNode, int range, bool walkableOnly=true){
|
|
//int range=(int)Mathf.Ceil(dist/GetNodeSize());
|
|
float dist=range*GetNodeSize();
|
|
List<Node> tgtList=GetNodesWithinDistance(srcNode, range, walkableOnly);
|
|
|
|
//instance.testNodeList=new List<Node>( tgtList );
|
|
|
|
for(int i=0; i<tgtList.Count; i++){
|
|
if(Vector3.Distance(srcNode.GetPos(), tgtList[i].GetPos())>dist){ tgtList.RemoveAt(i); i-=1; }
|
|
}
|
|
return tgtList;
|
|
}
|
|
public static List<Node> GetNodesInACone(Node srcNode, Node tgtNode, int range, int fov, bool walkableOnly=false){
|
|
List<Node> tgtList=new List<Node>();
|
|
|
|
Vector3 v=( tgtNode.GetPos() - srcNode.GetPos() ).normalized;
|
|
float baseAngle=Utility.Vector2ToAngle(new Vector2(v.x, v.z));
|
|
|
|
//~ int range=(int)Mathf.Ceil(dist/GetNodeSize());
|
|
List<Node> nodeList=GetNodesWithinDistance(srcNode, range, true, true, true);
|
|
//~ List<Node> nodeList=GetNodesInACircle(srcNode, range, walkableOnly);
|
|
|
|
//instance.testNodeList=nodeList;
|
|
|
|
for(int i=0; i<nodeList.Count; i++){
|
|
//if(Vector3.Distance(srcNode.GetPos(), nodeList[i].GetPos())>dist) continue;
|
|
if(!nodeList[i].walkable) continue;
|
|
if(nodeList[i].obstacleT!=null) continue;
|
|
if(walkableOnly && nodeList[i].unit!=null) continue;
|
|
|
|
float angle=GetAngle(srcNode, nodeList[i], false);//Utility.Vector2ToAngle(new Vector2(vv.x, vv.z));
|
|
|
|
float angleDiff=Mathf.Abs(angle-baseAngle);
|
|
if(angleDiff>180) angleDiff=Mathf.Abs(angleDiff-360);
|
|
|
|
if(angleDiff<=fov*0.5f){
|
|
tgtList.Add(nodeList[i]);
|
|
//Debug.DrawLine(srcNode.GetPos(), nodeList[i].GetPos(), Color.green, 0.2f);
|
|
}
|
|
//else Debug.DrawLine(srcNode.GetPos(), nodeList[i].GetPos(), Color.red, 0.2f);
|
|
}
|
|
|
|
return tgtList;
|
|
}
|
|
|
|
public static List<Node> GetNodesInALine(Node srcNode, float angle, int dist, bool walkableOnly=false){
|
|
List<Node> list=new List<Node>();
|
|
Node curNode=srcNode;
|
|
for(int i=0; i<dist; i++){
|
|
List<Node> neighbourList=curNode.GetNeighbourList(walkableOnly);
|
|
for(int n=0; n<neighbourList.Count; n++){
|
|
if(Mathf.Abs(GetAngle(neighbourList[n], curNode, true)-angle)>1) continue;
|
|
curNode=neighbourList[n];
|
|
list.Add(curNode);
|
|
break;
|
|
}
|
|
}
|
|
//Debug.Log("GetNodesInALine "+list.Count);
|
|
//if(list.Count>3) Debug.Log(list[0].objT+" "+list[1].objT+" "+list[2].objT+" "+list[3].objT+" ");
|
|
return list;
|
|
}
|
|
|
|
public static List<Node> GetNodesWithinDistance(Node srcNode, int dist, bool walkableOnly=false, bool allowUnit=false, bool allowObs=false){
|
|
return GetNodesWithinDistance(srcNode, dist, walkableOnly, AStar.BypassUnitCode(allowUnit), allowObs);
|
|
}
|
|
public static List<Node> GetNodesWithinDistance(Node srcNode, int dist, bool walkableOnly, int allowUnit, bool allowObs){
|
|
List<Node> neighbourList=srcNode.GetNeighbourList(walkableOnly, allowUnit, allowObs);
|
|
|
|
List<Node> closeList=new List<Node>();
|
|
List<Node> openList=new List<Node>();
|
|
List<Node> newOpenList=new List<Node>();
|
|
|
|
for(int m=0; m<neighbourList.Count; m++){
|
|
Node neighbour=neighbourList[m];
|
|
if(!newOpenList.Contains(neighbour)) newOpenList.Add(neighbour);
|
|
}
|
|
|
|
for(int i=0; i<dist; i++){
|
|
openList=newOpenList;
|
|
newOpenList=new List<Node>();
|
|
|
|
for(int n=0; n<openList.Count; n++){
|
|
neighbourList=openList[n].GetNeighbourList(walkableOnly, allowUnit, allowObs);
|
|
for(int m=0; m<neighbourList.Count; m++){
|
|
Node neighbour=neighbourList[m];
|
|
if(!closeList.Contains(neighbour) && !openList.Contains(neighbour) && !newOpenList.Contains(neighbour)){
|
|
newOpenList.Add(neighbour);
|
|
}
|
|
}
|
|
}
|
|
|
|
for(int n=0; n<openList.Count; n++){
|
|
Node tile=openList[n];
|
|
if(tile!=srcNode && !closeList.Contains(tile)){
|
|
closeList.Add(tile);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if(IsSquareGrid() && EnableDiagonalNeighbour() && instance.rangeCalculation==_RangeCalculation.ByDistance){
|
|
float convertedDist=dist*GetNodeSize()+GetNodeSize()*0.5f;
|
|
for(int i=0; i<closeList.Count; i++){
|
|
if(Vector3.Distance(closeList[i].GetPos(), srcNode.GetPos())>=convertedDist){
|
|
closeList.RemoveAt(i); i-=1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return closeList;
|
|
}
|
|
|
|
|
|
|
|
public static List<Node> GetSpawnGroup(int facID, int areaID){
|
|
List<Node> list=new List<Node>();
|
|
for(int x=0; x<instance.grid.Count; x++){
|
|
for(int z=0; z<instance.grid[x].Count; z++){
|
|
if(!instance.grid[x][z].walkable || instance.grid[x][z].HasObstacle()) continue;
|
|
if(instance.grid[x][z].spawnGroupFacID==facID && instance.grid[x][z].spawnGroupID==areaID) list.Add(instance.grid[x][z]);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
|
|
public static bool OnSameFac(Unit unit1, Unit unit2){ return unit1.GetFacID()==unit2.GetFacID(); }
|
|
|
|
|
|
void OnDrawGizmos(){
|
|
for(int x=0; x<grid.Count; x++){
|
|
for(int z=0; z<grid[x].Count; z++){
|
|
//Gizmos.color=grid[x][z].visible ? Color.grey : Color.white;
|
|
if(!grid[x][z].walkable){
|
|
Gizmos.color=new Color(0.4f, 0.4f, 0.4f, 1f);
|
|
Gizmos.DrawSphere(grid[x][z].GetPos(), nodeSize*0.125f);
|
|
}
|
|
else if(!grid[x][z].IsVisible()){
|
|
Gizmos.color=new Color(0.5f, 0.5f, 0.5f, .6f);
|
|
Gizmos.DrawSphere(grid[x][z].GetPos(), nodeSize*0.125f);
|
|
}
|
|
|
|
if(grid[x][z].deployFacID>=0){
|
|
Gizmos.color=UnitManager.GetFacColor(grid[x][z].deployFacID);
|
|
Gizmos.DrawSphere(grid[x][z].GetPos(), nodeSize*0.175f);
|
|
}
|
|
if(grid[x][z].spawnGroupFacID>=0){
|
|
//Gizmos.DrawSphere(grid[x][z].GetPos(), nodeSize*0.25f);
|
|
//Utility.GizmosDrawCross(grid[x][z].GetPos(), nodeSize*0.25f, UnitManager.GetFacColor(grid[x][z].spawnGroupFacID));
|
|
|
|
Gizmos.color=UnitManager.GetFacColor(grid[x][z].spawnGroupFacID);
|
|
|
|
float size=nodeSize*0.25f; Vector3 pos=grid[x][z].GetPos()+new Vector3(0, .1f, 0);
|
|
Gizmos.DrawLine(pos+new Vector3(1, 0, 1).normalized*size, pos-new Vector3(1, 0, 1).normalized*size);
|
|
Gizmos.DrawLine(pos+new Vector3(-1, 0, 1).normalized*size, pos-new Vector3(-1, 0, 1).normalized*size);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if(abilityTargetList.Count>0){
|
|
Gizmos.color=Color.yellow;
|
|
for(int i=0; i<abilityTargetList.Count; i++){
|
|
Gizmos.DrawSphere(abilityTargetList[i].GetPos(), 0.4f);
|
|
}
|
|
}
|
|
else{
|
|
Gizmos.color=Color.green;
|
|
for(int i=0; i<walkableList.Count; i++){
|
|
Gizmos.DrawSphere(walkableList[i].GetPos(), 0.3f);
|
|
}
|
|
|
|
Gizmos.color=Color.red;
|
|
for(int i=0; i<attackableList.Count; i++){
|
|
Gizmos.DrawSphere(attackableList[i].GetPos(), 0.4f);
|
|
}
|
|
}
|
|
|
|
OnDrawGizmos22();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
} |