/// 加载XML至路标点 <summary> /// 加载XML至路标点 /// </summary> /// <param name="xmlFileName">xml文件名(不包含路径)</param> /// <param name="all">路标点集合(父物体)</param> public void LoadXmlToWaypoints(WaypointMessage all, string xmlPath = null, string xmlString = null) { WaypointsXML temWaypointsXML = new WaypointsXML(); WaypointsModel temWM = new WaypointsModel(); int number = 0; all.WaypointsModelAll.Clear(); //销毁子物体 DestroyChild(all.transform); //获取XML数据至集合 temWaypointsXML.GetXmlData(all.WaypointsModelAll, xmlPath, xmlString); for (int i = 0; i < all.WaypointsModelAll.Count; i++) { number++; //在编辑器中则创建 if (Application.platform == RuntimePlatform.WindowsEditor) { GameObject go = new GameObject(); go.transform.parent = all.transform; go.name = all.WaypointsModelAll[i].Index.ToString(); go.transform.position = all.WaypointsModelAll[i].Position; go.transform.rotation = all.WaypointsModelAll[i].Rotation; go.transform.localScale = all.WaypointsModelAll[i].Scale; } } if (Debug.isDebugBuild) { Debug.Log("【" + all.WaypointsModelAll.Count.ToString() + "】加载完成:" + all.curWaypointsXMLPath); } }
/// 保存路标点至XML<summary> /// 保存路标点至XML /// </summary> /// <param name="xmlFileName">xml文件名(不包含路径)</param> /// <param name="all">路标点集合(父物体)</param> public void SaveWaypointsToXml(WaypointMessage all, string xmlPath) { WaypointsXML temWaypointsXML = new WaypointsXML(); int number = 0; //xml是否存在,如果存在就删除 //否则会叠加 if (File.Exists(xmlPath)) { File.Delete(xmlPath); } foreach (Transform child in all.transform) { number++; WaypointsModel temWM = new WaypointsModel(); temWM.Index = int.Parse(child.transform.name); temWM.Position = child.position; temWM.Rotation = child.rotation; temWM.Scale = child.localScale; temWaypointsXML.AddXmlData(temWM, xmlPath); } //保存后刷新路标点 LoadXmlToWaypoints(all, xmlPath); if (Debug.isDebugBuild) { Debug.Log("【" + all.WaypointsModelAll.Count.ToString() + "】保存完成:" + all.curWaypointsXMLPath); } }
public async Task <ActionResult <WaypointsModel> > PostWaypoints(WaypointsModel model) { Level lvlId = _context.Levels.Where(x => x.Name == model.LevelName).FirstOrDefault(); Object enemy = _context.Objects.Where(x => x.Name.Contains("tank")).Where(x => x.LevelId == lvlId.Id).FirstOrDefault(); if (enemy != null) { int id = (int)enemy.Id; foreach (Waypoint item in model.waypoints) { item.ObjectId = id; item.LevelName = model.LevelName; _context.Waypoints.Add(item); } } else { return(NotFound()); } await _context.SaveChangesAsync(); return(Ok()); }
/// 检测反向移动 <summary> /// 检测反向移动 /// 思路如下: /// 通过Waypoint检测到离赛车最近的点 /// 然后通过计算点的距离而得出是否反向 /// </summary> private void isReverse() { WaypointsModel ClosestWP = GetClosestWP(WaypointsModelAll, transform.position);//获取距离最近的路径点 //角度偏移 = 最近路径点的角度 - 赛车的角度 float angleOffset = ClosestWP.Rotation.eulerAngles.y - transform.eulerAngles.y; /* 理论上来说 * 完全可以只写成 if(Mathf.Abs(angleOffset) >= 90f) * 则判断为反向!但是实际运用时会出现问题 * 因为赛道是围成圈形的(首尾相连) * 当赛车移动到下半圈的时候 * 明明是正确的方向,但是却提示反向了 * 所以为了避免这种情况发生,我们要用360-90=270 * 如果还是不理解的话debug路径点角度和赛车的角度就会发现端倪了*/ //角度偏移<=270f && 角度偏移>=90f && 刚体速度>8f if (Mathf.Abs(angleOffset) <= 270f && Mathf.Abs(angleOffset) >= 90f) { is_reverse = true; } else { is_reverse = false; } }
/// 添加XML数据 <summary> /// 添加XML数据 /// </summary> /// <param name="_path">欲添加路标点实体</param> /// <param name="wm">xml文件路径</param> public void AddXmlData(WaypointsModel wm, string xmlPath) { CheckXmlFile(xmlPath);//检测XML文件 if (File.Exists(xmlPath)) { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(xmlPath); XmlNode root = xmlDoc.SelectSingleNode("waypoints"); XmlElement elmNew = xmlDoc.CreateElement("waypoint"); elmNew.SetAttribute("index", wm.Index.ToString()); XmlElement position = xmlDoc.CreateElement("position"); position.InnerText = wm.Position.ToString(); XmlElement rotation = xmlDoc.CreateElement("rotation"); rotation.InnerText = wm.Rotation.ToString(); XmlElement scale = xmlDoc.CreateElement("scale"); scale.InnerText = wm.Scale.ToString(); elmNew.AppendChild(position); elmNew.AppendChild(rotation); elmNew.AppendChild(scale); root.AppendChild(elmNew); xmlDoc.AppendChild(root); xmlDoc.Save(xmlPath); } }
/// 绘制方向标识线 <summary> /// 绘制方向标识线 /// </summary> /// <param name="wp1">路标点1</param> /// <param name="wp2">路标点2</param> /// <param name="_lineWidth">标识线宽度</param> private void DrawDirLine(WaypointsModel wm1, WaypointsModel wm2, float _lineWidth) { //计算方向标识线左边的点 Vector3 dirLineLeft = wm1.Position + (wm1.Rotation * Vector3.right * (_lineWidth / 2f) * -1); //计算方向标识线右边的点 Vector3 dirLineRight = wm1.Position + (wm1.Rotation * Vector3.right * (_lineWidth / 2f)); //绘制一条连接左右两点的线 Gizmos.DrawLine(dirLineLeft, dirLineRight); //绘制方向箭头(左右两点分别绘制一条连接下个路标点的线呈三角形) Gizmos.DrawLine(dirLineLeft, wm2.Position); Gizmos.DrawLine(dirLineRight, wm2.Position); }
/// 获取距离最近的路径点 <summary> /// 获取距离最近的路径点 /// </summary> /// <param name="DPs">路径点集合</param> /// <param name="myPosition">当前坐标</param> /// <returns>返回最近距离的路标点</returns> private WaypointsModel GetClosestWP(List <WaypointsModel> all, Vector3 myPosition) { WaypointsModel tMin = null; float minDist = Mathf.Infinity;//正无穷 for (int i = 0; i < all.Count; i++) { float dist = Vector3.Distance(all[i].Position, myPosition); if (dist < minDist) { tMin = all[i]; minDist = dist; } } return(tMin); }
/// 重置赛车 <summary> /// 重置赛车 /// </summary> private void RecoverCarA() { //获取距离最近的路标点 WaypointsModel ClosestWP = GetClosestWP(WaypointsModelAll, transform.position); //置赛车位置 transform.position = ClosestWP.Position; //置车头朝向 transform.rotation = Quaternion.LookRotation(ClosestWP.Rotation * Vector3.forward); //移动速度归零 GetComponent <Rigidbody>().velocity = Vector3.zero; //角速度归零 GetComponent <Rigidbody>().angularVelocity = Vector3.zero; }
/// 圈数检测 <summary> /// 圈数检测 /// 思路如下: /// 每一帧计算距离最近的检查点 /// 检查点存在则不添加,不存在则添加 /// 冲过终点线时取数量 /// 大于最少数量则算通过一圈 /// 然后清零 CheckPoints /// </summary> private void CircleNumberCheck() { WaypointsModel ClosestWP = GetClosestWP(WaypointsModelAll, transform.position);//获取距离最近的路径点 //判断当前最近路标点是否已存在 for (int i = 0; i < CheckPoints.Count; i++) { //存在则返回 if (ClosestWP.Position == CheckPoints[i].Position) { return; } } //不存在则添加 CheckPoints.Add(ClosestWP); }
/// 获取XML数据 <summary> /// 获取XML数据 /// </summary> /// <param name="_Waypoints">保存路标点集合</param> /// <param name="xmlPath">xml文件路径</param> /// <param name="xmlString">xml文本数据</param> public void GetXmlData(List <WaypointsModel> _Waypoints, string xmlPath = null, string xmlString = null) { if (File.Exists(xmlPath) || xmlPath == null) { XmlDocument xmlDoc = new XmlDocument(); if (xmlPath == null) { xmlDoc.LoadXml(xmlString); } else { xmlDoc.Load(xmlPath); } XmlNodeList nodeList = xmlDoc.SelectSingleNode("waypoints").ChildNodes; foreach (XmlElement xml1 in nodeList) { WaypointsModel temWaypoint = new WaypointsModel(); temWaypoint.Index = Convert.ToInt32(xml1.GetAttribute("index")); foreach (XmlElement xml2 in xml1.ChildNodes) { switch (xml2.Name) { case "position": temWaypoint.Position = StringToVector3(xml2.InnerText); break; case "rotation": temWaypoint.Rotation = StringToQuaternion(xml2.InnerText); break; case "scale": temWaypoint.Scale = StringToVector3(xml2.InnerText); break; } } //添加进路标点集合 _Waypoints.Add(temWaypoint); } } }
/// 添加路标点 <summary> /// 添加路标点 /// </summary> /// <param name="all">路标点集合(父物体)</param> public void AddWaypoint(WaypointMessage all) { GameObject go = new GameObject(); go.transform.parent = all.transform; Transform[] tt = all.transform.GetComponentsInChildren <Transform>(); go.name = (tt.Length - 2).ToString(); Selection.activeTransform = go.transform; //EditorApplication.ExecuteMenuItem("GameObject/Move To View"); //go.transform.rotation = new Quaternion(0f, 0f, 0f, 0f); if (all.WaypointsModelAll != null) { if (all.WaypointsModelAll.Count <= 0) { //生成的路标点移动到视窗内 EditorApplication.ExecuteMenuItem("GameObject/Move To View"); } else { Vector3 pos = all.WaypointsModelAll[all.WaypointsModelAll.Count - 1].Position + Vector3.up * 50f; Quaternion rota = all.WaypointsModelAll[all.WaypointsModelAll.Count - 1].Rotation; //生成的路标点在最后一个路标点的前方 //当前位置 = 上个路标点位置 + 上个路标点旋转 * 世界位置前 * (最大两点距离 - 3f) go.transform.position = pos + rota * Vector3.forward * (maxWaypointDis - 3f); go.transform.rotation = all.WaypointsModelAll[all.WaypointsModelAll.Count - 1].Rotation; } } WaypointsModel wm = new WaypointsModel(); wm.Index = int.Parse(go.name); wm.Position = go.transform.position; wm.Rotation = go.transform.rotation; wm.Scale = go.transform.localScale; WaypointsModelAll.Add(wm); }
void OnDrawGizmos() { //不在编辑器中则返回 if (Application.platform != RuntimePlatform.WindowsEditor) { return; } myTransform = transform; #region 对齐地面&更新数据 //当前选择的如果是Waypoint时 if (Selection.activeTransform != null) { if (Selection.activeTransform.parent == transform) { int temIndex = int.Parse(Selection.activeTransform.name); for (int i = 0; i < WaypointsModelAll.Count; i++) { if (temIndex == WaypointsModelAll[i].Index) { //当路标点被移动时更新数据 if (i != 0) { //限制两点间最大距离 if (Mathf.Abs(Vector3.Distance(WaypointsModelAll[i - 1].Position, Selection.activeTransform.position)) < maxWaypointDis) { WaypointsModelAll[i].Position = Selection.activeTransform.position; } } else { //最后一个路标点和第一个路标点不计算最大距离 WaypointsModelAll[i].Position = Selection.activeTransform.position; } WaypointsModelAll[i].Rotation = Selection.activeTransform.rotation; WaypointsModelAll[i].Scale = Selection.activeTransform.localScale; /* * if (i != WaypointsModelAll.Count - 1) * { * Selection.activeTransform.LookAt(WaypointsModelAll[i + 1].Position); * } * else if (isAroundCircle) * { * //如果绕圈则注视起点 * Selection.activeTransform.LookAt(WaypointsModelAll[0].Position); * }*/ //对齐地面 if (alignGround) { RaycastHit[] hit; hit = Physics.RaycastAll(WaypointsModelAll[i].Position, WaypointsModelAll[i].Rotation * -Vector3.up, 100f);//起始位置、方向、距离 #region 获取碰撞到的所有物体 for (int i1 = 0; i1 < hit.Length; i1++) { //当碰撞到的物体为地面时 if (hit[i1].transform.tag == "Map_ground") { //计算当前路标点与地面之间的距离 float temDis = Vector3.Distance(WaypointsModelAll[i].Position, hit[i1].point); //调整距离 Selection.activeTransform.position = new Vector3( WaypointsModelAll[i].Position.x, WaypointsModelAll[i].Position.y - (temDis - disGround), WaypointsModelAll[i].Position.z); //Debug.Log(temDis); //绘制高度线 Debug.DrawRay(WaypointsModelAll[i].Position, WaypointsModelAll[i].Rotation * -Vector3.up * temDis, Color.red); break; } } #endregion } break; } } } } #endregion WaypointsModelAll.Clear(); Transform lastTransform = null;//上次路标点 foreach (Transform child in transform) { //上次路标点不为null时注视本次路标点 if (lastTransform != null) { lastTransform.LookAt(child.position); } lastTransform = child; WaypointsModel temWM = new WaypointsModel(); temWM.Index = int.Parse(child.transform.name); temWM.Position = child.position; temWM.Rotation = child.rotation; temWM.Scale = child.localScale; WaypointsModelAll.Add(temWM); } Gizmos.color = lineColor; for (int i = 0; i < WaypointsModelAll.Count; i++) { //Gizmos.DrawIcon(wayPointAll[i].position, "Waypoint.png"); //Gizmos.DrawCube(wayPointAll[i].position, new Vector3(1f, 1f, 1f)); if (i != 0) { //绘制一条从当前路标点到下个路标点的线 if (showWaypoint) { Gizmos.DrawLine(WaypointsModelAll[i - 1].Position, WaypointsModelAll[i].Position); } //是否绘制方向标识线 if (showWaypointDir) { DrawDirLine(WaypointsModelAll[i - 1], WaypointsModelAll[i], lineWidth); } } else if (isAroundCircle) { //如果绕圈则首尾相连(多圈和单圈区分) //路标点尾首相连 if (showWaypoint) { Gizmos.DrawLine(WaypointsModelAll[WaypointsModelAll.Count - 1].Position, WaypointsModelAll[0].Position); } //是否绘制方向标识线 if (showWaypointDir) { DrawDirLine(WaypointsModelAll[WaypointsModelAll.Count - 1], WaypointsModelAll[0], lineWidth); } } } }
/// 重置赛车 <summary> /// 重置赛车 /// </summary> private void RecoverCar() { //获取距离最近的路标点 WaypointsModel ClosestWP = GetClosestWP(WaypointsModelAll, transform.position); //下个路标点索引 int nextIndex = ClosestWP.Index + 1; //最近路标点 Vector3 nearestPoint; //下一个复位点索引 小于 路标点数量 - 1 if (nextIndex < WaypointsModelAll.Count - 1) { //获取两个路标点间离赛车最近的点 nearestPoint = NearestPoint( ClosestWP.Position, WaypointsModelAll[nextIndex].Position, transform.position); } else { //最后一个点和起点之间时取最后一个点的位置 nearestPoint = WaypointsModelAll[WaypointsModelAll.Count - 1].Position; } #region 新添加 RaycastHit[] hit; //是否碰撞到地面 bool isColliderGround = false; //向下发送射线 hit = Physics.RaycastAll(nearestPoint, ClosestWP.Rotation * -Vector3.up, 100f); for (int i1 = 0; i1 < hit.Length; i1++) { //当碰撞到的物体为地面时 if (hit[i1].transform.tag == "Map_ground") { isColliderGround = true; //计算当前路标点与地面之间的距离 float temDis = Vector3.Distance(nearestPoint, hit[i1].point); //调整距离 nearestPoint.y = nearestPoint.y - (temDis - 0.5f); //Debug.Log(temDis); //绘制高度线 //Debug.DrawRay(WaypointsModelAll[i].Position, WaypointsModelAll[i].Rotation * -Vector3.up * temDis, Color.red); break; } } //如果没有碰撞到地面 //则说明赛车下面没有地面,处于悬空状态 //取最近路标点为复位点 if (!isColliderGround) { nearestPoint = WaypointsModelAll[ClosestWP.Index].Position; } #endregion transform.position = nearestPoint; transform.rotation = Quaternion.LookRotation(ClosestWP.Rotation * Vector3.forward); GetComponent <Rigidbody>().velocity = Vector3.zero; GetComponent <Rigidbody>().angularVelocity = Vector3.zero; }