/// <summary> /// Вызывается каждый кадр /// </summary> void Update() { if (Input.GetMouseButtonDown(0)) { RaycastHit hit; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (terrain.GetComponent <Collider>().Raycast(ray, out hit, Mathf.Infinity)) { globalTarget = new BaseAI.PathNode(hit.point); targetUpdated = true; Instantiate(DEBUG, globalTarget.Position, Quaternion.identity); } } // Фрагмент кода, отвечающий за вставание var vertical_angle = Vector3.Angle(Vector3.up, transform.up); if (vertical_angle > max_angle) { GetComponent <Rigidbody>().AddForceAtPosition(5 * force * Vector3.up, transform.position + 3.0f * transform.up, ForceMode.Force); } ; if (!walking) { return; } // Собственно движение if (MoveBot()) { MoveLegs(); } }
/// <summary> /// Обновление текущей целевой точки - куда вообще двигаться /// </summary> private bool UpdateCurrentTargetPoint() { // Если есть текущая целевая точка if (currentTarget != null) { float distanceToTarget = currentTarget.Distance(transform.position); // Если до текущей целевой точки ещё далеко, то выходим if (distanceToTarget >= movementProperties.epsilon || currentTarget.TimeMoment - Time.fixedTime > movementProperties.epsilon) { return(true); } // Иначе удаляем её из маршрута и берём следующую Debug.Log("Point reached : " + Time.fixedTime.ToString()); currentPath.RemoveAt(0); if (currentPath.Count > 0) { // Берём очередную точку и на выход currentTarget = currentPath[0]; return(true); } else { currentTarget = null; currentPath = null; // А вот тут надо будет проверять, есть ли уже построенный маршрут } } else if (currentPath != null) { if (currentPath.Count > 0) { currentTarget = currentPath[0]; return(true); } else { currentPath = null; } } // Здесь мы только в том случае, если целевой нет, и текущего пути нет - и то, и другое null // Обращение к plannedPath желательно сделать через блокировку - именно этот список задаётся извне планировщиком // Непонятно, насколько lock затратен, можно ещё булевский флажок добавить, его сначала проверять //lock(plannedPath) { if (plannedPath != null) { currentPath = plannedPath; plannedPath = null; if (currentPath.Count > 0) { currentTarget = currentPath[0]; } } } return(currentTarget != null); }
/// <summary> /// Обновление текущей целевой точки - куда вообще двигаться /// </summary> private bool UpdateCurrentTargetPoint() { if (currentTarget != null) { if (currentTarget.JumpingPosition) { currentTarget = globalPlanner.GetGlobalRoute(globalTarget, new BaseAI.PathNode(transform.position), movementProperties, transform.parent != null); return(true); } Vector3 dummyPosition = new Vector3(transform.position.x, currentTarget.Position.y, transform.position.z); float distanceToTarget = currentTarget.Distance(dummyPosition); if (distanceToTarget >= movementProperties.epsilon && transform.parent == null) //|| currentTarget.TimeMoment - Time.fixedTime > movementProperties.epsilon) { return(true); } //Debug.Log("Point reached : " + Time.fixedTime.ToString()); if (currentPath != null) { if (currentPath.Count > 0) { currentPath.RemoveAt(0); } if (currentPath.Count > 0) { currentTarget = currentPath[0]; return(true); } } else { //currentTarget = null; // Если мы сюда пришли, то мы находимся либо в цели, либо на границе регионов, куда нас направил глобальный планировщик // Снова дёргаем планировщика, если вернул не null, то // 1) смотрим, в той же что и мы зоне вернувшаяся точка // 2) если в той же, то скармливает её локалпланнеру и возвращаем этот маршрут // 3) если нет, то мы на границе зон. Сразу присваиваем точку из глобального планировщика currentTarget var currentPathNode = new BaseAI.PathNode(transform.position); var milestone = globalPlanner.GetGlobalRoute(globalTarget, currentPathNode, movementProperties, transform.parent != null); if (transform.parent != null) { currentTarget = milestone; return(true); } if (milestone != null) { NavMeshHit currentArea; Vector3 adjustedPosition = new Vector3(transform.position.x, milestone.Position.y, transform.position.z); if (NavMesh.SamplePosition(adjustedPosition, out currentArea, 1f, NavMesh.AllAreas)) { if (currentArea.mask == milestone.RegionId) { currentPath = LocalPlanner.GetLocalRoute(milestone, currentPathNode, movementProperties); //Для дебага и прочих шалостей for (int i = 0; i < currentPath.Count; i++) { Instantiate(DEBUG, currentPath[i].Position, Quaternion.identity); } } else { currentTarget = milestone; return(true); } } } else { currentTarget = null; } } } else if (targetUpdated && globalTarget != null) { targetUpdated = false; var currentPathNode = new BaseAI.PathNode(transform.position); //Пример получения майлстоуна от планировщика var milestone = globalPlanner.GetGlobalRoute(globalTarget, currentPathNode, movementProperties, transform.parent != null); if (milestone != null) { currentPath = LocalPlanner.GetLocalRoute(milestone, currentPathNode, movementProperties); //Для дебага и прочих шалостей for (int i = 0; i < currentPath.Count; i++) { Instantiate(DEBUG, currentPath[i].Position, Quaternion.identity); } } } else if (currentTarget == null) { } if (currentPath != null) { if (currentPath.Count > 0) { currentTarget = currentPath[0]; return(true); } else { currentPath = null; } } // Здесь мы только в том случае, если целевой нет, и текущего пути нет - и то, и другое null // Обращение к plannedPath желательно сделать через блокировку - именно этот список задаётся извне планировщиком // Непонятно, насколько lock затратен, можно ещё булевский флажок добавить, его сначала проверять ////lock(plannedPath) //{ //if(plannedPath != null) //{ // currentPath = plannedPath; // plannedPath = null; // if (currentPath.Count > 0) // currentTarget = currentPath[0]; //} //} return(currentTarget != null); }
/// <summary> /// Расстояние между точками без учёта времени. Со временем - отдельная история /// Если мы рассматриваем расстояние до целевой вершины, то непонятно как учитывать время /// </summary> /// <param name="other">Точка, до которой высчитываем расстояние</param> /// <returns></returns> public float Distance(PathNode other) { return(Vector3.Distance(Position, other.Position)); }
/// <summary> /// Конструирование вершины на основе родительской (если она указана) /// </summary> /// <param name="ParentNode">Если существует родительская вершина, то её указываем</param> public PathNode(PathNode ParentNode = null) { Parent = ParentNode; }
/// <summary> /// Обновление текущей целевой точки - куда вообще двигаться /// </summary> private bool UpdateCurrentTargetPoint() { // Если есть текущая целевая точка if (currentTarget != null) { float distanceToTarget = currentTarget.Distance(transform.position); // Если до текущей целевой точки ещё далеко, то выходим if (distanceToTarget >= movementProperties.epsilon || currentTarget.TimeMoment - Time.fixedTime > movementProperties.epsilon) { return(true); } // Иначе удаляем её из маршрута и берём следующую //Debug.Log("Point reached : " + Time.fixedTime.ToString()); currentPath.RemoveAt(0); if (currentPath.Count > 0) { // Берём очередную точку и на выход currentTarget = currentPath[0]; return(true); } else { currentTarget = null; currentPath = null; // А вот тут надо будет проверять, есть ли уже построенный маршрут } } else if (currentPath != null) { if (currentPath.Count > 0) { currentTarget = currentPath[0]; return(true); } else { currentPath = null; } } //lock(plannedPath) { if (PlannedPath != null) { currentPath = PlannedPath; PlannedPath = null; if (currentPath.Count > 0) { currentTarget = currentPath[0]; } } } var res = currentTarget != null; if (walking && !res) { walking = false; if (_localPathPlaner) { _localPathPlaner.IsWalking = false; } } return(res); }