void UpdateDoMovement(float deltaTime) { if (currentTile == destinationTile) { pathAStar = null; return; } if (nextTile == null || nextTile == currentTile) { if (pathAStar == null || pathAStar.count() == 0) { pathAStar = new Path_AStar(World.worldInstance, currentTile, destinationTile); if (pathAStar.count() == 0) { Debug.LogError("Path_AStar -- returned (0) no path to destinationTile"); AbbandonJob(); return; } pathAStar.Dequeue(); } nextTile = pathAStar.Dequeue(); /*if (nextTile == destinationTile) { * nextTile = currentTile; * destinationTile = currentTile; * }*/ } float distanceToTravel = Mathf.Sqrt(Mathf.Pow(currentTile.X - nextTile.X, 2) + Mathf.Pow(currentTile.Y - nextTile.Y, 2)); if (nextTile.isAccessible() == Accessiblity.NEVER) { Debug.LogError("Charcter tried to enter in unwalkable tile"); nextTile = null; pathAStar = null; return; } else if (nextTile.isAccessible() == Accessiblity.SOON) { return; } float distanceThisFrame = speed / nextTile.movementCost * deltaTime; float percentageThisFrame = distanceThisFrame / distanceToTravel; movementPercentage += percentageThisFrame; if (movementPercentage >= 1) { currentTile = nextTile; movementPercentage = 0; } }
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; } }
private void OnCharacterChanged(Character character) { if (_characterGameObjectMap.ContainsKey(character) == false) { Debug.LogError("OnCharacterChanged failed - Character requested that is not in the map!"); return; } var charGo = _characterGameObjectMap[character]; charGo.transform.position = new Vector3(character.X, character.Y, 0); // Draw 'footsteps' for any current path on this character if (character.CurrentTile != null && character.Path != null && character.Path.Length() > 0) { var p = new Path_AStar(character.Path); Tile t; do { t = p.Dequeue(); if (t != null) { var go = new GameObject(); go.name = "footstep"; go.transform.position = new Vector3(t.X, t.Y, 0); var sprite = go.AddComponent <SpriteRenderer>(); sprite.sprite = SpriteManager.Instance.GetSprite("colonist", "footstep"); sprite.sortingLayerName = "Characters"; sprite.enabled = true; Destroy(go, 1); } } while (t != null); } // Set the various subsprite visibility depending on what the situation is for this character. _characterSpriteParts[character]["working"].enabled = character.CurrentState == Character.State.WorkingJob; _characterSpriteParts[character]["shield"].enabled = character.ShieldStatus; }
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 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 ? } }
void Update_DoMovement(float deltaTime) { if (currTile == destTile) { pathAStar = null; return; } if (nextTile == null || nextTile == currTile) { //Get the next tile from the pathfinder if (pathAStar == null) { //Generate a path to our destination pathAStar = new Path_AStar(currTile.world, currTile, destTile); if (pathAStar.Length() == 0 && currTile != destTile) { Debug.LogError("Path_AStar returned no path to destination!"); //FIXME: Job should maybe be re-enqued instead? AbandonJob(); pathAStar = null; return; } //nextTile = pathAStar.Dequeue(); } nextTile = pathAStar.Dequeue(); if (nextTile == currTile) { Debug.LogError("Update_DoMovement - nextTile is currTile?"); } } if (nextTile.GetEnterability() == Enterability.Never) { //Most likely 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 dont 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; pathAStar = null; return; } else if (nextTile.GetEnterability() == Enterability.Soon) { // We can't enter the tile NOW, but we should be able to do so in the future //This is likely a door. //We dont bail out our movement path but we do return now and don't actually process movement return; } 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 = distToTravel <= 0 ? 1 - movementPercentage : distThisFrame / distToTravel; movementPercentage += percThisFrame; if (movementPercentage >= 1) { //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; } return; }
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? } }
/// <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 }
/// <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. }
void Update_DoJob(float deltaTime) { // Do I have a job? jobSearchCooldown -= Time.deltaTime; if (myJob == null) { if (jobSearchCooldown > 0) { // Don't look for job now. return; } GetNewJob(); if (myJob == null) { // There was no job on the queue for us, so just return. jobSearchCooldown = UnityEngine.Random.Range(0.1f, 0.5f); DestTile = currTile; return; } } // We have a job! (And the job tile is reachable) // STEP 1: Does the job have all the materials it needs? if (myJob.HasAllMaterial() == false) { // No, we are missing something! // STEP 2: Are we CARRYING anything that the job location wants? 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. // Are we still carrying things? if (inventory.stackSize == 0) { inventory = null; } else { Debug.LogError("Character is still carrying inventory, which shouldn't be. Just setting to NULL for now, but this means we are LEAKING inventory."); inventory = null; } } else { // We still need to walk to the job site. DestTile = myJob.tile; return; } } else { // We are carrying something, but the job doesn't want it! // Dump the inventory at our feet // TODO: Actually, walk to the nearest empty tile and dump it there. if (World.current.inventoryManager.PlaceInventory(currTile, inventory) == false) { Debug.LogError("Character tried to dump inventory into an invalid tile (maybe there's already something here."); // FIXME: For the sake of continuing on, we are still going to dump any // reference to the current inventory, but this means we are "leaking" // inventory. This is permanently lost now. inventory = null; } } } 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.canTakeFromStockpile || currTile.furniture == null || currTile.furniture.IsStockpile() == false) && myJob.DesiresInventoryType(currTile.inventory) > 0) { // 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; } // 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 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) { //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! AbandonJob(); return; } Debug.Log("pathAStar returned with length of: " + newPath.Length()); if (newPath == null || newPath.Length() == 0) { Debug.Log("No tile contains objects of type '" + desired.objectType + "' to satisfy job requirements."); AbandonJob(); return; } 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; } } return; // We can't continue until all materials are satisfied. } // If we get here, then the job has all the material that it needs. // Lets make sure that our destination tile is the job site tile. DestTile = myJob.tile; // Are we there yet? if (currTile == myJob.tile) { // We are at the correct tile for our job, so // execute the job's "DoWork", which is mostly // going to countdown jobTime and potentially // call its "Job Complete" callback. myJob.DoWork(deltaTime); } // Nothing left for us to do here, we mostly just need Update_DoMovement to // get us where we want to go. }
void Update_DoMovement(float deltaTime) { if (currTile == destTile) { pathAStar = null; return; // We're already where we want to be. } // currTile = Tile I'm in and in process of leaving. // nextTile = Tile I'm currently entering. // destTile = Our final destination -- we never walk here directly but use it for the pathfinding. if (nextTile == null || nextTile == currTile) { // I don't have a nextTile so I get it from the pathfinder. if (pathAStar == null || pathAStar.Lenght() == 0){ // I don't have a pathfinder so I create one. pathAStar = new Path_AStar(WorldController.Instance.world,currTile, destTile); if (pathAStar.Lenght() == 0) { // Pathfinding couldn't get a path to the destination. Debug.LogError("Path_AStar returned no path to destination!"); // Re-enqueue Job and set current to null. AbandonJob(); return; } // Let's ignore the first tile, because that's the tile we're currently in. nextTile = pathAStar.Dequeue(); } // Now we have a path. // Grab next waypoint from the path system nextTile = pathAStar.Dequeue(); if (nextTile == currTile) { Debug.LogError("Update_DoMovement -- nextTile is currTile?"); } } // At this point we have a valid nextTile // Total distance. float distToTravel = Mathf.Sqrt(Mathf.Pow(currTile.X - nextTile.X, 2f) + Mathf.Pow(currTile.Y - nextTile.Y, 2f)); if (nextTile.IsEnterable() == ENTERABILITY.Never) { // Most likely a wall got built after path creation. // FIXME: When a wall gets spawned we should invalidate our pathfinding imediatale Debug.LogError("Update_DoMovement -- Trying to move to an unwalkable tile or walkable tile with moveCost of 0."); 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) { // The tile we are trying to enter is technically walkable (i.e. not a wall), // but are we allowed to enter it right now. // We return without processing the movement. return; } // Distance travelled this update. float distThisFrame = speed/nextTile.movementCost * deltaTime; // Percentage to destination this frame. float percThisFrame = distThisFrame / distToTravel; // Add that to overall percentage travelled. movementPercentage += percThisFrame; if (movementPercentage >= 1) { // We have reached our destination // TODO: Get next destination tile from pathfinding system. // TODO: If there are no more tiles, we are in the real destination currTile = nextTile; movementPercentage = 0; } if (cbCharacterChanged != null) { cbCharacterChanged(this); } }
private BehaviourTreeStatus MoveTowardsDestination_Action(float deltaTime) { // If we've already arrived at our destination, just continue. if (CurrentTile == _destinationTile) { // Debug.Log("MoveTowardsDestination_Action: Destination Reached"); return(BehaviourTreeStatus.Success); } // If we don't have a next tile yet, get one. if (_nextTile == null || _nextTile == CurrentTile) { // If we don't have a route to the current destination, plan one. if (_path == null || _path.Length() == 0 || _path.EndTile() != DestinationTile) { _path = new Path_AStar() { World = World.Instance, Start = CurrentTile, End = DestinationTile }; _path.Calculate(); } // If Path is still null, we were not able to find a route to our goal if (_path == null) { AbandonJob(); Debug.LogFormat("MoveTowardsDestination_Action: Could not find a route to the next tile!"); return(BehaviourTreeStatus.Failure); } // See if we're "close enough" to the job. // _path.Debug(); if ((_path.Length()) <= CurrentJob.MinRange) { Debug.LogFormat("{0}: Close enough to job (is {1} needs to be <= {2})", Name, (_path.Length()), CurrentJob.MinRange); // Set dest to current, just in case it was the proximity-check that got us here DestinationTile = CurrentTile; return(BehaviourTreeStatus.Success); } else { Debug.LogFormat("{0}: Distance to job is {1}, needs to be <={2}", Name, (_path.Length()), CurrentJob.MinRange); } _nextTile = _path.Dequeue(); } if (_nextTile == null) { _nextTile = CurrentTile; // TODO: Not sure when this might apply } // 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 != CurrentTile) { distToTravel = Mathf.Sqrt( Mathf.Pow(CurrentTile.X - _nextTile.X, 2) + Mathf.Pow(CurrentTile.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) { _nextTile = null; _path = null; Debug.LogFormat("{0}: MoveTowardsDestination_Action failed trying to move into a blocked tile.", Name); return(BehaviourTreeStatus.Failure); } 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. CurrentState = State.WaitingForAccess; return(BehaviourTreeStatus.Running); } // How much distance can be travel this Update? if (_nextTile == null) { _nextTile = CurrentTile; } var distThisFrame = 0f; try { distThisFrame = (_speed / _nextTile.MovementCost) * deltaTime; } catch (Exception e) { Debug.LogError(e.Message); } // How much is that in terms of percentage to our destination? float percThisFrame; if (Mathf.Approximately(distToTravel, 0f)) { percThisFrame = 1f; } else { percThisFrame = distThisFrame / distToTravel; } // Add that to overall percentage travelled. _movementPercentage += percThisFrame; if (_movementPercentage >= 1) { // We have reached our (current) destination CurrentTile = _nextTile; _movementPercentage = 0; } // Debug.LogFormat("MoveTowardsDestination_Action: Character at [{0:F2},{1:F2}] {2:P2}", this.X, this.Y, _movementPercentage); return(BehaviourTreeStatus.Running); }
private BehaviourTreeStatus FindRequiredStock_Action() { //Debug.Log("FindRequiredStock_Action"); // If the current job has all the materials it needs already, we can just skip this step. if (CurrentJob.HasAllMaterial()) { AbandonMove(); return(BehaviourTreeStatus.Success); } // The job needs some more materials, perhaps we're holding them already so don't need to go anywhere. if (Inventory != null && CurrentJob.NeedsMaterial(Inventory) > 0) { // We are carrying at least some of what the current job needs, so continue on our merry way. AbandonMove(); return(BehaviourTreeStatus.Success); } // The job needs some more materials, and we're not carrying it already, so we need to move to where there are some. // Perhaps the stock is right where we're stood? if (CurrentTile.Inventory != null && (CurrentJob.CanTakeFromStockpile || CurrentTile.Furniture == null || CurrentTile.Furniture.IsStockpile() == false) && (CurrentJob.NeedsMaterial(CurrentTile.Inventory) != 0)) { // The materials we need are right where we're stood! AbandonMove(); return(BehaviourTreeStatus.Success); } // The Job needs some of this: var unsatisfied = CurrentJob.GetFirstRequiredInventory(); // We might have a path to the item we need already var endTile = _path == null ? null : _path.EndTile(); if (_path != null && endTile != null && endTile.Inventory != null && endTile.Inventory.ObjectType == unsatisfied.ObjectType) { // We are already moving towards a tile with the items we want, just keep going. return(BehaviourTreeStatus.Success); } // Look for the first item that matches. _path = World.Instance.InventoryManager.GetClosestPathToInventoryOfType( objectType: unsatisfied.ObjectType, t: CurrentTile, desiredQty: unsatisfied.MaxStackSize - unsatisfied.StackSize, searchInStockpiles: CurrentJob.CanTakeFromStockpile); // If there are no items anywhere that satisfy the requirements, we have to give up on this job. if (_path == null || _path.Length() == 0) { //// Debug.LogFormat("No Tile found containing the desired type ({0}).", unsatisfied.ObjectType); AbandonJob(); return(BehaviourTreeStatus.Failure); } // We've identified where the missing items can be found, so head there. _destinationTile = _path.EndTile(); _nextTile = _path.Dequeue(); return(BehaviourTreeStatus.Success); }
// World calls this to update the character public void Update(float deltaTime) { // Check if I have a job // If I don't have a job.. if (myJob == null) { // Try to pull a job myJob = WorldController.Instance.World.jobQueue.Dequeue(); // Did that pull succeed? // If I still don't have a job if (myJob == null) { // Pullout, I don't have a job and can't get one. I don't want to do anything else return; } // If I did get a job... else { jobTile = myJob.buildTile; // set the job tile as my jobtile myJob.RegisterJobCanceledCallback(OnJobEnded); // we want to know if the job is completed or canceled, so we can discard it and do something else myJob.RegisterJobCompleteCallback(OnJobEnded); // It's a new job, reset everything as we'll have to work out pathfinding again destTile = null; nextTile = currTile; } } // At this stage I should have a job // Am I at the job site? if (destTile != null && currTile == destTile) { // If I'm at the job site, work on the job myJob.DoWork(deltaTime); } else { // Do I have my next step (nextTile) ? // If I don't have my next step or are on it if (nextTile == null || currTile == nextTile) { // Check if I have a path to follow // If I don't have a path... if (mainPath == null || mainPath.Length() == 0) { // Check all neighbours // Get a list of all the neighbouring tiles to the jobTile Tile[] neighbourList = jobTile.GetNeighbours(true); // Local lists to hold possilbe paths and tile destinations. // Won't need these after we have worked out the one we want potentialPathList = new List <Path_AStar>(); pathToDestTileMap = new Dictionary <Path_AStar, Tile>(); // Check each tile adjacent to the job tile, and if it's standable generate a path to it and add that path to the list of potental paths foreach (Tile t in neighbourList) { if (t.IsStandable() == true) { Path_AStar PTemp = new Path_AStar(t.world, currTile, t); // check that there is a legitimate path before adding it to the list of potential paths if (PTemp.Length() != 0) { potentialPathList.Add(PTemp); pathToDestTileMap.Add(PTemp, t); } } } // Check that we have at least one potential path // If we don't, bail out as pathing is impossible if (potentialPathList.Count <= 0) { //Debug.LogError("No Potential Paths found"); AbandonJob(); // Pull out of job and put job back on queue mainPath = null; potentialPathList.Clear(); pathToDestTileMap.Clear(); return; } // We should now have at least one potential path, so we will see which one is the shortest // Set first on list at the shortest, and check each path agaisnt it, a shorter path becoming the new shortest Path_AStar shortestPath = potentialPathList.First(); foreach (Path_AStar path in potentialPathList) { if (path.Length() < shortestPath.Length()) { shortestPath = path; } } // We now have a path to use that will take us to a legitmate building spot\ // And also the tile we are trying to get to mainPath = shortestPath; destTile = pathToDestTileMap[shortestPath]; } // At this stage we should have a path nextTile = mainPath.Dequeue(); } // At this stage we should have a nextTile // If I'm not at the jobsite, move towards it MoveToNextTile(deltaTime); } if (cbCharacterChanged != null) // Let other objects know that we have changed -- TODO: don't want to run every tick??? { cbCharacterChanged(this); } }
// 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; } }
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; } }
public void Update_Movement(float deltaTime) { //Debug.Log("Character UpdateMovement"); if (currTile == destTile) { pather = null; return; // We're already were we want to be. } if (nextTile == null || nextTile == currTile) { // Get the next tile from the pathfinder. if (pather == null || pather.Length() == 0) { // Generate a path to our destination pather = new Path_AStar(currTile.world, currTile, destTile); // This will calculate a path from curr to dest. if (pather.Length() == 0) { Debug.LogError("Path_AStar returned no path to destination!"); AbandonJob(); pather = null; return; } } // Grab the next waypoint from the pathing system! nextTile = pather.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 = 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 * deltaTime; // How much is that in terms of percentage to our destination? float percThisFrame = distThisFrame / distToTravel; // Add that to overall percentage travelled. movementPercentage += (percThisFrame * currTile.MoveCost); Debug.Log("movementPercentage:" + movementPercentage + ". percThisFrame:" + percThisFrame + ". currTile.Movecost" + currTile.MoveCost); 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? } //Debug.Log("Character End Movement"); }
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> /// 更新移动 /// </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); } }
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? } }
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 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. }
void Update_DoMovement(float deltaTime) { if (CurrTile == destTile) { pathAStar = null; return; } if (nextTile == null || nextTile == CurrTile) { //get the next tile from the pathfinder if (pathAStar == null || pathAStar.Length() == 0) { //gen a path to dest pathAStar = new Path_AStar(CurrTile.World, CurrTile, destTile); if (pathAStar.Length() == 0) { Debug.LogError($"Path A star returned no path to destination"); AbandonJob(); pathAStar = null; return; } nextTile = pathAStar.Dequeue(); //burning through the first tile, as that is the tile we are currently in } nextTile = pathAStar.Dequeue(); if (nextTile == CurrTile) { Debug.Log($"Update_DoMovement - nexttile is currtile??"); } } //get distance from a to b float distToTravel = Mathf.Sqrt( Mathf.Pow(CurrTile.X - nextTile.X, 2) + Mathf.Pow(CurrTile.Y - nextTile.Y, 2)); if (nextTile.IsEnterable() == Enterability.Never) { Debug.LogError($"FIXME: a character was trying to enter an unwalkable tile"); nextTile = null; pathAStar = null; return; } else if (nextTile.IsEnterable() == Enterability.Soon) { return; } //how much distance are we travelling this update cycle 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 out destination //todo: get the next destinatnion from the pathfinding system //if there are no more tiles then we have truly reached the destination CurrTile = nextTile; movementPercentage = 0; } }