You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

354 lines
13 KiB

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Rendering;
using UnityEngine.UIElements;
using Random = UnityEngine.Random;
namespace ET
{
[Timer(TimerType.UpdateBuildingDataTimer)]
public class UpdateBuildingDataTimer : ATimer<MapComponent>
{
public override void Run(MapComponent self)
{
try
{
if (self.IsDisposed || self.Parent == null) return;
if (self.DomainScene() == null) return;
self.UpdateBuildingData().Coroutine();
}
catch(Exception ex)
{
Log.Error(ex.ToString());
}
}
}
public class MapComponentAwakeSystem : AwakeSystem<MapComponent>
{
public override void Awake(MapComponent self)
{
self.Awake();
}
}
// 以最底部为Map的数组的0,0点
[FriendClass(typeof(MapComponent))]
public static class MapComponentSystem
{
public static void Awake(this MapComponent self)
{
var gameSceneMgr = self.ZoneScene().CurrentScene().GetComponent<GameSceneManagerComponent>();
Transform mainSceneRoot = gameSceneMgr.GetRoot(GameSceneType.Main).transform;
var sceneTrans = mainSceneRoot.Find("Scene");
self.NavMesh2d = sceneTrans.GetComponent<NavMeshSurface2d>();
var mapSizeTran = mainSceneRoot.Find("MapSize");
BoxCollider2D collider2D = mapSizeTran.GetComponent<BoxCollider2D>();
var bounds = collider2D.bounds;
self.MapMinPos = bounds.min;
self.MapMaxPos = bounds.max;
self.MapSize = collider2D.size;
Transform availablePlaceObj = mapSizeTran.Find("AvailablePlaceSize");
collider2D = availablePlaceObj.GetComponent<BoxCollider2D>();
bounds = collider2D.bounds;
self.AvalablePlaceMinPos = bounds.min;
var size = collider2D.size;
float width = size.x;
float height = width / 2;
if (height > size.y)
{
height = size.y;
width = height * 2;
}
self.TileMapWidth = width;
self.TileMapHeight = height;
self.HalfTileMapWidth = self.TileMapWidth / 2;
self.HalfTileMapHeight = self.TileMapHeight / 2;
self.MaxTileX = Mathf.FloorToInt(self.TileMapWidth / self.TileWidth);
self.MaxTileY = self.MaxTileX;
self.OccupyPlaceMap = new bool[self.MaxTileX, self.MaxTileY];
self.HalfTileHeight = self.TileHeight / 2;
self.HalfTileWidth = self.TileWidth / 2;
self.BuildingRoot = GameObject.Find("SceneRoot/MainSceneRoot/Scene/Layout/BuildingRoot").transform;
self.ResourceRoot = GameObject.Find("SceneRoot/MainSceneRoot/Scene/Layout/ResourceRoot").transform;
self.PeopleRoot = GameObject.Find("SceneRoot/MainSceneRoot/PeopleRoot").transform;
// add grid
self.CreateGrid();
self.HideGrid();
// add indicator
self.CreateIndicator();
self.HideIndicator();
self.UpdateBuildingDataTimer = TimerComponent.Instance.NewRepeatedTimer(30000, TimerType.UpdateBuildingDataTimer, self);
}
public static void CreateGrid(this MapComponent self)
{
Transform mainSceneRoot = GameObject.Find("MainSceneRoot").transform;
var gridMeshObj = mainSceneRoot.Find("GridMesh").gameObject;
MeshRenderer meshRenderer = gridMeshObj.AddComponent<MeshRenderer>();
meshRenderer.material = new Material(Shader.Find("Sprites/Default"));
meshRenderer.material.color = new Color(0.9f, 0.9f, 0.9f, 0.5f);
self.GridMeshFilter = gridMeshObj.AddComponent<MeshFilter>();
self.GridMesh = new Mesh();
var verticies = new List<Vector3>();
var indicies = new List<int>();
// 以最底部为Map的数组的0,0点
var halfTileWidth = self.HalfTileWidth;
var halfTileHeight = self.HalfTileHeight;
// for coloum
for (int i = 0; i <= self.MaxTileY; i++)
{
float beginX = i * halfTileWidth;
float beginY = -self.HalfTileMapHeight + i * halfTileHeight;
float endX = -self.HalfTileMapWidth + i * halfTileWidth;
float endY = i * halfTileHeight;
Vector3 start = new Vector3(beginX, beginY, 0);
Vector3 end = new Vector3(endX, endY, 0);
verticies.Add(start);
verticies.Add(end);
indicies.Add(i * 2);
indicies.Add(i*2 + 1);
}
int offset = verticies.Count;
// for row
for (int i = 0; i <= self.MaxTileX; i++)
{
float beginX = -i * halfTileWidth;
float beginY = -self.HalfTileMapHeight + i * halfTileHeight;
float endX = self.HalfTileMapWidth - i * halfTileWidth;
float endY = i * halfTileHeight;
Vector3 start = new Vector3(beginX, beginY, 0);
Vector3 end = new Vector3(endX, endY, 0);
verticies.Add(start);
verticies.Add(end);
indicies.Add(offset + i * 2);
indicies.Add(offset + i * 2 + 1);
}
self.GridMesh.vertices = verticies.ToArray();
self.GridMesh.SetIndices(indicies.ToArray(), MeshTopology.Lines, 0);
self.GridMeshFilter.mesh = self.GridMesh;
}
public static void ShowGrid(this MapComponent self)
{
self.GridMeshFilter.gameObject.SetActive(true);
}
public static void HideGrid(this MapComponent self)
{
self.GridMeshFilter.gameObject.SetActive(false);
}
public static Vector2 MapToWorldPos(this MapComponent self, int row, int col)
{
Vector2 worldPos = new Vector2();
worldPos.x = (col - row) * self.HalfTileWidth;
worldPos.y = -self.HalfTileMapHeight + (row + col) * self.HalfTileHeight;
return worldPos;
}
public static Vector2Int WorldToMapPos(this MapComponent self, Vector2 worldPos)
{
Vector2Int mapPos = new Vector2Int();
var offsetY = worldPos.y + self.HalfTileMapHeight;
mapPos.x = Mathf.RoundToInt(offsetY / self.TileHeight - worldPos.x / self.TileWidth);
mapPos.y = Mathf.RoundToInt(worldPos.x / self.TileWidth + offsetY / self.TileHeight);
mapPos.x = Mathf.Clamp(mapPos.x, 0, self.MaxTileX);
mapPos.y = Mathf.Clamp(mapPos.y, 0, self.MaxTileY);
return mapPos;
}
public static void CreateIndicator(this MapComponent self)
{
self.OccupyPlaceInidcator = BuildingViewHelper.CreateOcupyPlaceInicator("OccupyPlaceIndicator", self.ValidColor);
self.OccupyPlaceIndicatorMR = self.OccupyPlaceInidcator.GetComponent<MeshRenderer>();;
}
public static RectIndices GetUnitRectIndices(this MapComponent self, Vector3 worldPos, Vector2Int size)
{
RectIndices rectIndices = new();
// 坐标原点在底部中心
Vector2Int bottomPos = self.WorldToMapPos(worldPos);
rectIndices.startRow = bottomPos.x;
rectIndices.endRow = Mathf.Min(bottomPos.x + size.x, self.MaxTileX);
rectIndices.startCol = bottomPos.y;
rectIndices.endCol = Mathf.Min(bottomPos.y + size.y, self.MaxTileY);
return rectIndices;
}
// 以传入的点为中心的一个矩形范围
public static RectIndices GetUnitRectIndicesOfCenter(this MapComponent self, Vector3 worldPos, Vector2Int size)
{
RectIndices rectIndices = new();
// 坐标原点在底部中心
Vector2Int bottomPos = self.WorldToMapPos(worldPos);
int halfSizeX = size.x / 2;
int halfSizeY = size.y / 2;
rectIndices.startRow = Mathf.Max(bottomPos.x - halfSizeX, 0);
rectIndices.endRow = Mathf.Min(bottomPos.x + halfSizeX, self.MaxTileX);
rectIndices.startCol = Mathf.Max(bottomPos.y - halfSizeY, 0);
rectIndices.endCol = Mathf.Min(bottomPos.y + halfSizeY, self.MaxTileY);
return rectIndices;
}
public static bool IsPosInRect(this MapComponent self, Vector2Int pos, RectIndices rectIndices)
{
if (pos.x >= rectIndices.startRow &&
pos.x < rectIndices.endRow &&
pos.y >= rectIndices.startCol &&
pos.y < rectIndices.endCol)
{
return true;
}
return false;
}
public static bool CheckPlaceValid(this MapComponent self, ref RectIndices rectIndices)
{
for (int i = rectIndices.startRow; i < rectIndices.endRow; i++)
{
for (int j = rectIndices.startCol; j < rectIndices.endCol; j++)
{
if (self.OccupyPlaceMap[i, j])
{
return false;
}
}
}
return true;
}
public static bool IsPlaceValid(this MapComponent self, Vector3 worldPos, Vector2Int size)
{
RectIndices rectIndices = self.GetUnitRectIndices(worldPos, size);
return self.CheckPlaceValid(ref rectIndices);
}
public static void UpdateIndicator(this MapComponent self,Vector3 worldPos, Vector2Int size)
{
var isValid = self.IsPlaceValid(worldPos, size);
if (isValid)
{
self.OccupyPlaceIndicatorMR.material.color = self.ValidColor;
}
else
{
self.OccupyPlaceIndicatorMR.material.color = self.InvalidColor;
}
BuildingViewHelper.UpdateIndicatorLocal(self.OccupyPlaceInidcator, self, worldPos, size);
}
public static void ShowIndicator(this MapComponent self)
{
self.OccupyPlaceInidcator.SetActive(true);
}
public static void HideIndicator(this MapComponent self)
{
self.OccupyPlaceInidcator.SetActive(false);
}
// 对齐坐标到格子上
public static Vector3 AlignPlacePosition(this MapComponent self, Vector3 worldPos, Vector2Int size)
{
Vector2Int bottomPos = self.WorldToMapPos(worldPos);
int x = Mathf.Clamp(bottomPos.x, 0, self.MaxTileX - size.x);
int y = Mathf.Clamp(bottomPos.y, 0, self.MaxTileY - size.y);
return self.MapToWorldPos(x, y);
}
public static void MarkPlaceOnGrid(this MapComponent self, Vector3 pos, Vector2Int size, bool marked = true)
{
RectIndices rectIndices = self.GetUnitRectIndices(pos, size);
for (int i = rectIndices.startRow; i < rectIndices.endRow; i++)
{
Mathf.Clamp(i, 0, self.MaxTileX - 1);
for (int j = rectIndices.startCol; j < rectIndices.endCol; j++)
{
Mathf.Clamp(j, 0, self.MaxTileY - 1);
self.OccupyPlaceMap[i, j] = marked;
}
}
}
public static void UpdateNavMesh2d(this MapComponent self)
{
self.NavMesh2d.BuildNavMesh();
}
// sprite的局部坐标系的原点为底部中点
public static Vector2Int LocalToMapPos(this MapComponent self, Vector2 topPos)
{
Vector2Int mapPos = new Vector2Int();
var tileWidth = self.TileWidth;
var tileHeight = self.TileHeight;
int row = Mathf.RoundToInt(topPos.y / tileHeight - topPos.x / tileWidth);
int col = Mathf.RoundToInt(topPos.y / tileHeight + topPos.x / tileWidth);
mapPos.x = row;
mapPos.y = col;
return mapPos;
}
public static Vector2 MapToLocalPos(this MapComponent self, int row, int col)
{
Vector2 localPos = new Vector2();
localPos.x = (col - row) * self.HalfTileWidth;
localPos.y = (row + col) * self.HalfTileHeight;
return localPos;
}
public static Vector2Int GetSizeBySpriteCollider(this MapComponent self, SpriteRenderer spriteRenderer)
{
PolygonCollider2D polygonCollider2D = spriteRenderer.GetComponent<PolygonCollider2D>();
if (polygonCollider2D == null)
{
Log.Warning("Sprite don't has a polygoncollider");
return Vector2Int.zero;
}
// 2 约定为多边形碰撞盒的顶点, 由工具生成
Vector2Int size = self.LocalToMapPos(polygonCollider2D.points[2]);
return size;
}
public static async ETTask UpdateBuildingData(this MapComponent self)
{
Unit unit = UnitHelper.GetMyUnitFromZoneScene(self.ZoneScene());
await BuildingHelper.GetBuildingDurable(unit);
}
}
}