private static float Heur(PathNode node1, PathNode node2, MovementProperties properties) { // Эвристику переделать - это пройденное время + оставшееся float angle = Mathf.Abs(Vector3.Angle(node1.Direction, node2.Position - node1.Position)) / properties.rotationAngle; //return node1.Distance(node2) + Mathf.Abs(angle); return(node1.TimeMoment + 2 * node1.Distance(node2) / properties.maxSpeed + angle * properties.deltaTime); }
public void GroundCheck(MovementProperties moveProperty) { moveProperty.isGrounded = Physics2D.OverlapCircle(moveProperty.groundCheck.position, moveProperty.groundRadius, moveProperty.whatIsGround); if (moveProperty.isGrounded) //Resets jumpcount when player touches back down. { moveProperty.jumpCount = 0; } // character.anim.SetBool ("Ground", moveProperty.isGrounded); }
/// <summary> /// Get the attached implementations on awake /// </summary> protected override void Awake() { base.Awake(); m_MovementEffects.Init(this); m_CurrentMovementProperties = m_Walking; m_NewMovementProperties = m_Walking; m_MovementEffects.AdjustTriggerThreshold(m_CurrentMovementProperties.strideLength); m_MainCamera = Camera.main; }
// Changes the current motor state and play events associated with state change void ChangeState(MovementProperties newState) { m_NewMovementProperties = newState; if (controllerAdapter.isGrounded) { m_CurrentMovementProperties = m_NewMovementProperties; } m_MovementEffects.AdjustTriggerThreshold(newState.strideLength); }
public MatchSimulationUnit(byte unitId, int xPosition, int yPosition, byte rotation, byte healthPercent, byte frame) { UnitId = unitId; movementState = new MovementProperties { XPosition = xPosition, YPosition = yPosition, Rotation = rotation, Frame = frame }; MovementState = new ReactiveProperty <MovementProperties>(movementState); HealthPercent = new ReactiveProperty <byte>(healthPercent); AbilityActivationSubject = new Subject <MatchSimulation.AbilityActivation>(); LastConfirmedFrame = frame; }
public static List <PathNode> GetNeighbours(PathNode node, MovementProperties properties) { // Вот тут хардкодить не надо, это должно быть в properties // У нас есть текущая точка, и свойства движения (там скорость, всякое такое) //float step = 1f; float step = properties.deltaTime * properties.maxSpeed; List <PathNode> result = new List <PathNode>(); NavMeshHit currentArea; try { if (!NavMesh.SamplePosition(node.Position, out currentArea, 2f, NavMesh.AllAreas)) { return(result); } } catch (Exception e) { Debug.Log("Shit happens : " + e.Message); return(null); } for (int mult = 0; mult <= 1; ++mult) { for (int angleStep = -properties.angleSteps; angleStep <= properties.angleSteps; ++angleStep) { PathNode next = node.SpawnChildren(step * mult, angleStep * properties.rotationAngle, properties.deltaTime); if (CheckWalkable(next.Position, currentArea.mask)) { result.Add(next); Debug.DrawLine(node.Position, next.Position, Color.white, 10f); } } } //Debug.Log("Children spawned : " + result.Count.ToString()); return(result); }
// Called on character landing void OnLanded() { m_CurrentMovementProperties = m_NewMovementProperties; }
/// <summary> /// Change state to the new state and adds to previous state stack /// </summary> /// <param name="newState">The new first person movement properties to be used</param> public void EnterNewState(MovementProperties newState) { ChangeState(newState); }
public PathNode GetGlobalRoute(PathNode target, PathNode position, MovementProperties movementProperties, bool onPlatform) { NavMeshHit targetArea; if (!NavMesh.SamplePosition(target.Position, out targetArea, 1f, NavMesh.AllAreas)) { return(null); } Vector3 adjustedPosition = new Vector3(position.Position.x, targetArea.position.y, position.Position.z); if (target.Distance(adjustedPosition) < movementProperties.epsilon) { return(null); } NavMeshHit currentArea; if (!NavMesh.SamplePosition(adjustedPosition, out currentArea, 1f, NavMesh.AllAreas) && !(globalPath.Count == 0) && !(globalPath.First().Type == RegionType.Moving)) { return(null); } if (NavMesh.SamplePosition(adjustedPosition, out _, 1f, NavMesh.AllAreas) && currentArea.mask == targetArea.mask) { if (targetArea.position.x - currentArea.position.x < 1f && targetArea.position.z - currentArea.position.z < 1f) { return(null); } globalPath = new List <Region>(); target.RegionId = currentArea.mask; return(target); } if (globalPath.Count == 0) { globalPath = GetPathWithDijkstra( new Region { Index = currentArea.mask, Type = RegionType.Stable }, new Region { Index = targetArea.mask, Type = RegionType.Stable }, target.Position); Cartographer cartographer = new Cartographer(); int areaMask = currentArea.mask; Vector3 inregionPosition = adjustedPosition; for (int i = 0; i < globalPath.Count(); i++) { var neighbours = cartographer.GetNeighbours(areaMask, inregionPosition); var modifiedRegion = neighbours.Find(x => x.Index == globalPath[i].Index); globalPath[i] = modifiedRegion; inregionPosition = modifiedRegion.PathPoints[0]; areaMask = modifiedRegion.Index; } } if (globalPath.Count != 0) { var nextRegion = globalPath.First(); if (currentArea.mask == nextRegion.Index) { globalPath.RemoveAt(0); if (globalPath.Count == 0) { return(target); } nextRegion = globalPath.First(); } if (nextRegion.Type == RegionType.Moving && globalPath.Count > 1 && globalPath[1].Index == currentArea.mask) { globalPath.RemoveAt(0); globalPath.RemoveAt(1); if (globalPath.Count == 0) { return(target); } nextRegion = globalPath.First(); } if (nextRegion.Type == RegionType.Stable) { return(calcStableRegionPath(nextRegion, currentArea, adjustedPosition, movementProperties)); } else if (nextRegion.Type == RegionType.Moving) { var movingRegion = (MovingRegion)nextRegion; foreach (var exit in movingRegion.ExitPoints) { //ищем точку прыжка на платформу в текущей области NavMeshHit exitHit; if (NavMesh.SamplePosition(exit.transform.position, out exitHit, 20, currentArea.mask)) { if (exitHit.mask == currentArea.mask) { if (Math.Abs(exitHit.position.x - adjustedPosition.x) < movementProperties.deltaTime * movementProperties.maxSpeed && Math.Abs(exitHit.position.y - adjustedPosition.y) < movementProperties.deltaTime * movementProperties.maxSpeed) { //Если мы в ней, то ждем платформу var node = new PathNode(movingRegion.EntryPoint.transform.position); node.RegionId = nextRegion.Index; node.JumpingPosition = true; return(node); } else { //Если не в ней, то топаем к ней var node = new PathNode(exitHit.position); node.RegionId = currentArea.mask; return(node); } } } } //Если мы уже на платформе, то идем следующий регион среди выходных точек и ждем, пока доедем //Либо если мы уже на входе в следующий регион, то топаем дальше var entryPointPosition = movingRegion.EntryPoint.transform.position; if (onPlatform) { if (globalPath.Count < 2) { //Мы уже у цели globalPath = new List <Region>(); return(null); } var exitRegion = globalPath[1]; foreach (var exit in movingRegion.ExitPoints) { NavMeshHit exitHit; if (NavMesh.SamplePosition(exit.transform.position, out exitHit, 20, exitRegion.Index)) { //Мы нашли точку выхода в следующую зону //Если мы в ней, то мы успешно прошли платформу if (Math.Abs(exitHit.position.x - adjustedPosition.x) < movementProperties.deltaTime * movementProperties.maxSpeed && Math.Abs(exitHit.position.z - adjustedPosition.z) < movementProperties.deltaTime * movementProperties.maxSpeed) { globalPath.RemoveAt(0); var node = new PathNode(exitHit.position); node.RegionId = globalPath.First().Index; return(node); } //Иначе ждем приближения точки else { var node = new PathNode(exit.transform.position); node.RegionId = nextRegion.Index; node.JumpingPosition = true; return(node); } } } } } return(new PathNode(nextRegion.PathPoints[0])); } return(null); }
private PathNode calcStableRegionPath(Region nextRegion, NavMeshHit currentArea, Vector3 adjustedPosition, MovementProperties movementProperties) { NavMeshHit moveTo; //Ищем ближайшую точку текущего региона, соседствующаю с целевым регионом if (NavMesh.SamplePosition(nextRegion.PathPoints[0], out moveTo, 40f, currentArea.mask)) { //Если мы в данный момент находимся близко к найденной точке, то мы на границе //В этом случае возвращаем точку из соседнего региона if (Math.Abs(moveTo.position.x - adjustedPosition.x) < movementProperties.deltaTime * movementProperties.maxSpeed && Math.Abs(moveTo.position.z - adjustedPosition.z) < movementProperties.deltaTime * movementProperties.maxSpeed) { var node = new PathNode(nextRegion.PathPoints[0]); node.RegionId = nextRegion.Index; return(node); } //Иначе мы возвращаем ближайшую к цели точку из текущего региона, чтобы скормить локальному планировщику else { var node = new PathNode(moveTo.position); node.RegionId = currentArea.mask; return(node); } } else { var node = new PathNode(moveTo.position); node.RegionId = currentArea.mask; return(node); }; }
public static List <PathNode> GetLocalRoute( PathNode target, PathNode position, MovementProperties movementProperties ) { Debug.Log("Начато построение пути"); // Вот тут вместо equals надо использовать == (как минимум), а лучше измерять расстояние между точками // сравнивая с некоторым epsilon. Хотя может это для каких-то специальных случаев? // if (position.Position.Equals(target.Position)) return new List<PathNode>(); if (Vector3.Distance(position.Position, target.Position) < movementProperties.epsilon) { return(new List <PathNode>()); } //HashSet<(Vector3, Vector3)> closed = new HashSet<(Vector3, Vector3)>(); //HashSet<Vector3> closedDir = new HashSet<Vector3>(); Priority_Queue.SimplePriorityQueue <PathNode> opened = new Priority_Queue.SimplePriorityQueue <PathNode>(); // Тут тоже вопрос - а почему с 0 добавляем? Хотя она же сразу извлекается, не важно opened.Enqueue(position, 0); int steps = 0; // Посещенные узлы (с некоторым шагом, аналог сетки) HashSet <(int, int, int, int)> closed = new HashSet <(int, int, int, int)>(); closed.Add(position.ToGrid4DPoint(movementProperties.deltaDist, movementProperties.deltaTime)); PathNode last = opened.First; while (opened.Count != 0 && steps < 5000) { steps++; PathNode currentNode = opened.Dequeue(); last = currentNode; //closed.Add(currentNode.ToGrid4DPoint(movementProperties.deltaDist, movementProperties.deltaTime)); // Для Sample-based список closed не нужен // Тут что-то более сложное if (currentNode.EqualsSigma(target, movementProperties.epsilon)) { Debug.Log("Braked by closest point. Steps : " + steps.ToString()); break; } // Получаем список соседей var neighbours = GetNeighbours(currentNode, movementProperties); foreach (var nextNode in neighbours) { var discreteNode = nextNode.ToGrid4DPoint(movementProperties.deltaDist, movementProperties.deltaTime); if (!closed.Contains(discreteNode)) { nextNode.H = Heur(nextNode, target, movementProperties); opened.Enqueue(nextNode, nextNode.H); closed.Add(discreteNode); } } } if (last.EqualsSigma(target, movementProperties.epsilon) == false) { Debug.Log("Failed to build a way. Steps : " + steps.ToString()); return(new List <PathNode>()); } List <PathNode> result = new List <PathNode>(); // Восстанавливаем путь от целевой к стартовой // Может, заменить последнюю на целевую, с той же отметкой по времени? Но тогда с поворотом сложновато получается var pathElem = last; while (pathElem != null) { result.Add(pathElem); pathElem = pathElem.Parent; } result.Reverse(); result.RemoveAt(0); return(result); }