| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using Newtonsoft.Json;
- /**
- 狼的行动区域,为了避免狼的行动目的坐标重合的问题。
- */
- public class WolfActGrid : MonoBehaviour
- {
- [SerializeField] TextAsset jsonText;
- JsonConfig config;
- [System.NonSerialized] public AreaMatrix areaMatrix = new AreaMatrix();
- [SerializeField] Material[] sphereMaterials;
- public static WolfActGrid ins;
- //调试绘制模式-手动开关
- bool debugDrawing = false;
- //调试-生成新的地域矩阵,不从配置中读取
- bool debugNewAreaMatrix = false;
- void Awake()
- {
- ins = this;
- areaMatrix.wolfActGrid = this;
- config = JsonConfig.Load(jsonText.text);
- if (debugNewAreaMatrix) {
- createAreaMatrix();
- } else {
- loadAreaMatrix();
- }
- }
- //从配置中加载地域矩阵(前提是有保存在json配置文件内)
- void loadAreaMatrix() {
- List<List<Vector3>> posMatrix = areaMatrix.posMatrix = config.GetPosMatrix();
- config.SetPosMatrixNull();
- for (int r = 0; r < posMatrix.Count; r++) {
- for (int c = 0; c < posMatrix[r].Count; c++) {
- Vector3 pos = posMatrix[r][c];
- DebugDrawSphere(pos, r, c);
- }
- }
- }
- //动态创建地域矩阵
- void createAreaMatrix() {
- float circleRadius = 0.6f;
- Vector3 standardPosition = transform.position;
- Vector3 standardPointer = transform.forward;
- float minAngleY = -14f;
- float maxAngleY = 16f;
- for (float distance = 11.5f; distance <= 50f; distance += circleRadius * 2) {
- List<Vector3> posList = new List<Vector3>();
- areaMatrix.posMatrix.Add(posList);
- float sinValue = circleRadius / distance;
- float deltaAngle = 2f * Mathf.Asin(sinValue) / Mathf.PI * 180f;
- for (int col = 0; ; col++) {
- float angleY = minAngleY + deltaAngle * col;
- if (angleY > maxAngleY) break;
- Vector3 pointer = Quaternion.AngleAxis(angleY, Vector3.up) * standardPointer;
- Vector3 pointerWithLen = pointer * distance;
- Vector3 newPos = standardPosition + pointerWithLen;
- #region 射线检测是否被树遮挡
- float checkRayDistance = 60f;
- Vector3 rayPos = newPos;
- Vector3 rayDir = Quaternion.AngleAxis(180, Vector3.up) * pointer;
- if (Physics.Raycast(rayPos, rayDir, checkRayDistance, LayerMask.GetMask("Test"))) {
- continue;
- }
- Vector3 pointerWithLen1 = Quaternion.AngleAxis(-deltaAngle / 3f, Vector3.up) * pointerWithLen;
- Vector3 rayPos1 = standardPosition + pointerWithLen1;
- Vector3 rayDir1 = Quaternion.AngleAxis(180, Vector3.up) * pointerWithLen1;
- if (Physics.Raycast(rayPos1, rayDir1, checkRayDistance, LayerMask.GetMask("Test"))) {
- continue;
- }
- Vector3 pointerWithLen2 = Quaternion.AngleAxis(deltaAngle / 3f, Vector3.up) * pointerWithLen;
- Vector3 rayPos2 = standardPosition + pointerWithLen2;
- Vector3 rayDir2 = Quaternion.AngleAxis(180, Vector3.up) * pointerWithLen2;
- if (Physics.Raycast(rayPos2, rayDir2, checkRayDistance, LayerMask.GetMask("Test"))) {
- continue;
- }
- #endregion
- posList.Add(newPos);
- DebugDrawSphere(newPos, areaMatrix.posMatrix.Count - 1, posList.Count - 1);
- }
- }
- }
- void DebugDrawSphere(Vector3 pos, int r, int c) {
- if (!debugDrawing) return;
- GameObject sphere = transform.Find("Sphere").gameObject;
- GameObject o = GameObject.Instantiate(sphere, pos, Quaternion.identity, transform);
- o.name = r + "_" + c;
- o.SetActive(true);
- o.AddComponent<WolfActGridCell>().pos = pos;
- }
- public void DebugOccupySphere(string name, bool occupy) {
- if (!debugDrawing) return;
- transform.Find(name).GetComponent<MeshRenderer>().material = occupy ? sphereMaterials[1] : sphereMaterials[0];
- }
- //提供给狼的接口,扑击结束后,跑回的地点
- int runBackPointIndex = -1;
- public Vector3 GetRunBackPointAfterPounce() {
- if (runBackPointIndex == -1) runBackPointIndex = Random.Range(0, 2);
- runBackPointIndex++;
- return this.transform.Find("RunBackPoint" + (runBackPointIndex % 2)).position;
- }
- public class AreaMatrix {
- public List<List<Vector3>> posMatrix = new List<List<Vector3>>();
- //格式:"行_列"
- public Dictionary<object, string> occupyDC = new Dictionary<object, string>();
- public WolfActGrid wolfActGrid;
- //计算水平距离
- float calDis(Vector3 p1, Vector3 p2) {
- return Mathf.Sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.z - p2.z) * (p1.z - p2.z));
- }
- // 占用距离最近的格子,如果最近的被占用则广度优先寻找附近较近的格子
- public bool occupyPos(Vector3 p, object obj) {
- float minDis = float.MaxValue;
- int bestR = 0;
- int bestC = 0;
- for (int r = 0; r < posMatrix.Count; r++) {
- for (int c = 0; c < posMatrix[r].Count; c++) {
- Vector3 pos = posMatrix[r][c];
- float dis = calDis(pos, p);
- if (dis < minDis) {
- minDis = dis;
- bestR = r;
- bestC = c;
- }
- }
- }
- object cur_occupy_obj = checkOccupy(bestR, bestC);
- //如果目标格子被其它对象占用,则过渡优先寻找附近的格子,因为矩阵是扇形,目前的fbs有偏差,但无妨
- if (cur_occupy_obj != null && !obj.Equals(cur_occupy_obj)) {
- int sr = bestR;
- int sc = bestC;
- List<string> openList = new List<string>();
- openList.Add(sr + "_" + sc);
- int scanIndex = 1;
- bool breakBFS = false;
- while (true) {
- int i = 0;
- while (i < 8) {
- i++;
- if (i == 1) { sc++; }
- if (i == 2) { sr--; }
- if (i == 3) { sc--; }
- if (i == 4) { sc--; }
- if (i == 5) { sr++; }
- if (i == 6) { sr++; }
- if (i == 7) { sc++; }
- if (i == 8) { sc++; }
- if (sr >= 0 && sr < posMatrix.Count && sc >= 0 && sc < posMatrix[sr].Count) {
- string keyName = sr + "_" + sc;
- if (!openList.Contains(keyName)) {
- object now_occupy_obj = checkOccupy(sr, sc);
- if (now_occupy_obj == null || obj.Equals(now_occupy_obj)) {
- bestR = sr;
- bestC = sc;
- breakBFS = true;
- break;
- }
- //加入
- openList.Add(keyName);
- }
- }
- }
- if (breakBFS) break;
- if (scanIndex < openList.Count) {
- string[] str = openList[scanIndex].Split('_');
- scanIndex++;
- sr = int.Parse(str[0]);
- sc = int.Parse(str[1]);
- } else {
- return false;
- }
- }
- }
- //找到最佳的格子
- Vector3 bestPoint = posMatrix[bestR][bestC];
- p.x = bestPoint.x;
- p.z = bestPoint.z;
- //释放自己以前占用的格子
- releaseOccupy(obj);
- //占用目标格子
- Occupy(bestR, bestC, obj);
- return true;
- }
- public object checkOccupy(int r, int c) {
- string keyName = r + "_" + c;
- foreach (var item in occupyDC)
- {
- if (item.Value.Equals(keyName)) return item.Key;
- }
- return null;
- }
- public void releaseOccupy(object obj) {
- string keyName = null;
- occupyDC.TryGetValue(obj, out keyName);
- if (keyName == null) {
- return;
- }
- occupyDC.Remove(obj);
- wolfActGrid.DebugOccupySphere(keyName, false);
- }
- public void Occupy(int r, int c, object obj) {
- string keyName = r + "_" + c;
- occupyDC[obj] = keyName;
- wolfActGrid.DebugOccupySphere(keyName, true);
- if (!wolfActGrid.debugDrawing) return;
- if (obj.GetType().Equals(typeof(Wolf))) {
- Wolf wolf = (Wolf) obj;
- WolfLineRender wolfLineRender = wolf.GetComponentInChildren<WolfLineRender>();
- if (!wolfLineRender) {
- GameObject prefab = wolfActGrid.transform.Find("WolfLineRender").gameObject;
- GameObject o = GameObject.Instantiate(prefab, wolf.transform.position + Vector3.up * 0.8f, Quaternion.identity, wolf.transform);
- wolfLineRender = o.GetComponent<WolfLineRender>();
- o.SetActive(true);
- }
- wolfLineRender.SetDestination(posMatrix[r][c]);
- }
- }
- }
- class JsonConfig {
- public string posMatrix = null;
- //清空,避免占用内存
- public void SetPosMatrixNull() {
- posMatrix = null;
- }
- public List<List<Vector3>> GetPosMatrix() {
- string[] lines = posMatrix.Split('\n');
- List<List<Vector3>> list = new List<List<Vector3>>();
- foreach (var line in lines)
- {
- if (line.Trim().Length == 0) continue;
- string[] vectorStrs = line.Split(' ');
- List<Vector3> childList = new List<Vector3>();
- foreach (var vectorStr in vectorStrs)
- {
- string[] valStrs = vectorStr.Split('_');
- Vector3 vec = new Vector3(
- float.Parse(valStrs[0]),
- float.Parse(valStrs[1]),
- float.Parse(valStrs[2])
- );
- childList.Add(vec);
- }
- list.Add(childList);
- }
- return list;
- }
- public void SetPosMatrix(List<List<Vector3>> list) {
- posMatrix = "";
- for (int i = 0; i < list.Count; i++) {
- for (int j = 0; j < list[i].Count; j++) {
- Vector3 pos = list[i][j];
- posMatrix += pos.x + "_" + pos.y + "_" + pos.z;
- if (j < list[i].Count - 1) posMatrix += " ";
- }
- if (i < list.Count - 1) posMatrix += "\n";
- };
- }
- public void Write() {
- string filePath =
- "E:\\UnityProject\\SmartBow\\Assets\\BowArrow\\Scripts\\GameChallenge\\WoldActGird\\WolfActGrid.json";
- if (!System.IO.File.Exists(filePath)) {
- Debug.LogError("JsonConfig-File-NotExist");
- return;
- }
- try
- {
- System.IO.StreamWriter writer = new System.IO.StreamWriter(filePath);
- writer.Write(JsonConvert.SerializeObject(this));
- writer.Close();
- }
- catch (System.Exception e)
- {
- Debug.LogError("JsonConfig-Write-Fail");
- Debug.LogError(e.Message);
- }
- }
- public static JsonConfig Load(string jsonText) {
- JsonConfig jsonConfig = JsonConvert.DeserializeObject<JsonConfig>(jsonText);
- if (jsonConfig == null) jsonConfig = new JsonConfig();
- return jsonConfig;
- }
- }
- [ContextMenu("SaveJsonConfig")]
- void SaveJsonConfig() {
- config.SetPosMatrix(areaMatrix.posMatrix);
- config.Write();
- Debug.LogWarning("网格配置保存成功");
- }
- }
|