public void OnDisable() { Pathfinding.RVO.Simulator sim = AStarPathfindingUtils.GetSimulator(); RVOContourObstacle cutObstacle = GetRVOContourObstacle(); if (cutObstacle) { cutObstacle.RemoveDynamicObstacles(sim); } if (_wasActive) { if (cutObstacle) { cutObstacle.SetObstaclesActive(sim, false); } if (null != TileHandlerHelper.instance) { TileHandlerHelper.instance.OnNavMeshCutDisabled(lastBounds); } } _UpdateIsRequired = false; EventManager.instance.RemoveListener <PopulateZonesPlayingEvent>(OnPopulateZones); EventManager.instance.RemoveListener <LevelStartEvent>(OnLevelStart); }
public static List <TriangleMeshNode> GetAllNodesInRadius(Vector3 origin, float radius) { //float radiusSquared = radius * radius; TriangleMeshNode root = AStarPathfindingUtils.GetNearestNodeOnNavMesh(origin); List <TriangleMeshNode> validNodes = new List <TriangleMeshNode>(); EB.Collections.Queue <TriangleMeshNode> toCheck = new EB.Collections.Queue <TriangleMeshNode>(); HashSet <TriangleMeshNode> visited = new HashSet <TriangleMeshNode>(); toCheck.Enqueue(root); while (toCheck.Count > 0) { TriangleMeshNode curNode = toCheck.Dequeue(); if (SphereXZTriangleIntersect(origin, radius, (Vector3)curNode.GetVertex(0), (Vector3)curNode.GetVertex(1), (Vector3)curNode.GetVertex(2))) { validNodes.Add(curNode); for (int i = 0; i < curNode.connections.Length; i++) { TriangleMeshNode connection = curNode.connections[i] as TriangleMeshNode; if (!visited.Contains(connection)) { toCheck.Enqueue(connection); } } } visited.Add(curNode); } return(validNodes); }
public void NotifyUpdated() { #if BNICKSON_UPDATED Pathfinding.RVO.Simulator sim = AStarPathfindingUtils.GetSimulator(); RVOContourObstacle cutObstacle = GetRVOContourObstacle(); if (cutObstacle) { cutObstacle.SetObstaclesActive(sim, isActive); if (HasMoved()) { cutObstacle.Move(sim); } else if (_UpdateIsRequired && isActive) { cutObstacle.CreateDynamicEdgesIfNoStaticEdgesExist(sim); } } _wasActive = isActive; _UpdateIsRequired = false; #endif wasEnabled = enabled; if (wasEnabled) { lastPosition = tr.position; lastBounds = GetBounds(); if (useRotation) { lastRotation = tr.rotation; } } }
private Pathfinding.RVO.Simulator GetSimulator() { if (null == _sim) { _sim = AStarPathfindingUtils.GetSimulator(); } return(_sim); }
// calculate what position and velocity we should send to peers who do not own the characters public void CalculatePositionAndVelocityToSend(ref Vector2 position, ref Vector2 velocity, ref float distToDestination) { // to save some bandwidth we're sending 2d vectors. y is calculated procedurally based on the ground height at the point you are standing on so isn't needed to be sent position.x = transform.position.x; position.y = transform.position.z; Vector3 velocity3d = new Vector3(_rvoController.newVelocity.x, 0f, _rvoController.newVelocity.z); Vector3 positionToDestinationXZ = GameUtils.SubXZ(_locomotion.Destination, transform.position); distToDestination = Mathf.Max(positionToDestinationXZ.magnitude - _locomotion.ArrivalThreshold, 0f); // check if our current rvo controller velocity is gonna make us overshoot the target if (velocity3d.magnitude * GetNetworkUpdateInterval() > distToDestination) { // set our speed so we do not overshoot velocity3d = velocity3d.normalized * (distToDestination / GetNetworkUpdateInterval()); } const float DirectionTolerance = 0.819f; // 0.819f == cos(35 degrees) const float StoppingTime = 4f; // seconds // if the character is not heading towards the destination, or the destination is far away then it's not gonna stop soon and the distance can be unlimited if (GameUtils.DotXZ(velocity3d.normalized, positionToDestinationXZ.normalized) < DirectionTolerance || // character is not traveling towards target (probably RVO related) distToDestination > velocity3d.magnitude * GetNetworkUpdateInterval() * StoppingTime) // the destination is far away, so no stop is imminent { distToDestination = NetworkTransform.DistanceUnlimited; } // this section makes sure our velocity would not take us off the nav mesh Vector3 from = transform.position; Vector3 targetPosition = AStarPathfindingUtils.CalculateExitPoint(ref from, from + velocity3d, _locomotion.Simulator, true); // see if the target poition would cause us to exit the nav mesh float distToOriginalTargetSqr = GameUtils.GetDistSqXZ(from, from + velocity3d); float distToNewTargetSqr = GameUtils.GetDistSqXZ(from, targetPosition); if (distToNewTargetSqr < distToOriginalTargetSqr) // if the returned length is nearer, it means we hit an edge { const float NudgeIntoNavMeshDist = 0.1f; if (distToNewTargetSqr > NudgeIntoNavMeshDist * NudgeIntoNavMeshDist) { float distToNewTarget = Mathf.Sqrt(distToNewTargetSqr); // here we're moving targetPosition slightly back onto the nav mesh away from the nav mesh perimeter, this is to stop the character being moved slightly off mesh targetPosition = from + (((targetPosition - from) / distToNewTarget) * (distToNewTarget - NudgeIntoNavMeshDist)); } else { targetPosition = from; // edge is very close, so just use the from position as the target position } velocity3d = targetPosition - transform.position; } velocity.x = velocity3d.x; velocity.y = velocity3d.z; if (!NetworkTransform.IsMovement(new Vector3(velocity3d.x, 0f, velocity3d.z))) // is no movement being sent { // if we're sending a velocity of zero, we can have distance unlimited because there will be no movement anyway, so having distance unlimited means it can start moving quickly when a movement begins distToDestination = NetworkTransform.DistanceUnlimited; } }
public void OnPopulateZones(PopulateZonesPlayingEvent evt) { if (isActive != _wasActive) // if our active state has changed, it means we are awaiting for the fact this has hapenned to be picked up in the TileHandlerHelper Update { lastPosition = tr.position; // set this here so TileHandlerHelper picks up the activity change, and not the movement, so NotifyUpdated() will not flag // this cuts obstacles as dynamic } RVOContourObstacle cutObstacle = GetRVOContourObstacle(); cutObstacle.OnLatePostScan(AStarPathfindingUtils.GetSimulator()); }
public void OnPopulateZones(PopulateZonesPlayingEvent evt) { if (scanOnStartup && AStarPathfindingUtils.WillNavMeshBeBuiltFromInputMeshOnLevelBegin()) { if (!astarData.cacheStartup || astarData.data_cachedStartup == null) { LevelHelper helper = GameObject.FindObjectOfType(typeof(LevelHelper)) as LevelHelper; if (helper != null) { AStarPathfindingUtils.CreateRecastNavMeshForInputMeshes(helper.transform.Find(ZoneHelper.ZonesRootName), helper.isOverworldNavMeshRequired); Scan(); EventManager.instance.Raise(new NavMeshScanEvent()); } } } if (Application.isPlaying) { RecastGraph.DestroyWalkableAreaObjects(); // we don't need the instances of AStarPathfindingWalkableArea in the game after this point RecastGraph.DestroyRecastMeshObjComponents(); // RecastMeshObj's are only used for nav mesh generation, they are not needed after this point AStarPathfindingRecastCut.DestroyRecastCutObjects(); AStarPathfindingGenerationTimeGeo.DestroyGenerationTimeGeoObjects(); } }
// make sure everything is correct on level start public void OnLevelStart(LevelStartEvent e) { RVOContourObstacle cutObstacle = GetRVOContourObstacle(); cutObstacle.SetObstaclesActive(AStarPathfindingUtils.GetSimulator(), isActive); }
private bool FindTargetAndLocation(TouchWrapper touch, out Transform target, out Vector3 location, out Vector3 groundPosition, out Vector3 direction) { target = null; if (Camera.main == null) { location = default(Vector3); groundPosition = default(Vector3); direction = default(Vector3); return(false); } if (mMainCamera == null) { mMainCamera = Camera.main; } Ray ray = mMainCamera.ScreenPointToRay(new Vector3(Mathf.Clamp(touch.position.x, 0, Screen.width), Mathf.Clamp(touch.position.y, 0, Screen.height), 0.0f)); RaycastHit rayHit; groundPosition = default(Vector3); direction = default(Vector3); location = default(Vector3); if (Physics.Raycast(ray, out rayHit, 200, _groundLayer)) { groundPosition = rayHit.point; } //Check raycast first for best precision if (Physics.Raycast(ray, out rayHit, 200, _characterLayers | _groundLayer)) { if (PlayerManager.IsPlayer(rayHit.transform.gameObject)) { target = rayHit.transform; } else if (rayHit.transform.gameObject.layer != LayerMask.NameToLayer("Ground")) { Selectable selectable = rayHit.transform.GetComponent <Selectable>(); if (selectable == null) { //If raycast couldn't find a selectable widen to an overlap sphere cast and pick closest selectable Collider[] colliders = Physics.OverlapSphere(rayHit.point, fingerRadius, 1 << LayerMask.NameToLayer("Enemy")); if (colliders.Length > 0) { float minSqDistance = float.MaxValue; Collider closestCollider = colliders[0]; foreach (Collider collider in colliders) { float sqrDistance = Vector3.SqrMagnitude(collider.transform.position - rayHit.point); if (sqrDistance < minSqDistance) { minSqDistance = sqrDistance; closestCollider = collider; } } selectable = closestCollider.gameObject.GetComponent <Selectable>(); } } //Move or target selectable if (selectable != null) { target = selectable.transform; } else { target = null; } } //if the object has a ServerCallback then call it!! if (rayHit.transform.gameObject != null) { MeshClick callback = rayHit.transform.gameObject.GetComponent <MeshClick>(); if (callback != null) { target = callback.transform; } } if (target != null) { location = target.transform.position; } else { location = groundPosition; } if (_playerTransform != null && _muzzleTransform != null) { Vector3 muzzleYOffset = new Vector3(0, _muzzleTransform.position.y - _playerTransform.position.y, 0); location += muzzleYOffset; direction = (groundPosition - _playerTransform.position).normalized; } // todo: FindTargetAndLocation called many times //Debug.LogFormat("FindTargetAndLocation: location = {0}", location.ToString()); if (!AStarPathfindingUtils.IsPointOnNavMeshOptimized(location)) { return(false); } return(true); } else if (_playerTransform != null) { Plane playerPlane = new Plane(Vector3.up, _playerTransform.position); float enter = 0; if (playerPlane.Raycast(ray, out enter)) { Vector3 hitPoint = ray.GetPoint(enter); direction = (hitPoint - _playerTransform.position).normalized; groundPosition = hitPoint; } } target = null; location = default(Vector3); return(false); }
/** Sets up all needed variables and scans the graphs. * Calls Initialize, starts the ReturnPaths coroutine and scans all graphs. * Also starts threads if using multithreading * \see #OnAwakeSettings */ void Awake() { //Very important to set this. Ensures the singleton pattern holds active = this; if (FindObjectsOfType(typeof(AstarPath)).Length > 1) { EB.Debug.LogError("You should NOT have more than one AstarPath component in the scene at any time.\n" + "This can cause serious errors since the AstarPath component builds around a singleton pattern."); } //Disable GUILayout to gain some performance, it is not used in the OnGUI call useGUILayout = false; isEditor = Application.isEditor; // This class uses the [ExecuteInEditMode] attribute // So Awake is called even when not playing // Don't do anything when not in play mode if (!Application.isPlaying) { return; } if (OnAwakeSettings != null) { OnAwakeSettings(); } //To make sure all graph modifiers have been enabled before scan (to avoid script run order issues) GraphModifier.FindAllModifiers(); RelevantGraphSurface.FindAllGraphSurfaces(); int numThreads = CalculateThreadCount(threadCount); threads = new Thread[numThreads]; //Thread info, will contain at least one item since the coroutine "thread" is thought of as a real thread in this case threadInfos = new PathThreadInfo[System.Math.Max(numThreads, 1)]; //Set up path queue with the specified number of receivers pathQueue = new ThreadControlQueue(threadInfos.Length); for (int i = 0; i < threadInfos.Length; i++) { threadInfos[i] = new PathThreadInfo(i, this, new PathHandler(i, threadInfos.Length)); } //Start coroutine if not using multithreading if (numThreads == 0) { threadEnumerator = CalculatePaths(threadInfos[0]); } else { threadEnumerator = null; } #if !UNITY_WEBGL for (int i = 0; i < threads.Length; i++) { threads[i] = new Thread(new ParameterizedThreadStart(CalculatePathsThreaded)); threads[i].Name = "Pathfinding Thread " + i; threads[i].IsBackground = true; } //Start pathfinding threads for (int i = 0; i < threads.Length; i++) { if (logPathResults == PathLog.Heavy) { EB.Debug.Log("Starting pathfinding thread {0}", i); } threads[i].Start(threadInfos[i]); } if (numThreads != 0) { graphUpdateThread = new Thread(new ParameterizedThreadStart(ProcessGraphUpdatesAsync)); graphUpdateThread.IsBackground = true; // Set the thread priority for graph updates // Unless compiling for windows store or windows phone which does not support it #if !UNITY_WINRT graphUpdateThread.Priority = System.Threading.ThreadPriority.Lowest; #endif graphUpdateThread.Start(this); } #endif Initialize(); // Flush work items, possibly added in initialize to load graph data FlushWorkItems(); euclideanEmbedding.dirty = true; #if BNICKSON_UPDATED // added !AStarPathfindingUtils.WillNavMeshBeBuiltFromInputMeshOnLevelBegin() if (scanOnStartup && !AStarPathfindingUtils.WillNavMeshBeBuiltFromInputMeshOnLevelBegin()) #else if (scanOnStartup) #endif { if (!astarData.cacheStartup || astarData.file_cachedStartup == null) { Scan(); #if BNICKSON_UPDATED EventManager.instance.Raise(new NavMeshScanEvent()); #endif } } }