public Job TakeClosestJobToTile(Tile t) { Job found = null; int distance = int.MaxValue; foreach (var job in _jobQueue) { var route = new Path_AStar() { World = World.Instance, Start = t, End = job.Tile }; route.Calculate(); if (found == null || route.Length() < distance) { found = job; distance = route.Length(); } } if (found != null) { _jobQueue.Remove(found); } return(found); }
void GetNewJob() { myJob = World.Current.jobQueue.Dequeue(); if (myJob == null) { myJob = new Job(CurrTile, "Waiting", null, UnityEngine.Random.Range(0.1f, 0.5f), null, false); } DestTile = myJob.tile; myJob.cbJobStopped += OnJobStopped; // Immediately check to see if the job tile is reachable pathAStar = new Path_AStar(World.Current, CurrTile, DestTile); // This will calculate path from curr to dest if (pathAStar.Length() == 0) { Debug.LogError("Path_AStar returned no path to destination!"); AbandonJob(); DestTile = CurrTile; } }
/// <summary> /// Grab a new job from the queue. This will first check if the tile is reachable. /// </summary> private void GetNewJob() { // Grab job from jobQueue currentJob = currentTile.World.jobQueue.Dequeue(); if (currentJob == null) { return; } // Set the destinationtile DestinationTile = currentJob.tile; // Add job callback actions currentJob.RegisterJobCancelCallback(OnJobEnded); currentJob.RegisterJobCompleteCallback(OnJobEnded); // Check if the job tile is reachable // NOTE: We might not be pathing to it right away (due to requiring materials), // but we still need to verify that the final tile is reachalbe. #region Check tile is reachable // Generate new A* path from currentTile to destinationTile path_AStar = new Path_AStar(currentTile.World, currentTile, DestinationTile); // Check if path isn't null if (path_AStar.Length() == 0) { Debug.LogError("Path_AStar: Returned no path to target job tile!"); // FIXME: Job should get added back to queue AbandonJob(); DestinationTile = currentTile; } #endregion }
void GetNewJob() { // Get the first job on the queue. myJob = World.current.jobQueue.Dequeue(); if (myJob == null) { myJob = new Job(CurrTile, "Waiting", null, UnityEngine.Random.Range(0.1f, 0.5f), null, false); } // Get our destination from the job DestTile = myJob.tile; myJob.cbJobStopped += OnJobStopped; // Immediately check to see if the job tile is reachable. // NOTE: We might not be pathing to it right away (due to // requiring materials), but we still need to verify that the // final location can be reached. Profiler.BeginSample("PathGeneration"); pathAStar = new Path_AStar(World.current, CurrTile, DestTile); // This will calculate a path from curr to dest. Profiler.EndSample(); if (pathAStar.Length() == 0) { Debug.LogError("Path_AStar returned no path to target job tile!"); AbandonJob(); DestTile = CurrTile; } }
void Update_DoMovement(float deltaTime) { if (CurrentTile == _destTile) { CurrentTile.SetUnit(this); _pathAStar = null; return; // We're already were we want to be. } if (_nextTile == null || _nextTile == CurrentTile) { // Get the next tile from the pathfinder. if (_pathAStar == null || _pathAStar.Length() == 0) { // Generate a path to our destination CurrentTile.SetUnit(null); _pathAStar = new Path_AStar(CurrentTile.World, CurrentTile, _destTile); // This will calculate a path from curr to dest. if (_pathAStar.Length() == 0) { Debug.LogError("Path_AStar returned no path to destination!"); _destTile = CurrentTile; _pathAStar = null; return; } } // Grab the next waypoint from the pathing system! _nextTile = _pathAStar.Dequeue(); } float distToTravel = Mathf.Sqrt( Mathf.Pow(CurrentTile.X - _nextTile.X, 2) + Mathf.Pow(CurrentTile.Y - _nextTile.Y, 2) ); // How much distance can be travel this Update? float distThisFrame = Speed * deltaTime; // How much is that in terms of percentage to our destination? float percThisFrame = distThisFrame / distToTravel; // Add that to overall percentage travelled. _movementPercentage += percThisFrame; if (_movementPercentage >= 1) { // We have reached our destination // If there are no more tiles, then we have TRULY // reached our destination. CurrentTile = _nextTile; _movementPercentage = 0; } }
public Block GetNextPathBlock() { if (myPath.Length() > 0) { return(myPath.GetNextBlock()); } else { return(null); } }
public static Room FindNearestRoom(Tile start) { Path_AStar tileResolver = new Path_AStar(World.Current, start, GoalHasRoomEvaluator(), DijkstraDistance()); if (tileResolver.Length() >= 1) { return(tileResolver.EndTile().Room); } return(null); }
public void PrioritizeJob(Job job) { AbandonJob(false); World.Current.jobQueue.Remove(job); job.IsBeingWorked = true; /*Check if the character is carrying any materials and if they could be used for the new job, * if the character is carrying materials but is not used in the new job, then drop them * on the current tile for now.*/ if (inventory != null && !job.inventoryRequirements.ContainsKey(inventory.ObjectType)) { World.Current.inventoryManager.PlaceInventory(CurrTile, inventory); DumpExcessInventory(); } MyJob = job; // Get our destination from the job. DestTile = MyJob.tile; // If the destination tile does not have neighbours that are walkable it's very likable that they can't be walked to. if (DestTile.HasWalkableNeighbours() == false) { Debug.ULogChannel("Character", "No neighbouring floor tiles! Abandoning job."); AbandonJob(false); return; } MyJob.OnJobStopped += OnJobStopped; pathAStar = new Path_AStar(World.Current, CurrTile, DestTile); if (pathAStar != null && pathAStar.Length() == 0) { Debug.ULogChannel("Character", "Path_AStar returned no path to target job tile!"); AbandonJob(false); return; } if (MyJob.adjacent) { IEnumerable <Tile> reversed = pathAStar.Reverse(); reversed = reversed.Skip(1); pathAStar = new Path_AStar(new Queue <Tile>(reversed.Reverse())); DestTile = pathAStar.EndTile(); jobTile = DestTile; } else { jobTile = MyJob.tile; } }
bool find_If_Tile_Job_Is_Rechable(Vector3Int jobTile) { Path_AStar path_to_job = new Path_AStar(WorldController.Instance.World, currTile, jobTile); if (path_to_job.Length() == 0) { return(false); } else { return(true); } }
// Start Pathfinding from Start to Goal tile public bool StartPathfinding() { Debug.Log("Start Path Finding"); if (World.startTile == null || World.goalTile == null) { Debug.LogError("No Start or Goal tile"); return(false); } Path_AStar oldPathAStar = pathAStar; // Update old path way not valid anymore if (oldPathAStar != null) { foreach (Tile t in oldPathAStar.Path()) { //Debug.Log("Old Path:"+ tileGraphicController.tileGameObjectMap[t] ); t.isPathway = false; tileGraphicController.tileGameObjectMap[t].GetComponent <GroundCube>().UpdatePathfindingGraphic(); } } // Generate New pathway pathAStar = new Path_AStar(true, World.startTile, World.goalTile); if (pathAStar.Length() == 0) { // No valid Pathfinding way Debug.LogError("Path_AStar returned no path to destination!"); pathAStar = null; return(false); } else { foreach (Tile t in pathAStar.Path()) { t.isPathway = true; tileGraphicController.tileGameObjectMap[t].GetComponent <GroundCube>().UpdatePathfindingGraphic(); } return(true); } }
void GetNewJob() { _myJob = _currentTile.World.JobQueue.Dequeue(); if (_myJob == null) { return; } DestinationTile = _myJob.Tile; _myJob.RegisterJobCompletedCallback(RegisterOnJobEnded); _myJob.RegisterJobCancelledCallback(RegisterOnJobEnded); _pathAStar = new Path_AStar(WorldController.Instance.World, _currentTile, _destinationTile); if (_pathAStar.Length() == 0) { Debug.LogError("Path_AStart returned no path to current job tile!"); AbandonJob(); } }
void GetNewJob() { myJob = currentTile.World.jobQueue.Dequeue(); if (myJob == null) { return; } DestinationTile = myJob.tile; myJob.RegisterJobCancelCallback(OnJobEnded); myJob.RegisterJobCompleteCallback(OnJobEnded); //check to see if final job tile is reachable //generate a path to check pathAStar = new Path_AStar(currentTile.World, currentTile, DestinationTile); //calculate a path from the current tile to the destination tile if (pathAStar.Length() == 0) { Debug.LogError("Character -- Update_DoMovement: Path_AStar returned no path to target job"); AbandonJob(); DestinationTile = currentTile; } }
void GetNewJob() { myJob = World.current.jobQueue.Dequeue(); if (myJob == null) { return; } DestTile = myJob.tile; myJob.RegisterJobStoppedCallback(OnJobStopped); // Immediately check to see if the job tile is reachable. // NOTE: We might not be pathing to it right away (due to // requiring materials), but we still need to verify that the // final location can be reached. pathAStar = new Path_AStar(World.current, currTile, DestTile); // This will calculate a path from curr to dest. if (pathAStar.Length() == 0) { Debug.LogError("Path_AStar returned no path to target job tile!"); AbandonJob(); DestTile = currTile; } }
/// <summary> /// 更新移动 /// </summary> /// <param name="deltaTime"></param> void Update_DoMovement(float deltaTime) { if (currTile == destTile) { path_AStar = null; return; } if (nextTile == null || nextTile == currTile) { //获取下一个寻路点 if (path_AStar == null || path_AStar.Length() == 0) { //生存到目的地寻路 path_AStar = new Path_AStar(currTile.world, currTile, destTile); if (path_AStar.Length() == 0) { AbandonJob(); path_AStar = null; return; } //获取下一个路径tile nextTile = path_AStar.Dequeue(); } //获取下一个路径tile nextTile = path_AStar.Dequeue(); } if (nextTile.IsEnterable() == Enterability.Never) { //很可能是墙建成了,所以我们只需要重置我们的寻路信息。 // FIXME:理想情况下,当墙壁产生时,我们应立即使路径无效, //这样我们就不会浪费一大堆时间走向死胡同。 //为了节省CPU,也许我们只能经常检查? //或者我们应该注册OnTileChanged事件的回调? nextTile = null; path_AStar = null; return; } else if (nextTile.IsEnterable() == Enterability.Soon) { //我们现在无法进入,但我们应该可以进入 //未来 这可能是一个DOOR。 //所以我们不要保佑我们的运动/路径,但我们确实会回来 //现在并不实际处理运动。 return; } //从A点到B点的总距离是多少? //我们将使用欧几里德距离现在...... //但是当我们进行寻路系统时,我们很可能会这样做 //切换到曼哈顿或切比雪夫的距离 float distToTravel = Mathf.Sqrt( Mathf.Pow(currTile.x - nextTile.x, 2) + Mathf.Pow(currTile.y - nextTile.y, 2) ); // 移动速度(通过门的时 缓慢通过) float distThisFrame = speed / nextTile.movementCost * deltaTime; // 到目的地的需要多久? float percThisFrame = distThisFrame / distToTravel; // movementPercentage += percThisFrame; if (movementPercentage >= 1) { // TODO:从寻路系统中获取下一个图块。 //如果没有更多的瓷砖,那么我们就有了TRULY //到达目的地 // 我们到达了目的地 currTile = nextTile; movementPercentage = 0; // 我们真的想保留任何超车运动吗? } if (cbCharacterChanged != null) { cbCharacterChanged(this); } }
private void GetNewJob() { float needPercent = 0; Need need = null; foreach (Need n in needs) { if (n.Amount > needPercent) { need = n; needPercent = n.Amount; } } if (needPercent > 50 && needPercent < 100 && need.RestoreNeedFurn != null) { if (World.Current.CountFurnitureType(need.RestoreNeedFurn.ObjectType) > 0) { MyJob = new Job(null, need.RestoreNeedFurn.ObjectType, need.CompleteJobNorm, need.RestoreNeedTime, null, Job.JobPriority.High, false, true, false); } } if (needPercent == 100 && need != null && need.CompleteOnFail) { MyJob = new Job(CurrTile, null, need.CompleteJobCrit, need.RestoreNeedTime * 10, null, Job.JobPriority.High, false, true, true); } // Get the first job on the queue. if (MyJob == null) { MyJob = World.Current.jobQueue.Dequeue(); // Check if we got a job from the queue. if (MyJob == null) { Debug.ULogChannel("Character", name + " did not find a job."); MyJob = new Job( CurrTile, "Waiting", null, UnityEngine.Random.Range(0.1f, 0.5f), null, Job.JobPriority.Low, false); MyJob.JobDescription = "job_waiting_desc"; } else { if (MyJob.tile == null) { Debug.ULogChannel("Character", name + " found a job."); } else { Debug.ULogChannel("Character", name + " found a job at x " + MyJob.tile.X + " y " + MyJob.tile.Y + "."); } } } // Get our destination from the job. DestTile = MyJob.tile; // If the destination tile does not have neighbours that are walkable it's very likely that they can't be walked to if (DestTile != null) { if (DestTile.HasWalkableNeighbours() == false) { Debug.ULogChannel("Character", "No neighbouring floor tiles! Abandoning job."); AbandonJob(false); return; } } MyJob.OnJobStopped += OnJobStopped; // Immediately check to see if the job tile is reachable. // NOTE: We might not be pathing to it right away (due to // requiring materials), but we still need to verify that the // final location can be reached. Profiler.BeginSample("PathGeneration"); if (MyJob.IsNeed) { // This will calculate a path from current tile to destination tile. pathAStar = new Path_AStar(World.Current, CurrTile, DestTile, need.RestoreNeedFurn.ObjectType, 0, false, true); } else { pathAStar = new Path_AStar(World.Current, CurrTile, DestTile); } Profiler.EndSample(); if (pathAStar != null && pathAStar.Length() == 0) { Debug.ULogChannel("Character", "Path_AStar returned no path to target job tile!"); AbandonJob(false); return; } if (MyJob.adjacent) { IEnumerable <Tile> reversed = pathAStar.Reverse(); reversed = reversed.Skip(1); pathAStar = new Path_AStar(new Queue <Tile>(reversed.Reverse())); DestTile = pathAStar.EndTile(); jobTile = DestTile; } else { jobTile = MyJob.tile; } MyJob.IsBeingWorked = true; }
private void GetNewJob() { float needPercent = 0; Need need = null; foreach (Need n in needs) { if (n.Amount > needPercent) { need = n; needPercent = n.Amount; } } if (needPercent > 50 && needPercent < 100 && need != null) { myJob = new Job(null, need.restoreNeedFurn.objectType, need.CompleteJobNorm, need.restoreNeedTime, null, Job.JobPriority.High, false, true, false); } if (needPercent == 100 && need != null && need.completeOnFail) { myJob = new Job(CurrTile, null, need.CompleteJobCrit, need.restoreNeedTime * 10, null, Job.JobPriority.High, false, true, true); } // Get the first job on the queue. if (myJob == null) { myJob = World.current.jobQueue.Dequeue(); } if (myJob == null) { Debug.Log(name + " did not find a job."); myJob = new Job( CurrTile, "Waiting", null, UnityEngine.Random.Range(0.1f, 0.5f), null, Job.JobPriority.Low, false); } else { if (myJob.tile == null) { Debug.Log(name + " found a job."); } else { Debug.Log(name + " found a job at x " + myJob.tile.X + " y " + myJob.tile.Y + "."); } } // Get our destination from the job DestTile = myJob.tile; // If the dest tile does not have neighbours it's very if ((DestTile == null || DestTile.HasNeighboursOfType(TileType.Floor) || DestTile.HasNeighboursOfType(TileType.Ladder)) == false) { Debug.Log("No neighbouring floor tiles! Abandoning job."); AbandonJob(false); return; } myJob.cbJobStopped += OnJobStopped; // Immediately check to see if the job tile is reachable. // NOTE: We might not be pathing to it right away (due to // requiring materials), but we still need to verify that the // final location can be reached. Profiler.BeginSample("PathGeneration"); if (myJob.isNeed) { pathAStar = new Path_AStar(World.current, CurrTile, DestTile, need.restoreNeedFurn.objectType, 0, false, true); // This will calculate a path from curr to dest. } else { pathAStar = new Path_AStar(World.current, CurrTile, DestTile); } Profiler.EndSample(); if (pathAStar != null && pathAStar.Length() == 0) { Debug.Log("Path_AStar returned no path to target job tile!"); AbandonJob(false); return; } if (myJob.adjacent) { IEnumerable <Tile> reversed = pathAStar.Reverse(); reversed = reversed.Skip(1); pathAStar = new Path_AStar(new Queue <Tile>(reversed.Reverse())); DestTile = pathAStar.EndTile(); jobTile = DestTile; } else { jobTile = myJob.tile; } }
void Update_DoMovement(float _deltaTime) { //if we don't need to move, don't move, we're already here if (currentTile == DestinationTile) { pathAStar = null; return; } if (nextTile == null || nextTile == currentTile) { //Get next tile from pathfinder if (pathAStar == null || pathAStar.Length() == 0) { //generate a path pathAStar = new Path_AStar(currentTile.World, currentTile, DestinationTile); //calculate a path from the current tile to the destination tile if (pathAStar.Length() == 0) { Debug.LogError("Character -- Update_DoMovement: Path_AStar returned no path to destination"); AbandonJob(); return; } //ignore the first tile, it is what we're on nextTile = pathAStar.Dequeue(); } //Grab next waypoint nextTile = pathAStar.Dequeue(); if (nextTile == currentTile) { Debug.LogError("Character-- Update_DoMovement: nextTile is equal to currentTile"); } } //if (pathAStar.Length() == 1) // return; //At this point we should have a valid nextTile //total distance from point A to point B float distanceToTravel = Mathf.Sqrt(Mathf.Pow(currentTile.X - nextTile.X, 2) + Mathf.Pow(currentTile.Y - nextTile.Y, 2)); if (nextTile.IsEnterable() == ENTERABILITY.Never) { Debug.LogError("Character -- Update_DoMovement: A character tried to enter an unwalkable tile"); //the next tile shouldn't be walked on, so the path info is outdated and need to be updated (e.g. a wall was built here after the path was made) nextTile = null; pathAStar = null; return; } else if (nextTile.IsEnterable() == ENTERABILITY.Soon) { //We can't enter the tile now, but we should be able to in the near future. This tile is likely a door, so we will return until the tile is enterable //then we process the movement and move thrugh the tile return; } //How much distance can we travel this update float distanceThisFrame = speed / nextTile.MovementCost * _deltaTime; //How mush is that in terms of percentage to our destination float percentageThisFrame = distanceThisFrame / distanceToTravel; //add to overall percentage travel movementPercentage += percentageThisFrame; //if we have reached the destination if (movementPercentage >= 1) { currentTile = nextTile; movementPercentage = 0; } }
/// <summary> /// Checks weather the current job has all the materials in place and if not instructs the working character to get the materials there first. /// Only ever returns true if all materials for the job are at the job location and thus signals to the calling code, that it can proceed with job execution. /// </summary> /// <returns></returns> bool CheckForJobMaterials() { if (myJob.HasAllMaterial()) { return(true); //we can return early } // Job still needs materials // Am I carrying anything the job location wants? if (inventory != null) { if (myJob.DesiresInventoryType(inventory) > 0) { // If so, deliver // Walk to the job tile then drop off the stack into the job if (CurrTile == myJob.tile) { // We are at the job site so drop the inventory World.Current.inventoryManager.PlaceInventory(myJob, inventory); myJob.DoWork(0); // This will call all cbJobWorked callbacks //at this point we should dump anything in our inventory DumpExcessInventory(); } else { // Walk to job site DestTile = myJob.tile; return(false); } } else { // We are carrying something but the job doesn't want it // Dump it DumpExcessInventory(); } } else { // At this point, the job still requires inventory but we aren't carrying it // Are we standing on a tile with goods desired by job? if (CurrTile.inventory != null && myJob.DesiresInventoryType(CurrTile.inventory) > 0 && (myJob.canTakeFromStockpile || CurrTile.furniture == null || CurrTile.furniture.IsStockpile() == false)) { // Pick up the stuff World.Current.inventoryManager.PlaceInventory( this, CurrTile.inventory, myJob.DesiresInventoryType(CurrTile.inventory) ); } else { // If not, walk towards a tile containing the required goods // Find the first thing in the job that isn't satisfied Inventory desired = myJob.GetFirstDesiredInventory(); if (CurrTile != NextTile) { // We are still moving somewhere so just bail out return(false); } // Any chance we already have a path that leads to the items we want? if (pathAStar != null && pathAStar.EndTile() != null && pathAStar.EndTile().inventory != null && pathAStar.EndTile().inventory.objectType == desired.objectType) { // We are already moving towards a tile that we want so do nothing } else { Path_AStar newPath = World.Current.inventoryManager.GetPathToClosestInventoryOfType( desired.objectType, CurrTile, desired.maxStackSize - desired.stackSize, myJob.canTakeFromStockpile ); if (newPath == null || newPath.Length() == 0) { Debug.Log("No tile contains objects of type " + desired.objectType + "to satisfy job requirements"); AbandonJob(); return(false); } Debug.Log("pathAStar returned with length of: " + newPath.Length()); DestTile = newPath.EndTile(); // Since we already have a path calculated let's just save that pathAStar = newPath; // Ignore the first tile because that's the tile we're already in NextTile = newPath.Dequeue(); } // One way or the other, we are now on route to an object of the right type return(false); } } return(false); // Can't continue until all materials are satisifed }
void Update_DoMovement(float deltaTime) { if (CurrTile == DestTile) { pathAStar = null; return; // Already there } // currTile = the tile I'm currently in (and may be leaving) // nextTile = the tile I'm currently entering // destTile = Our final destination -- we never walk here directly, but instead use it for the pathfinder if (NextTile == null || NextTile == CurrTile) { // Get the next tile from the pathfinder if (pathAStar == null || pathAStar.Length() == 0) { // Generate a path to our destination pathAStar = new Path_AStar(World.Current, CurrTile, DestTile); // This will calculate path from curr to dest if (pathAStar.Length() == 0) { Debug.LogError("Path_AStar returned no path to destination!"); AbandonJob(); return; } // Let's ignore the first tile because that's the tile we're currently in NextTile = pathAStar.Dequeue(); } // Grab the next waypoint from the pathing system! NextTile = pathAStar.Dequeue(); if (NextTile == CurrTile) { Debug.LogError("Update_DoMovement - nextTile is currTile?"); } } // At this point we should have a valid nextTile to move to // Total distance between A and B // Euclidean distance for now; for pathfinding change to Manhattan or something else float distToTravel = Mathf.Sqrt( Mathf.Pow(CurrTile.X - NextTile.X, 2) + Mathf.Pow(CurrTile.Y - NextTile.Y, 2) ); if (NextTile.IsEnterable() == ENTERABILITY.Never) { // Most likely a wall got built, so we need to reset pathfinding // FIXME: when a wall gets spanwed, invalidate path immediately. or check sometimes to save CPU. // or register a callback to ontilechanged event Debug.LogError("Fix me - character trying to walk through unwalkable tile"); NextTile = null; // our next tile is a no-go pathAStar = null; // pathfinding info is out of date return; } else if (NextTile.IsEnterable() == ENTERABILITY.Soon) { // Can't enter now but should be able to in the future.(Door?) // Don't bail on movement path but return now and don't process movement. return; } // How much distance can be travelled this Update float distThisFrame = speed / NextTile.movementCost * deltaTime; // How much is that in terms of percentage float percThisFrame = distThisFrame / distToTravel; // Add that to overall percentage travelled movementPercentage += percThisFrame; if (movementPercentage >= 1) { // Reached destination // TODO: get the next tile from pathfinding system CurrTile = NextTile; movementPercentage = 0; // FIXME: Overshot movement? } }
private void Update_DoMovement(float deltaTime) { if (currTile == destTile) { pathAStar = null; return; // We're already were we want to be. } if (nextTile == null || nextTile == currTile) { // Get the next tile from the pathfinder. if (pathAStar == null || pathAStar.Length() == 0) { // Generate a path to our destination pathAStar = new Path_AStar(currTile.World, currTile, destTile); // This will calculate a path from curr to dest. if (pathAStar.Length() == 0) { //Debug.LogError("Path_AStar returned no path to destination!"); AbandonJob(); pathAStar = null; return; } // Ignore the first tile in the path, as that's the tile we are currently in, // and we can always move out of our current tile. nextTile = pathAStar.Dequeue(); } // Grab the next waypoint from the pathing system! nextTile = pathAStar.Dequeue(); if (nextTile == currTile) { //Debug.LogError("Update_DoMovement - nextTile is currTile?"); } } /* if(pathAStar.Length() == 1) { * return; * } */ // At this point we should have a valid nextTile to move to. // What's the total distance from point A to point B? // We are going to use Euclidean distance FOR NOW... // But when we do the pathfinding system, we'll likely // switch to something like Manhattan or Chebyshev distance float distToTravel = 0; if (nextTile != currTile) { distToTravel = (float)Math.Sqrt( Math.Pow(currTile.X - nextTile.X, 2) + Math.Pow(currTile.Y - nextTile.Y, 2) ); } // Before entering a tile, make sure it is not impassable. // This might happen if the tile is changed (e.g. wall built) after the pathfinder runs. if (nextTile.IsEnterable() == Enterability.Never) { // Debug.LogError("Error - character was strying to enter an impassable tile!"); nextTile = currTile; pathAStar = null; } else if (nextTile.IsEnterable() == Enterability.Soon) { // The next tile we're trying to enter is walkable, but maybe for some reason // cannot be entered right now. Perhaps it is occupied, or contains a closed door. return; } // How much distance can be travel this Update? var distThisFrame = (speed / nextTile.MovementCost) * deltaTime; // How much is that in terms of percentage to our destination? var percThisFrame = distThisFrame / distToTravel; // Add that to overall percentage travelled. movementPercentage += percThisFrame; if (movementPercentage >= 1) { // We have reached our destination // TODO: Get the next tile from the pathfinding system. // If there are no more tiles, then we have TRULY // reached our destination. currTile = nextTile; movementPercentage = 0; // FIXME? Do we actually want to retain any overshot movement? } }
void DoMovement() { if (curTile == DestTile) { // We made it StopMove(); return; } if (nextTile == null || nextTile == curTile) { // Get the next tile if (path == null || path.Length() == 0) { // Generate path path = new Path_AStar(activeArea, curTile, DestTile); if (path.Length() == 0) { StopMove(); // Debug.LogError("Enemy's PathAStar did not return a path!"); return; } // Ignore the first tile since we are on it nextTile = path.Dequeue(); } nextTile = path.Dequeue(); SetDirection(); ENTERABILITY nextTileEnterability = nextTile.CanEnter(); switch (nextTileEnterability) { case ENTERABILITY.Never: // Cant go on StopMove(); return; } if (nextTile == curTile) { StopMove(); return; } } // How much distance can we travel this frame? float distToTravel = Mathf.Sqrt( Mathf.Pow(curTile.X - nextTile.X, 2) + Mathf.Pow(curTile.Y - nextTile.Y, 2)); // How much distance can we travel this frame? float distThisFrame = speed.GetValue() / nextTile.MovementCost * Time.deltaTime; float perThisFrame = distThisFrame / distToTravel; movePercent += perThisFrame; if (movePercent >= 1) { movePercent = 0; curTile = nextTile; } }
// Set Patrol Point in 4 Quadrant public void SetValidPatrolPoints(World world) { minionState = MinionState.Patrol; patrolPoints = new List <Tile>(); if (patrolRange == 0) { return; } // Set tile graph width and height int startW = charStartTile.X - patrolRange <= 0 ? 0 : charStartTile.X - patrolRange; int endW = charStartTile.X + patrolRange >= world.Width - 1 ? world.Width - 1 : charStartTile.X + patrolRange; //Debug.Log("StartWidth : " + startW + "EndWidth : " + endW); int startH = charStartTile.Z - patrolRange <= 0 ? 0 : charStartTile.Z - patrolRange; int endH = charStartTile.Z + patrolRange >= world.Height - 1 ? world.Height - 1 : charStartTile.Z + patrolRange; //Debug.Log("StartHeight : " + startH + "EndHeight : " + endH); // Create Tile Graph within Patrol range mTileGraph = new Path_TileGraph(startW, endW, startH, endH); //// Check 4 Quadrant have at least 1 patrol tile? Tile LUtile = null; Tile RUtile = null; Tile LLtile = null; Tile RLtile = null; // ======Loop Outer in 4 Quadrant============ // Left-Lower Q ,X(min > max), Z(min > max) // Loop the X axis farest tile for (int x = startW; x < charStartTile.X; x++) { int z = startH; Tile checkT = world.GetTileAt(x, z); if (LLtile == null && checkT != charStartTile) { mPathAStar = new Path_AStar(false, charStartTile, checkT, mTileGraph, startW, endW, startH, endH); // There is valid pathfinder to this tile if (mPathAStar.Length() != 0) { Debug.Log("Add LLtile to patrol point : " + checkT.X + "," + checkT.Z); LLtile = checkT; } } } // Loop the Z axis farest tile for (int z = startH; z < charStartTile.Z; z++) { int x = startW; Tile checkT = world.GetTileAt(x, z); //Debug.Log("Check tile : " + checkT.X + "," + checkT.Z); // Check the farest tile first and Check it not CharTile if (LLtile == null && checkT != charStartTile) { mPathAStar = new Path_AStar(false, charStartTile, checkT, mTileGraph, startW, endW, startH, endH); // There is valid pathfinder to this tile if (mPathAStar.Length() != 0) { Debug.Log("Add LLtile to patrol point : " + checkT.X + "," + checkT.Z); LLtile = checkT; } } } // Left-Upper Q ,X(min > max),Z(max > min) // Loop the X axis farest tile for (int x = startW; x <= charStartTile.X; x++) { int z = endH; Tile checkT = world.GetTileAt(x, z); if (LUtile == null && checkT != charStartTile) { mPathAStar = new Path_AStar(false, charStartTile, checkT, mTileGraph, startW, endW, startH, endH); // There is valid pathfinder to this tile if (mPathAStar.Length() != 0) { Debug.Log("Add LUtile to patrol point : " + checkT.X + "," + checkT.Z); LUtile = checkT; } } } // Loop the Z axis farest tile for (int z = endH; z >= charStartTile.Z; z--) { int x = startW; Tile checkT = world.GetTileAt(x, z); // Check the farest tile first and Check it not CharTile if (LUtile == null && checkT != charStartTile) { mPathAStar = new Path_AStar(false, charStartTile, checkT, mTileGraph, startW, endW, startH, endH); // There is valid pathfinder to this tile if (mPathAStar.Length() != 0) { Debug.Log("Add LUtile to patrol point : " + checkT.X + "," + checkT.Z); LUtile = checkT; } } } // Right-Upper Q ,X(max > min),Z(max > min) // Loop the X axis farest tile for (int x = endW; x >= charStartTile.X; x--) { int z = endH; Tile checkT = world.GetTileAt(x, z); // Check the farest tile first and Check it not CharTile if (RUtile == null && checkT != charStartTile) { mPathAStar = new Path_AStar(false, charStartTile, checkT, mTileGraph, startW, endW, startH, endH); // There is valid pathfinder to this tile if (mPathAStar.Length() != 0) { Debug.Log("Add RUtile to patrol point : " + checkT.X + "," + checkT.Z); RUtile = checkT; } } } // Loop the Z axis farest tile for (int z = endH; z >= charStartTile.Z; z--) { int x = endW; Tile checkT = world.GetTileAt(x, z); // Check the farest tile first and Check it not CharTile if (RUtile == null && checkT != charStartTile) { mPathAStar = new Path_AStar(false, charStartTile, checkT, mTileGraph, startW, endW, startH, endH); // There is valid pathfinder to this tile if (mPathAStar.Length() != 0) { Debug.Log("Add RUtile to patrol point : " + checkT.X + "," + checkT.Z); RUtile = checkT; } } } // Right-Lower Q ,X(max > min),Z(min > max) // Loop the X axis farest tile for (int x = endW; x >= charStartTile.X; x--) { int z = startH; Tile checkT = world.GetTileAt(x, z); // Check the farest tile first and Check it not CharTile if (RLtile == null && checkT != charStartTile) { mPathAStar = new Path_AStar(false, charStartTile, checkT, mTileGraph, startW, endW, startH, endH); // There is valid pathfinder to this tile if (mPathAStar.Length() != 0) { Debug.Log("Add RLtile to patrol point : " + checkT.X + "," + checkT.Z); RLtile = checkT; } } } // Loop the Z axis farest tile for (int z = startH; z > charStartTile.Z; z++) { int x = startW; Tile checkT = world.GetTileAt(x, z); // Check the farest tile first and Check it not CharTile if (RLtile == null && checkT != charStartTile) { mPathAStar = new Path_AStar(false, charStartTile, checkT, mTileGraph, startW, endW, startH, endH); // There is valid pathfinder to this tile if (mPathAStar.Length() != 0) { Debug.Log("Add RLtile to patrol point : " + checkT.X + "," + checkT.Z); RLtile = checkT; } } } // ======== Loop Inner in 4 Quadrant ========== // Left-Lower Q ,X(min > max), Z(min > max) // Loop the inner tile if (LLtile == null) { for (int x = startW + 1; x < charStartTile.X; x++) { for (int z = startH + 1; z < charStartTile.Z; z++) { Tile checkT = world.GetTileAt(x, z); if (LLtile == null && checkT != charStartTile) { mPathAStar = new Path_AStar(false, charStartTile, checkT, mTileGraph, startW, endW, startH, endH); // There is valid pathfinder to this tile if (mPathAStar.Length() != 0) { Debug.Log("Add LLtile to patrol point : " + checkT.X + "," + checkT.Z); LLtile = checkT; } } } } } // Left-Upper Q ,X(min > max),Z(max > min) // Loop the X axis farest tile if (LUtile == null) { for (int x = startW + 1; x <= charStartTile.X; x++) { for (int z = endH - 1; z >= charStartTile.Z; z--) { Tile checkT = world.GetTileAt(x, z); if (LUtile == null && checkT != charStartTile) { mPathAStar = new Path_AStar(false, charStartTile, checkT, mTileGraph, startW, endW, startH, endH); // There is valid pathfinder to this tile if (mPathAStar.Length() != 0) { Debug.Log("Add LUtile to patrol point : " + checkT.X + "," + checkT.Z); LUtile = checkT; } } } } } // Right-Upper Q ,X(max > min),Z(max > min) // Loop the X axis farest tile if (RUtile == null) { for (int x = endW - 1; x >= charStartTile.X; x--) { for (int z = endH - 1; z >= charStartTile.Z; z--) { Tile checkT = world.GetTileAt(x, z); // Check the farest tile first and Check it not CharTile if (RUtile == null && checkT != charStartTile) { mPathAStar = new Path_AStar(false, charStartTile, checkT, mTileGraph, startW, endW, startH, endH); // There is valid pathfinder to this tile if (mPathAStar.Length() != 0) { Debug.Log("Add RUtile to patrol point : " + checkT.X + "," + checkT.Z); RUtile = checkT; } } } } } // Right-Lower Q ,X(max > min),Z(min > max) // Loop the X axis farest tile if (RLtile == null) { for (int x = endW - 1; x >= charStartTile.X; x--) { for (int z = startH + 1; z < charStartTile.Z; z++) { Tile checkT = world.GetTileAt(x, z); // Check the farest tile first and Check it not CharTile if (RLtile == null && checkT != charStartTile) { mPathAStar = new Path_AStar(false, charStartTile, checkT, mTileGraph, startW, endW, startH, endH); // There is valid pathfinder to this tile if (mPathAStar.Length() != 0) { Debug.Log("Add RLtile to patrol point : " + checkT.X + "," + checkT.Z); RLtile = checkT; } } } } } if (LUtile != null) { patrolPoints.Add(LUtile); } if (RUtile != null) { patrolPoints.Add(RUtile); } if (LLtile != null) { patrolPoints.Add(LLtile); } if (RLtile != null) { patrolPoints.Add(RLtile); } }
void Update_DoMovement(float deltaTime) { if (currTile == destTile) { path_AStar = null; return; } if (nextTile == null || nextTile == currTile) { //get the next tile from pathfinding if (path_AStar == null || path_AStar.Length() == 0) { path_AStar = new Path_AStar(WorldController.Instance.World, currTile, destTile); if (path_AStar.Length() == 0) { Debug.LogError("Path_AStar returned no path to destination"); AbandonJob(); path_AStar = null; return; } nextTile = path_AStar.GetNextTile(); } nextTile = path_AStar.GetNextTile(); //removes it from the path list if (nextTile == currTile) { Debug.Log("Update_DoMovement::NextTile is curr tile ?"); } } float totalDisToTravel = Vector3Int.Distance(currTile, nextTile); //total distance from A to B float movementCost = 1; ENTERABILITY enterability = ENTERABILITY.Yes; if (WorldController.Instance.World.foundationGameMap.ContainsKey(nextTile) == true) { movementCost = WorldController.Instance.World.foundationGameMap[nextTile].movementCost; try{ enterability = WorldController.Instance.World.foundationGameMap[nextTile].IsEnterable(WorldController.Instance.World.foundationGameMap[nextTile]); } catch { enterability = ENTERABILITY.Never; } if (movementCost > 0 && enterability == ENTERABILITY.Never) { enterability = ENTERABILITY.Yes; } } if (enterability == ENTERABILITY.Never) { Debug.LogError("Character " + name + " was trying to enter an unwalkable tile"); nextTile = currTile; path_AStar = null; return; } else if (enterability == ENTERABILITY.Soon) { //Have to wait to enter the tile, this is likely a door //No bailing on the movement/path, but we do return now and don't actually process the movement; return; } float distanceThisFrame = speed / movementCost * deltaTime; //how much distance can character tavel this update float percantageThisFrame = distanceThisFrame / totalDisToTravel; //how much is that in percentage movementPercentage += percantageThisFrame; //increase percentage moved if (movementPercentage >= 1) { //Destination reached currTile = nextTile; movementPercentage = 0; } if (cbCharacterMoved != null) { cbCharacterMoved(this); } }
void Update_DoMovement(float deltaTime) { if (CurrTile == DestTile) { pathAStar = null; return; // We're already were we want to be. } // currTile = The tile I am currently in (and may be in the process of leaving) // nextTile = The tile I am currently entering // destTile = Our final destination -- we never walk here directly, but instead use it for the pathfinding if (NextTile == null || NextTile == CurrTile) { // Get the next tile from the pathfinder. if (pathAStar == null || pathAStar.Length() == 0) { // Generate a path to our destination pathAStar = new Path_AStar(World.current, CurrTile, DestTile); // This will calculate a path from curr to dest. if (pathAStar.Length() == 0) { Debug.LogError("Path_AStar returned no path to destination!"); AbandonJob(); return; } // Let's ignore the first tile, because that's the tile we're currently in. NextTile = pathAStar.Dequeue(); } // Grab the next waypoint from the pathing system! NextTile = pathAStar.Dequeue(); if (NextTile == CurrTile) { //Debug.LogError("Update_DoMovement - nextTile is currTile?"); } } // At this point we should have a valid nextTile to move to. // What's the total distance from point A to point B? // We are going to use Euclidean distance FOR NOW... // But when we do the pathfinding system, we'll likely // switch to something like Manhattan or Chebyshev distance float distToTravel = Mathf.Sqrt( Mathf.Pow(CurrTile.X - NextTile.X, 2) + Mathf.Pow(CurrTile.Y - NextTile.Y, 2) ); if (NextTile.IsEnterable() == ENTERABILITY.Never) { // Most likely a wall got built, so we just need to reset our pathfinding information. // FIXME: Ideally, when a wall gets spawned, we should invalidate our path immediately, // so that we don't waste a bunch of time walking towards a dead end. // To save CPU, maybe we can only check every so often? // Or maybe we should register a callback to the OnTileChanged event? Debug.LogError("FIXME: A character was trying to enter an unwalkable tile."); NextTile = null; // our next tile is a no-go pathAStar = null; // clearly our pathfinding info is out of date. return; } else if (NextTile.IsEnterable() == ENTERABILITY.Soon) { // We can't enter the NOW, but we should be able to in the // future. This is likely a DOOR. // So we DON'T bail on our movement/path, but we do return // now and don't actually process the movement. return; } // How much distance can be travel this Update? float distThisFrame = speed / NextTile.movementCost * deltaTime; // How much is that in terms of percentage to our destination? float percThisFrame = distThisFrame / distToTravel; // Add that to overall percentage travelled. movementPercentage += percThisFrame; if (movementPercentage >= 1) { // We have reached our destination // TODO: Get the next tile from the pathfinding system. // If there are no more tiles, then we have TRULY // reached our destination. CurrTile = NextTile; movementPercentage = 0; // FIXME? Do we actually want to retain any overshot movement? } }
/// <summary> /// Checks weather the current job has all the materials in place and if not instructs the working character to get the materials there first. /// Only ever returns true if all materials for the job are at the job location and thus signals to the calling code, that it can proceed with job execution. /// </summary> /// <returns></returns> bool CheckForJobMaterials() { if (myJob.HasAllMaterial()) { return(true); //we can return early } // At this point we know, that the job still needs materials. // First we check if we carry any materials the job wants by chance. if (inventory != null) { if (myJob.DesiresInventoryType(inventory) > 0) { // If so, deliver the goods. // Walk to the job tile, then drop off the stack into the job. if (CurrTile == myJob.tile) { // We are at the job's site, so drop the inventory World.current.inventoryManager.PlaceInventory(myJob, inventory); myJob.DoWork(0); // This will call all cbJobWorked callbacks, because even though // we aren't progressing, it might want to do something with the fact // that the requirements are being met. //at this point we should dump anything in our inventory DumpExcessInventory(); } else { // We still need to walk to the job site. DestTile = myJob.tile; return(false); } } else { // We are carrying something, but the job doesn't want it! // Dump the inventory so we can be ready to carry what the job actually wants. DumpExcessInventory(); } } else { // At this point, the job still requires inventory, but we aren't carrying it! // Are we standing on a tile with goods that are desired by the job? Debug.Log("Standing on Tile check"); if (CurrTile.inventory != null && myJob.DesiresInventoryType(CurrTile.inventory) > 0 && (myJob.canTakeFromStockpile || CurrTile.furniture == null || CurrTile.furniture.IsStockpile() == false)) { // Pick up the stuff! Debug.Log("Pick up the stuff"); World.current.inventoryManager.PlaceInventory( this, CurrTile.inventory, myJob.DesiresInventoryType(CurrTile.inventory) ); } else { // Walk towards a tile containing the required goods. Debug.Log("Walk to the stuff"); Debug.Log(myJob.canTakeFromStockpile); // Find the first thing in the Job that isn't satisfied. Inventory desired = myJob.GetFirstDesiredInventory(); if (CurrTile != NextTile) { // We are still moving somewhere, so just bail out. return(false); } // Any chance we already have a path that leads to the items we want? if (pathAStar != null && pathAStar.EndTile() != null && pathAStar.EndTile().inventory != null && (pathAStar.EndTile().furniture != null && !(myJob.canTakeFromStockpile == false && pathAStar.EndTile().furniture.IsStockpile() == true)) && pathAStar.EndTile().inventory.objectType == desired.objectType) { // We are already moving towards a tile that contains what we want! // so....do nothing? } else { Path_AStar newPath = World.current.inventoryManager.GetPathToClosestInventoryOfType( desired.objectType, CurrTile, desired.maxStackSize - desired.stackSize, myJob.canTakeFromStockpile ); if (newPath == null || newPath.Length() < 1) { //Debug.Log("pathAStar is null and we have no path to object of type: " + desired.objectType); // Cancel the job, since we have no way to get any raw materials! Debug.Log("No tile contains objects of type '" + desired.objectType + "' to satisfy job requirements."); AbandonJob(); return(false); } Debug.Log("pathAStar returned with length of: " + newPath.Length()); DestTile = newPath.EndTile(); // Since we already have a path calculated, let's just save that. pathAStar = newPath; // Ignore first tile, because that's what we're already in. NextTile = newPath.Dequeue(); } // One way or the other, we are now on route to an object of the right type. return(false); } } return(false); // We can't continue until all materials are satisfied. }
// Job myJob; // // void Update_DoJob (float deltaTime) { // if (myJob == null) { // myJob = currTile.world.jobQueue.Dequeue (); // // if (myJob != null) { // // I got a job! // destTile = myJob.tile; // // // Register the ended job callback // myJob.RegisterJobCompleteCallback (OnJobEnded); // myJob.RegisterJobCancelCallback (OnJobEnded); // } // } // // // moving the character // if (myJob != null && currTile == myJob.tile) { // myJob.DoJob(deltaTime); // } // // } // // public void AbandonJob() { // nextTile = destTile = currTile; // pathAStar = null; // currTile.world.jobQueue.Enqueue(myJob); // myJob = null; // } void Update_DoMovement(float deltaTime) { if (currTile == destTile) { pathAStar = null; return; // where are already where we want to be } if (nextTile == null || nextTile == currTile) { // get the next tile from the pathfinder if (pathAStar == null || pathAStar.Length() == 0) { // generate a new path to our destination pathAStar = new Path_AStar(WorldController.Instance.world, currTile, destTile); if (pathAStar.Length() == 0) { //Debug.LogError ("pathAStar returned no path to destination"); // FIXME: the job should be re-enqued // AbandonJob (); pathAStar = null; return; } nextTile = pathAStar.Dequeue(); } // FIXME: discarding the first node, the current tile of the character // from the pathfinding system. Maybe there's a better way? nextTile = pathAStar.Dequeue(); if (nextTile == currTile) { Debug.LogError("Update_DoMovement: nextTile is currTile?"); } } float distToTravel = Vector2.Distance(new Vector2(currTile.X, currTile.Y), new Vector2(nextTile.X, nextTile.Y)); // float distToTravel = Mathf.Sqrt (Mathf.Pow (currTile.X - nextTile.X, 2) + Mathf.Pow (currTile.Y - nextTile.Y, 2)); if (nextTile.movementCost == 0) { //FIXME : this is getting called too much. shouldnt be at all? Debug.LogError("character trying to traverse an unwalkble tile"); nextTile = null; pathAStar = null; return; } float percThisFram = (speed * deltaTime) / (distToTravel * nextTile.movementCost); movementPercentage += percThisFram; if (movementPercentage >= 1) { // get the next destination tile from the pathfinding system currTile = nextTile; movementPercentage = 0; } }
private void Update_DoMovement(float deltaTime) { if (CurrTile == DestTile) { // We're already were we want to be. pathAStar = null; IsWalking = false; VisualPath.Instance.RemoveVisualPoints(name); return; } if (nextTile == null || nextTile == CurrTile) { // Get the next tile from the pathfinder. if (pathAStar == null || pathAStar.Length() == 0) { // Generate a path to our destination. // This will calculate a path from current tile to destination tile. pathAStar = new Path_AStar(World.Current, CurrTile, DestTile); if (pathAStar.Length() == 0) { Debug.ULogErrorChannel("Character", "Path_AStar returned no path to destination!"); AbandonJob(false); return; } // Let's ignore the first tile, because that's the tile we're currently in. nextTile = pathAStar.Dequeue(); } if (IsSelected) { VisualPath.Instance.SetVisualPoints(name, pathAStar.GetList()); } IsWalking = true; // Grab the next waypoint from the pathing system! nextTile = pathAStar.Dequeue(); if (nextTile == CurrTile) { IsWalking = false; } } if (nextTile.IsEnterable() == Enterability.Never) { //// Most likely a wall got built, so we just need to reset our pathfinding information. //// FIXME: Ideally, when a wall gets spawned, we should invalidate our path immediately, //// so that we don't waste a bunch of time walking towards a dead end. //// To save CPU, maybe we can only check every so often? //// Or maybe we should register a callback to the OnTileChanged event? //// Debug.ULogErrorChannel("FIXME", "A character was trying to enter an unwalkable tile."); nextTile = null; // our next tile is a no-go pathAStar = null; // clearly our pathfinding info is out of date. return; } else if (nextTile.IsEnterable() == Enterability.Soon) { // We can't enter the NOW, but we should be able to in the // future. This is likely a DOOR. // So we DON'T bail on our movement/path, but we do return // now and don't actually process the movement. return; } CharacterFacing(); // At this point we should have a valid nextTile to move to. // What's the total distance from point A to point B? // We are going to use Euclidean distance FOR NOW... // But when we do the pathfinding system, we'll likely // switch to something like Manhattan or Chebyshev distance float distToTravel = Mathf.Sqrt( Mathf.Pow(CurrTile.X - nextTile.X, 2) + Mathf.Pow(CurrTile.Y - nextTile.Y, 2)); // How much distance can be travel this Update? float distThisFrame = speed / nextTile.MovementCost * deltaTime; // How much is that in terms of percentage to our destination? float percThisFrame = distThisFrame / distToTravel; // Add that to overall percentage travelled. movementPercentage += percThisFrame; if (movementPercentage >= 1) { // We have reached our destination //// TODO: Get the next tile from the pathfinding system. //// If there are no more tiles, then we have TRULY //// reached our destination. CurrTile = nextTile; movementPercentage = 0; // FIXME? Do we actually want to retain any overshot movement? } }
void Update_DoMovement(float deltaTime) { if (currTile == destTile) { pathAStar = null; return; //we're already were we want to be. } if (nextTile == null || nextTile == currTile) { //get the next tile from the pathfinder if (pathAStar == null || pathAStar.Length() == 0) { //calculate a path from curr to dest pathAStar = new Path_AStar(currTile.world, currTile, destTile); if (pathAStar.Length() == 0) { Debug.LogError("Path_AStar returned no path to destination !"); AbandonJob(); pathAStar = null; return; } } //grab the next waypoint from the pathfinding system nextTile = pathAStar.Dequeue(); if (nextTile == currTile) { Debug.LogError("Update_DoMovement - nextTile is currTile ?"); } } /* if(pathAStar.Length() == 1 ){ * return; * } */ //at this point we should have a valid nextTile to move to ! //on détermnie la distance entre les deux points theoreme de pythagore mec ?? //for now it is euclidian, but when pathfinding system we do, manhattan or chebyshev system BRO !! //Pow !!! //public static float Pow(float f, float p); //Returns f raised to power p. //public static float Sqrt(float f); -- Returns square root of f. float distToTravel = Mathf.Sqrt(Mathf.Pow(currTile.X - nextTile.X, 2) + Mathf.Pow(currTile.Y - nextTile.Y, 2)); //on détermine la distance par frame pour qu'elle soit égale quelque que soit le nombre de fps //how much distance can be traveled this update float distThisFrame = speed * deltaTime; // how much is that in terms of percentage to our destination ? (de 0 a 1) float percThisFrame = distThisFrame / distToTravel; //add that overall poercentage travelled movementPercentage += percThisFrame; if (movementPercentage >= 1) { //we have reached our destination //TODO : get the next tile from the pathfinding system //If there are no more tiles, then we have TRULKY reach our destination currTile = nextTile; movementPercentage = 0; //FIXME do we actually want to retain any overshot movement ? } }
/// <summary> /// Checks whether the current job has all the materials in place and if not instructs the working character to get the materials there first. /// Only ever returns true if all materials for the job are at the job location and thus signals to the calling code, that it can proceed with job execution. /// </summary> /// <returns></returns> private bool CheckForJobMaterials() { List <string> fulfillableInventoryRequirements = new List <string>(); if (MyJob != null && MyJob.IsNeed && MyJob.Critical == false) { MyJob.tile = jobTile = new Path_AStar(World.Current, CurrTile, null, MyJob.JobObjectType, 0, false, true).EndTile(); } if (MyJob == null || MyJob.MaterialNeedsMet()) { // We can return early. return(true); } else { fulfillableInventoryRequirements = MyJob.FulfillableInventoryRequirements(); // If we somehow get here and fulfillableInventoryRequirements is empty then there is a problem! if (fulfillableInventoryRequirements == null || fulfillableInventoryRequirements.Count() == 0) { Debug.ULogChannel("Character", "CheckForJobMaterials: no fulfillable inventory requirements"); AbandonJob(true); return(false); } } // At this point we know that the job still needs materials and these needs are satisfiable. // First we check if we carry any materials the job wants by chance. if (inventory != null) { if (MyJob.AmountDesiredOfInventoryType(inventory) > 0) { // If so, deliver the goods. // Walk to the job tile, then drop off the stack into the job. if (CurrTile == JobTile) { // We are at the job's site, so drop the inventory World.Current.inventoryManager.PlaceInventory(MyJob, inventory); MyJob.DoWork(0); // This will call all cbJobWorked callbacks, because even though // we aren't progressing, it might want to do something with the fact // that the requirements are being met. // at this point we should dump anything in our inventory DumpExcessInventory(); } else { // We still need to walk to the job site. DestTile = JobTile; return(false); } } else { // We are carrying something, but the job doesn't want it! // Dump the inventory so we can be ready to carry what the job actually wants. DumpExcessInventory(); } } else { // At this point, the job still requires inventory, but we aren't carrying it! // Are we standing on a tile with goods that are desired by the job? if (CurrTile.Inventory != null && MyJob.AmountDesiredOfInventoryType(CurrTile.Inventory) > 0 && !CurrTile.Inventory.Locked && (MyJob.canTakeFromStockpile || CurrTile.Furniture == null || CurrTile.Furniture.IsStockpile() == false)) { // Pick up the stuff! World.Current.inventoryManager.PlaceInventory( this, CurrTile.Inventory, MyJob.AmountDesiredOfInventoryType(CurrTile.Inventory)); } else { // Walk towards a tile containing the required goods. if (CurrTile != nextTile) { // We are still moving somewhere, so just bail out. return(false); } // Any chance we already have a path that leads to the items we want? // Check that we have an end tile and that it has content. // Check if contains the desired objectType�. if (WalkingToUsableInventory() && fulfillableInventoryRequirements.Contains(pathAStar.EndTile().Inventory.ObjectType)) { // We are already moving towards a tile that contains what we want! // so....do nothing? return(false); } else { Inventory desired = null; Path_AStar newPath = null; foreach (string itemType in fulfillableInventoryRequirements) { desired = MyJob.inventoryRequirements[itemType]; newPath = World.Current.inventoryManager.GetPathToClosestInventoryOfType( desired.ObjectType, CurrTile, desired.MaxStackSize - desired.StackSize, MyJob.canTakeFromStockpile); if (newPath == null || newPath.Length() < 1) { // Try the next requirement Debug.ULogChannel("Character", "No tile contains objects of type '" + desired.ObjectType + "' to satisfy job requirements."); continue; } // else, there is a valid path to an item that will satisfy the job break; } if (newPath == null || newPath.Length() < 1) { // tried all requirements and found no path Debug.ULogChannel("Character", "No reachable tile contains objects able to satisfy job requirements."); AbandonJob(true); return(false); } Debug.ULogChannel("Character", "pathAStar returned with length of: " + newPath.Length()); DestTile = newPath.EndTile(); // Since we already have a path calculated, let's just save that. pathAStar = newPath; // Ignore first tile, because that's what we're already in. nextTile = newPath.Dequeue(); } // One way or the other, we are now on route to an object of the right type. return(false); } } return(false); // We can't continue until all materials are satisfied. }
/// <summary> /// Update all movement related things of a character /// </summary> /// <param name="deltaTime">The time passed since last tick</param> void UpdateCharacter_Movement(float deltaTime) { // Is movement needed? Is character already at the correct location if (currentTile == DestinationTile) { // Reset the current A* path path_AStar = null; return; } // currentTile = The tile a character is currently standing on and might be in the process of leaving // nextTile = The tile a character is entering // destinationTile = The final destination -- a character never gets here directly, but it's used for pathfinding instead // Grab 'next' nextTile if (nextTile == null || nextTile == currentTile) { // Get next tile from the path (calculted path wiht A*) if (path_AStar == null || path_AStar.Length() == 0) { // Generate new A* path from currentTile to destinationTile path_AStar = new Path_AStar(currentTile.World, currentTile, DestinationTile); // Check if path isn't null if (path_AStar.Length() == 0) { Debug.LogError("Path_AStar: Returned no path to destination!"); // FIXME: Job should get added back to queue AbandonJob(); return; } // Grab the first tile and right away override it. // First tile is the file the character is standing on, this results in some problems. (tile might have a movementCost of 0, like a wall that was just build by the character) nextTile = path_AStar.DequeueNextTile(); } // Grab the next tile nextTile = path_AStar.DequeueNextTile(); // Check for error if (nextTile == currentTile) { Debug.LogError("UpdateCharacter_Movement: nextTile == currentTile? -- Only valid for startingTile."); } } // At this point there a valid nextTile to move to. // Total distance from A to B (pythagorean theorem) float totalDistanceToTravel = Mathf.Sqrt( Mathf.Pow(currentTile.X - nextTile.X, 2) + Mathf.Pow(currentTile.Y - nextTile.Y, 2)); /// Check if movementCost is 0, which it never should be. /// Set nextTile to null, so that the character won't move. /// Set path_AStart to null, this one is no longer valid. /// MovementCost can be 0 if something was build in the mean time if (nextTile.IsEnterable() == EnterAbility.Never) { Debug.LogError("FIXME: A charcter tried to enter an unwalkable tile!"); nextTile = null; path_AStar = null; return; } // Character can't enter right now, but will be in the near future. (like a door or something) else if (nextTile.IsEnterable() == EnterAbility.Soon) { // Temp return; } // Distance to travel in one tick (one frame) // nextTile.MovementCost can be 0 (which would throw an error) but it should never happen. // Moving to a tile with a movementCost of 0 is NOT allowed float distanceThisTick = (movementSpeed / nextTile.MovementCost) * deltaTime; // Progression in one tick float progressionThisTick = distanceThisTick / totalDistanceToTravel; // Increase the movement progression each tick movementProgression += progressionThisTick; // Has the character reached it's destination yet? if (movementProgression >= 1) { currentTile = nextTile; movementProgression = 0; } }