标签:作用 for position single hid public base coding math
设置Object属性
a)点击Bake烘焙出地图网络信息 b)烘焙后的网络信息图
1 using System.IO; 2 using UnityEditor; 3 using UnityEngine.SceneManagement; 4 using UnityEngine; 5 6 namespace AStar 7 { 8 //navmesh导出数据 9 public class NavMeshExport : MonoBehaviour 10 { 11 [MenuItem("NavMesh/Export")] 12 static void Export() 13 { 14 Debug.Log("NavMesh Export Start"); 15 16 UnityEngine.AI.NavMeshTriangulation navMeshTriangulation = UnityEngine.AI.NavMesh.CalculateTriangulation(); 17 18 //文件路径 19 string path = Application.dataPath /*+ "/AStar/obj/"*/ + SceneManager.GetActiveScene().name + ".obj"; 20 21 //新建文件 22 StreamWriter streamWriter = new StreamWriter(path); 23 24 //顶点 25 for (int i = 0; i < navMeshTriangulation.vertices.Length; i++) 26 { 27 streamWriter.WriteLine("v " + navMeshTriangulation.vertices[i].x + " " + navMeshTriangulation.vertices[i].y + " " + navMeshTriangulation.vertices[i].z); 28 } 29 30 streamWriter.WriteLine("g pPlane1"); 31 32 //索引 33 for (int i = 0; i < navMeshTriangulation.indices.Length;) 34 { 35 streamWriter.WriteLine("f " + (navMeshTriangulation.indices[i] + 1) + " " + (navMeshTriangulation.indices[i + 1] + 1) + " " + (navMeshTriangulation.indices[i + 2] + 1)); 36 i = i + 3; 37 } 38 39 streamWriter.Flush(); 40 streamWriter.Close(); 41 42 43 AssetDatabase.Refresh(); 44 45 Debug.Log("NavMesh Export Success"); 46 } 47 } 48 }
导出后的obj图
导出二维坐标代码:1 using UnityEngine; 2 using System.Collections; 3 using System.IO; 4 using System.Text; 5 using UnityEditor; 6 using UnityEngine.SceneManagement; 7 using UnityEngine; 8 9 public class NavArrayExport: MonoBehaviour 10 { 11 #region Public Attributes 12 public Vector3 leftUpStart = Vector3.zero; 13 public float accuracy = 1; 14 public int height = 30; 15 public int wide = 30; 16 public float maxdistance = 0.2f; 17 public float kmin = -10; 18 public float kmax = 20; 19 #endregion 20 21 22 #region Public Methods 23 24 public void Exp() 25 { 26 exportPoint(leftUpStart, wide, height, accuracy); 27 } 28 29 public float ConvertToNearestHalfNum(float num) 30 { 31 float numFloor = Mathf.Floor(num); 32 float half = 0.5f; 33 float d1 = num - numFloor; 34 float d2 = Mathf.Abs(num - (numFloor + half)); 35 float d3 = numFloor + 1 - num; 36 float d = Mathf.Min(d1, d2, d3); 37 if(d == d1) 38 { 39 return numFloor; 40 } 41 else if(d == d2) 42 { 43 return numFloor + 0.5f; 44 } 45 else 46 { 47 return numFloor + 1f; 48 } 49 } 50 51 public void exportPoint(Vector3 startPos, int x, int y, float accuracy) 52 { 53 StringBuilder str = new StringBuilder(); 54 int[,] list = new int[x, y]; 55 str.Append("[MAP_DESC]\r\n"); 56 str.Append("startpos=").Append(startPos).Append("\r\n"); 57 str.Append("height=").Append(y).Append("\r\nwide=").Append(x).Append("\r\naccuracy=").Append(accuracy).Append("\r\n"); 58 for (int j = 0; j < y; ++j) 59 { 60 for (int i = 0; i < x; ++i) 61 { 62 UnityEngine.AI.NavMeshHit hit; 63 for (float k = kmin; k < kmax; k+=0.5f) 64 { 65 Vector3 p = startPos + new Vector3(i * accuracy, k, -j * accuracy); 66 if (UnityEngine.AI.NavMesh.SamplePosition(p, out hit, maxdistance, UnityEngine.AI.NavMesh.AllAreas)) 67 { 68 //Debug.DrawRay(new Vector3(ConvertToNearestHalfNum(hit.position.x), hit.position.y, ConvertToNearestHalfNum(hit.position.z)), Vector3.up, Color.green); 69 list[(int)(ConvertToNearestHalfNum(hit.position.x) * 2), (int)(ConvertToNearestHalfNum(hit.position.z) * 2)] = 1; 70 break; 71 } 72 } 73 } 74 } 75 str.Append("map="); 76 for (int j = 0; j < y; ++j) 77 { 78 str.Append("["); 79 for (int i = 0; i < x; ++i) 80 { 81 str.Append(Mathf.Abs(1 - list[i, j])).Append(","); 82 } 83 str.Append("],"); 84 } 85 //文件路径 86 string path = Application.dataPath + SceneManager.GetActiveScene().name + ".ini"; 87 88 //新建文件 89 StreamWriter streamWriter = new StreamWriter(path); 90 streamWriter.Write(str.ToString()); 91 streamWriter.Flush(); 92 streamWriter.Close(); 93 94 95 AssetDatabase.Refresh(); 96 } 97 #endregion 98 99 } 100 101 [CustomEditor(typeof(NavArrayExport))] 102 public class NavArrayExportHelper: Editor 103 { 104 public override void OnInspectorGUI() 105 { 106 base.OnInspectorGUI(); 107 if (GUILayout.Button("Export")) 108 { 109 var exp = target as NavExport; 110 exp.Exp(); 111 } 112 } 113 }
导出的二维坐标表
解决了客户端导出的地图信息后,服务端只需要通过获取客户端发送过来的start_pos和end_pos,并通过这两个点执行寻路逻辑,然后得到一串路径点,然后将这些路径点返回给客户端,客户端通过路径点执行对应人物的方向行走即可。不过要注意的是,这里客户端之所以是通过方向行走而不是直接走到那个路径点是因为我们是忽略了高度的因素)
1 #!/bin/env python 2 # -*- coding:utf8 -*- 3 import os 4 import ConfigParser 5 import numpy 6 from heapq import * 7 from vector3 import Vector3 8 from triangle import Triangle 9 from math_tools import MathTools 10 from common.singleton import Singleton 11 from common.logger import Logger 12 class Navmesh(Singleton): 13 ‘‘‘ 14 服务端寻路组件 15 ‘‘‘ 16 def __init__(self): 17 self.vertices = [] 18 self.indices = [] 19 self.all_triangles = [] # 所有三角形 20 self.all_center_o = [] # 所有三角形的重心 21 self.point_2_triangles = {} # 点包含的三角形列表集合 22 23 # obj_file 24 dir = os.path.dirname(os.path.realpath(__file__)) 25 #self.map_obj_file_name = ‘{}/{}‘.format(dir,‘test.obj‘) 26 self.map_obj_file_name = ‘{}/{}‘.format(dir,‘AssetsDeserScene.obj‘) 27 28 29 def load(self): 30 with open(self.map_obj_file_name, ‘r+‘) as f: 31 Logger().I(‘loading map data({})...‘.format(self.map_obj_file_name)) 32 lines = f.readlines() 33 for line in lines: 34 for kv in [line.strip().split(‘ ‘)]: 35 if kv[0] == ‘v‘: 36 self.vertices.append(Vector3(float(kv[1]),float(kv[2]),float(kv[3]))) 37 elif kv[0] == ‘f‘: 38 a = int(kv[1])-1 39 b = int(kv[2])-1 40 c = int(kv[3])-1 41 t = Triangle(self.vertices[a], self.vertices[b], self.vertices[c]) 42 self.indices.append(Vector3(a,b,c)) 43 self.all_triangles.append(t) 44 self.all_center_o.append(t.o) 45 46 if t.a not in self.point_2_triangles: 47 self.point_2_triangles[t.a] = [t] 48 elif t not in self.point_2_triangles[t.a]: 49 self.point_2_triangles[t.a].append(t) 50 51 if t.b not in self.point_2_triangles: 52 self.point_2_triangles[t.b] = [t] 53 elif t not in self.point_2_triangles[t.b]: 54 self.point_2_triangles[t.b].append(t) 55 56 if t.c not in self.point_2_triangles: 57 self.point_2_triangles[t.c] = [t] 58 elif t not in self.point_2_triangles[t.c]: 59 self.point_2_triangles[t.c].append(t) 60 61 return True 62 63 def load_map_array(self): 64 conf = ConfigParser.ConfigParser() 65 conf.read(‘map/AssetsDeserScene.ini‘) 66 map_data = conf.get(‘MAP_DESC‘,‘map‘) 67 self.h = conf.getint(‘MAP_DESC‘,‘height‘) 68 self.w = conf.getint(‘MAP_DESC‘,‘wide‘) 69 self.accuracy = conf.getfloat(‘MAP_DESC‘,‘accuracy‘) 70 self.nmap = numpy.array(eval(map_data)) 71 72 def convert_pos_to_arr_idx(self, v_pos): 73 #(0,0,700)->(0,0) 74 #(100,0,700)->(0,199) 75 #(100,0,600)->(199,199) 76 x = (self.h - MathTools.convert_to_half_num(v_pos.z)) * self.accuracy - 1 77 z = MathTools.convert_to_half_num(v_pos.x) * self.accuracy - 1 78 return (int(x), int(z)) 79 80 def convert_arr_idx_to_pos(self, idx): 81 return Vector3((idx[1] + 1) / self.accuracy, 0, self.h - (idx[0] + 1)/self.accuracy) 82 83 def calulate_path_array(self, start_pos, end_pos): 84 ‘‘‘ 85 通过二维数组的地图数据寻路 86 @paramIn: [Vector3] start_pos 87 @paramIn: [Vector3] end_pos 88 ‘‘‘ 89 start = self.convert_pos_to_arr_idx(start_pos) 90 end = self.convert_pos_to_arr_idx(end_pos) 91 res = MathTools.astar(self.nmap, start, end) 92 93 paths = [] 94 95 if res is False or len(res) == 0: 96 # 找不到就直接走向end 97 paths.append(end_pos) 98 return paths 99 100 # 将点路径转化为线段路径 101 res.reverse() 102 paths.append(self.convert_arr_idx_to_pos(res[0])) 103 if len(res) > 1: 104 for i in xrange(1,len(res)): 105 if MathTools.check_points_in_line(start,res[i-1],res[i]): 106 paths[-1] = self.convert_arr_idx_to_pos(res[i]) 107 else: 108 # 斜率开始不一样,则添加最新的点 109 paths.append(self.convert_arr_idx_to_pos(res[i])) 110 start = res[i-1] 111 return paths 112 113 114 115 116 def calulate_path(self, start_pos, end_pos): 117 open_list = [] 118 close_list = [] 119 start_pos_triangle = Triangle(start_pos, start_pos, start_pos) 120 end_pos_triangle = Triangle(end_pos, end_pos, end_pos) 121 122 start_triangle, start_pos = MathTools.fix_border_point_if_needed(start_pos, self.all_triangles) 123 end_triangle, start_pos = MathTools.fix_border_point_if_needed(end_pos, self.all_triangles) 124 rv_path = {} 125 if start_triangle is None: 126 #Logger().W(‘start_pos is not in the navmesh‘) 127 return None 128 if end_triangle is None: 129 #Logger().W(‘end_pos is not in the navmesh‘) 130 return None 131 132 f = {} 133 g = {} 134 h = {} 135 136 open_list.append(start_pos_triangle) 137 138 while end_pos_triangle not in open_list and len(open_list) != 0: 139 # step 1. get the min triangle in open_list 140 t = open_list[0] 141 for i in xrange(0, len(open_list)): 142 if open_list[i] not in f: 143 f[open_list[i]] = 0 144 if f[t] > f[open_list[i]]: 145 t = open_list[i] 146 147 # step 2. remove the triangle from the open_list 148 open_list.remove(t) 149 150 # step 3. append the triangle to the close_list 151 close_list.append(t) 152 153 # step 4. explore 154 155 # step 4.1. get round triangles 156 current = t 157 if current == start_pos_triangle: 158 current = start_triangle 159 round_triangles = [] 160 161 if current.a in self.point_2_triangles: 162 round_triangles = round_triangles + self.point_2_triangles[current.a] 163 if current.b in self.point_2_triangles: 164 round_triangles = round_triangles + self.point_2_triangles[current.b] 165 if current.c in self.point_2_triangles: 166 round_triangles = round_triangles + self.point_2_triangles[current.c] 167 168 # remove dulplicate triangles 169 round_triangles = sorted(set(round_triangles),key=round_triangles.index) 170 if end_triangle in round_triangles: 171 round_triangles.append(end_pos_triangle) 172 173 # step 4.2 174 for i in xrange(0, len(round_triangles)): 175 round_triangle = round_triangles[i] 176 177 if round_triangle is t: 178 continue 179 180 if round_triangle in close_list: 181 continue 182 183 if round_triangle not in open_list: 184 rv_path[round_triangle] = t 185 if t not in g: 186 g[t] = 0 187 g[round_triangle] = g[t] + MathTools.distance(t.o,round_triangle.o) 188 h[round_triangle] = MathTools.distance(round_triangle.o, end_pos) 189 open_list.append(round_triangle) 190 else: 191 if round_triangle not in g: 192 g[round_triangle] = 0 193 if round_triangle not in h: 194 h[round_triangle] = 0 195 G = g[round_triangle] 196 H = h[round_triangle] 197 F = g[round_triangle] + MathTools.distance(round_triangle.o, t.o) + MathTools.distance(round_triangle.o, end_pos) 198 if G + H > F: 199 rv_path[round_triangle] = t 200 g[round_triangle] = g[t] + MathTools.distance(t.o,round_triangle.o) 201 h[round_triangle] = MathTools.distance(round_triangle.o, end_pos) 202 open_list.remove(round_triangle) 203 204 path_list = [] 205 t = end_pos_triangle 206 while t in rv_path and rv_path[t] is not None: 207 path_list.append(t.o) 208 t = rv_path[t] 209 210 path_list.reverse() 211 212 return path_list 213 214 215 # start_pos =Vector3(315.976135254,11.0661716461,360.217041016) 216 # end_pos = Vector3(315.970001221,11.86622715,350.790008545) 217 # nav = Navmesh() 218 # nav.load_map_array() 219 # print nav.calulate_path_array(start_pos,end_pos) 220 221 # start_pos = Vector3(-2.3, 0.3, -2.8) 222 # end_pos = Vector3(3.2, 0.0, -2.8) 223 # print nav.calulate_path(start_pos, end_pos) 224 225 # (-0.3, 0.1, -3.9) 226 # (1.7, 0.1, -4.2) 227 # (3.2, 0.1, -2.8)
三角网络很大的情况
标签:作用 for position single hid public base coding math
原文地址:https://www.cnblogs.com/leothzhang/p/svr_nav.html