Ejemplo n.º 1
0
 public CreatureAI(Creature creature,
     string name,
     EnemySensor sensor,
     PlanService planService)
     : base(name, creature.Physics)
 {
     Movement = new CreatureMovement();
     GatherManager = new GatherManager(this);
     Blackboard = new Blackboard();
     Creature = creature;
     CurrentPath = null;
     DrawPath = false;
     PlannerTimer = new Timer(0.1f, false);
     LocalControlTimeout = new Timer(5, false);
     WanderTimer = new Timer(1, false);
     Creature.Faction.Minions.Add(this);
     DrawAIPlan = false;
     WaitingOnResponse = false;
     PlanSubscriber = new PlanSubscriber(planService);
     ServiceTimeout = new Timer(2, false);
     Sensor = sensor;
     Sensor.OnEnemySensed += Sensor_OnEnemySensed;
     Sensor.Creature = this;
     CurrentTask = null;
     Tasks = new List<Task>();
     Thoughts = new List<Thought>();
     IdleTimer = new Timer(15.0f, true);
     SpeakTimer = new Timer(5.0f, true);
     XPEvents = new List<int>();
 }
Ejemplo n.º 2
0
 public CreatureAI(Creature creature,
                   string name,
                   EnemySensor sensor,
                   PlanService planService) :
     base(name, creature.Physics)
 {
     Movement            = new CreatureMovement();
     GatherManager       = new GatherManager(this);
     Blackboard          = new Blackboard();
     Creature            = creature;
     CurrentPath         = null;
     DrawPath            = false;
     PlannerTimer        = new Timer(0.1f, false);
     LocalControlTimeout = new Timer(5, false);
     WanderTimer         = new Timer(1, false);
     Creature.Faction.Minions.Add(this);
     DrawAIPlan            = false;
     WaitingOnResponse     = false;
     PlanSubscriber        = new PlanSubscriber(planService);
     ServiceTimeout        = new Timer(2, false);
     Sensor                = sensor;
     Sensor.OnEnemySensed += Sensor_OnEnemySensed;
     Sensor.Creature       = this;
     CurrentTask           = null;
     Tasks      = new List <Task>();
     Thoughts   = new List <Thought>();
     IdleTimer  = new Timer(15.0f, true);
     SpeakTimer = new Timer(5.0f, true);
     XPEvents   = new List <int>();
 }
Ejemplo n.º 3
0
        /// <summary>
        ///     Finds the path from the start to the goal region of move actions that can be performed by the creature.
        /// </summary>
        /// <param name="mover">The creature following the path.</param>
        /// <param name="start">The voxel the path starts with.</param>
        /// <param name="goal">Goal conditions that must be satisfied by the path.</param>
        /// <param name="chunks">The chunks the creature is moving through.</param>
        /// <param name="maxExpansions">Maximum number of voxels to explore before giving up.</param>
        /// <param name="weight">
        ///     The heuristic weight of the planner. If 1.0, the path returned is optimal.
        ///     Higher values result in suboptimal paths, but the search may be faster.
        /// </param>
        /// <param name="numPlans"></param>
        /// <param name="continueFunc"></param>
        /// <returns>The path of movements the creature must take to reach the goal. Returns null if no such path exists.</returns>
        public static List <MoveAction> FindPath(CreatureMovement mover, VoxelHandle start, GoalRegion goal,
                                                 ChunkManager chunks, int maxExpansions, float weight, int numPlans, Func <bool> continueFunc, out PlanResultCode resultCode)
        {
            var  p           = new List <MoveAction>();
            bool use_inverse = goal.IsReversible() && OpennessHeuristic(goal.GetVoxel()) < OpennessHeuristic(start);
            //bool use_inverse = false;
            var result = use_inverse ? InversePath(mover, start, goal, chunks, maxExpansions, ref p, weight, continueFunc)
                : Path(mover, start, goal, chunks, maxExpansions, ref p, weight, continueFunc);

            resultCode = result.Result;
            var length = (start.WorldPosition - goal.GetVoxel().WorldPosition).Length();

            if (result.Result == PlanResultCode.Success)
            {
                return(p);
            }

            if (result.Result == PlanResultCode.Invalid ||
                result.Result == PlanResultCode.NoSolution ||
                result.Result == PlanResultCode.Cancelled)
            {
                return(null);
            }

            if (!goal.IsReversible())
            {
                return(null);
            }

            result = use_inverse ? Path(mover, start, goal, chunks, maxExpansions, ref p, weight, continueFunc)
                : InversePath(mover, start, goal, chunks, maxExpansions, ref p, weight, continueFunc);
            resultCode = result.Result;
            return(result.Result == PlanResultCode.Success ? p : null);
        }
Ejemplo n.º 4
0
        /// <summary>
        ///     Finds the path from the start to the goal region of move actions that can be performed by the creature.
        /// </summary>
        /// <param name="mover">The creature following the path.</param>
        /// <param name="start">The voxel the path starts with.</param>
        /// <param name="goal">Goal conditions that must be satisfied by the path.</param>
        /// <param name="chunks">The chunks the creature is moving through.</param>
        /// <param name="maxExpansions">Maximum number of voxels to explore before giving up.</param>
        /// <param name="weight">
        ///     The heuristic weight of the planner. If 1.0, the path returned is optimal.
        ///     Higher values result in suboptimal paths, but the search may be faster.
        /// </param>
        /// <returns>The path of movements the creature must take to reach the goal. Returns null if no such path exists.</returns>
        public static List <Creature.MoveAction> FindPath(CreatureMovement mover, Voxel start, GoalRegion goal,
                                                          ChunkManager chunks, int maxExpansions, float weight)
        {
            var  p       = new List <Creature.MoveAction>();
            bool success = Path(mover, start, goal, chunks, maxExpansions, ref p, weight);

            if (success)
            {
                return(p);
            }
            return(null);
        }
Ejemplo n.º 5
0
        public CreatureAI(
            ComponentManager Manager,
            string name,
            EnemySensor sensor) :
            base(name, Manager)
        {
            Movement       = new CreatureMovement(this);
            PlanSubscriber = new PlanSubscriber(Manager.World.PlanService);

            Sensor = sensor;
            Sensor.OnEnemySensed += Sensor_OnEnemySensed;
            Sensor.Creature       = this;
        }
Ejemplo n.º 6
0
        /// <summary>
        ///     Given two voxels, and an action taken between the voxels, returns the cost of moving
        ///     between the two voxels given that action.
        /// </summary>
        /// <param name="a">The source voxel of the action.</param>
        /// <param name="b">The destination voxel of the action.</param>
        /// <param name="action">The action taken to get between voxels.</param>
        /// <param name="movement">The creature making the movement.</param>
        /// <returns>The cost of going from a to b using the given action.</returns>
        public static float GetDistance(Voxel a, Voxel b, Creature.MoveType action, CreatureMovement movement)
        {
            // If trying to move through a non-empty voxel, the cost is  just a big number.
            if (!b.IsEmpty)
            {
                return(100000);
            }
            // Otherwise, the cost is the distance between the voxels multiplied by the intrinsic cost
            // of an action.
            float score = (a.Position - b.Position).LengthSquared() * ActionCost(movement, action);

            return(score);
        }
Ejemplo n.º 7
0
        public static List<Creature.MoveAction> FindPath(CreatureMovement mover, Voxel start, GoalRegion goal, ChunkManager chunks, int maxExpansions)
        {
            List<Creature.MoveAction> p = new List<Creature.MoveAction>();
            bool success = Path(mover, start, goal, chunks, maxExpansions, ref p, false);

            if(success)
            {
                return p;
            }
            else
            {
                return null;
            }
        }
Ejemplo n.º 8
0
 public CreatureAI()
 {
     Movement = new CreatureMovement();
 }
Ejemplo n.º 9
0
 /// <summary>
 ///     Returns the intrinsic cost of an action.
 /// </summary>
 private static float ActionCost(CreatureMovement movement, MoveType action)
 {
     return(movement.Cost(action));
 }
Ejemplo n.º 10
0
        /// <summary>
        ///     Given two voxels, and an action taken between the voxels, returns the cost of moving
        ///     between the two voxels given that action.
        /// </summary>
        /// <param name="a">The source voxel of the action.</param>
        /// <param name="b">The destination voxel of the action.</param>
        /// <param name="action">The action taken to get between voxels.</param>
        /// <param name="movement">The creature making the movement.</param>
        /// <returns>The cost of going from a to b using the given action.</returns>
        public static float GetDistance(VoxelHandle a, VoxelHandle b, MoveType action, CreatureMovement movement)
        {
            // Otherwise, the cost is the distance between the voxels multiplied by the intrinsic cost
            // of an action.
            var   actionCost = ActionCost(movement, action);
            float score      = (a.WorldPosition - b.WorldPosition).LengthSquared() * actionCost + actionCost;

            return(score);
        }
Ejemplo n.º 11
0
 public CreatureAI()
 {
     Movement = new CreatureMovement(this.Creature);
 }
Ejemplo n.º 12
0
        // Find a path from the start to the goal by computing an inverse path from goal to the start. Should only be used
        // if the forward path fails.
        private static PlanResult InversePath(CreatureMovement mover, VoxelHandle startVoxel, GoalRegion goal, ChunkManager chunks,
                                              int maxExpansions, ref List <MoveAction> toReturn, float weight, Func <bool> continueFunc)
        {
            // Create a local clone of the octree, using only the objects belonging to the player.
            var         octree        = new OctTreeNode(mover.Creature.World.ChunkManager.Bounds.Min, mover.Creature.World.ChunkManager.Bounds.Max);
            List <Body> playerObjects = new List <Body>(mover.Creature.World.PlayerFaction.OwnedObjects);

            foreach (var obj in playerObjects)
            {
                octree.Add(obj, obj.GetBoundingBox());
            }

            MoveState start = new MoveState()
            {
                Voxel = startVoxel
            };

            var startTime = DwarfTime.Tick();

            if (mover.IsSessile)
            {
                return(new PlanResult()
                {
                    Result = PlanResultCode.Invalid,
                    Expansions = 0,
                    TimeSeconds = 0
                });
            }

            if (!start.IsValid)
            {
                return(new PlanResult()
                {
                    Result = PlanResultCode.Invalid,
                    Expansions = 0,
                    TimeSeconds = 0
                });
            }


            // Sometimes a goal may not even be achievable a.priori. If this is true, we know there can't be a path
            // which satisifies that goal.
            // It only makes sense to do inverse plans for goals that have an associated voxel.
            if (!goal.IsPossible() || !goal.GetVoxel().IsValid)
            {
                toReturn = null;
                return(new PlanResult()
                {
                    Result = PlanResultCode.Invalid,
                    Expansions = 0,
                    TimeSeconds = 0
                });
            }


            if (goal.IsInGoalRegion(start.Voxel))
            {
                toReturn = new List <MoveAction>();
                return(new PlanResult()
                {
                    Result = PlanResultCode.Success,
                    Expansions = 0,
                    TimeSeconds = 0
                });
            }

            // Voxels that have already been explored.
            var closedSet = new HashSet <MoveState>();

            // Voxels which should be explored.
            var openSet = new HashSet <MoveState>();

            // Dictionary of voxels to the optimal action that got the mover to that voxel.
            var cameFrom = new Dictionary <MoveState, MoveAction>();

            // Optimal score of a voxel based on the path it took to get there.
            var gScore = new Dictionary <MoveState, float>();

            // Expansion priority of voxels.
            var fScore = new PriorityQueue <MoveState>();

            var goalVoxels = new List <VoxelHandle>();

            goalVoxels.Add(goal.GetVoxel());
            // Starting conditions of the search.

            foreach (var goalVoxel in VoxelHelpers.EnumerateCube(goal.GetVoxel().Coordinate)
                     .Select(c => new VoxelHandle(start.Voxel.Chunk.Manager.ChunkData, c)))
            {
                if (!goalVoxel.IsValid)
                {
                    continue;
                }
                var goalState = new MoveState()
                {
                    Voxel = goalVoxel
                };
                if (goal.IsInGoalRegion(goalVoxel))
                {
                    goalVoxels.Add(goalVoxel);
                    openSet.Add(goalState);
                    gScore[goalState] = 0.0f;
                    fScore.Enqueue(goalState,
                                   gScore[goalState] + weight * (goalVoxel.WorldPosition - start.Voxel.WorldPosition).LengthSquared());
                }
            }

            // Keep count of the number of expansions we've taken to get to the goal.
            int numExpansions = 0;

            // Loop until we've either checked every possible voxel, or we've exceeded the maximum number of
            // expansions.
            while (openSet.Count > 0 && numExpansions < maxExpansions)
            {
                if (numExpansions % 10 == 0 && !continueFunc())
                {
                    return new PlanResult
                           {
                               Result      = PlanResultCode.Cancelled,
                               Expansions  = numExpansions,
                               TimeSeconds = DwarfTime.Tock(startTime)
                           }
                }
                ;

                // Check the next voxel to explore.
                var current = GetStateWithMinimumFScore(fScore);
                if (!current.IsValid)
                {
                    continue;
                }
                //Drawer3D.DrawBox(current.GetBoundingBox(), Color.Blue, 0.1f);
                numExpansions++;

                // If we've reached the goal already, reconstruct the path from the start to the
                // goal.
                if (current.Equals(start))
                {
                    toReturn = ReconstructInversePath(goal, cameFrom, cameFrom[start]);
                    return(new PlanResult()
                    {
                        Result = PlanResultCode.Success,
                        Expansions = numExpansions,
                        TimeSeconds = DwarfTime.Tock(startTime)
                    });
                }

                // We've already considered the voxel, so add it to the closed set.
                openSet.Remove(current);
                closedSet.Add(current);

                IEnumerable <MoveAction> neighbors = null;

                // Get the voxels that can be moved to from the current voxel.
                neighbors = mover.GetInverseMoveActions(current, octree);

                // Otherwise, consider all of the neighbors of the current voxel that can be moved to,
                // and determine how to add them to the list of expansions.
                foreach (MoveAction n in neighbors)
                {
                    //Drawer3D.DrawBox(n.SourceVoxel.GetBoundingBox(), Color.Red, 0.1f);
                    // If we've already explored that voxel, don't explore it again.
                    if (closedSet.Contains(n.SourceState))
                    {
                        continue;
                    }

                    // Otherwise, consider the case of moving to that neighbor.
                    float tenativeGScore = gScore[current] + GetDistance(current.Voxel, n.SourceState.Voxel, n.MoveType, mover);

                    // IF the neighbor can already be reached more efficiently, ignore it.
                    if (openSet.Contains(n.SourceState) && gScore.ContainsKey(n.SourceState) && !(tenativeGScore < gScore[n.SourceState]))
                    {
                        continue;
                    }

                    // Otherwise, add it to the list of voxels for consideration.
                    openSet.Add(n.SourceState);

                    // Add an edge to the voxel from the current voxel.
                    var cameAction = n;
                    cameFrom[n.SourceState] = cameAction;

                    // Update the expansion scores for the next voxel.
                    gScore[n.SourceState] = tenativeGScore;
                    fScore.Enqueue(n.SourceState, gScore[n.SourceState] + weight * ((n.SourceState.Voxel.WorldPosition - start.Voxel.WorldPosition).LengthSquared() + (!n.SourceState.VehicleState.IsRidingVehicle ? 100.0f : 0.0f)));
                }

                // If we've expanded too many voxels, just give up.
                if (numExpansions >= maxExpansions)
                {
                    return(new PlanResult()
                    {
                        Result = PlanResultCode.MaxExpansionsReached,
                        Expansions = numExpansions,
                        TimeSeconds = DwarfTime.Tock(startTime)
                    });
                }
            }

            // Somehow we've reached this code without having found a path. Return false.
            toReturn = null;
            return(new PlanResult()
            {
                Result = PlanResultCode.NoSolution,
                Expansions = numExpansions,
                TimeSeconds = DwarfTime.Tock(startTime)
            });
        }
Ejemplo n.º 13
0
        /// <summary>
        ///     Creates a path from the start voxel to some goal region, returning a list of movements that can
        ///     take a mover from the start voxel to the goal region.
        /// </summary>
        /// <param name="mover">The agent that we want to find a path for.</param>
        /// <param name="startVoxel"></param>
        /// <param name="goal">Goal conditions that the agent is trying to satisfy.</param>
        /// <param name="chunks">The voxels that the agent is moving through</param>
        /// <param name="maxExpansions">Maximum number of voxels to consider before giving up.</param>
        /// <param name="toReturn">The path of movements that the mover should take to reach the goal.</param>
        /// <param name="weight">
        ///     A heuristic weight to apply to the planner. If 1.0, the path is garunteed to be optimal. Higher values
        ///     usually result in faster plans that are suboptimal.
        /// </param>
        /// <param name="continueFunc"></param>
        /// <returns>True if a path could be found, or false otherwise.</returns>
        private static PlanResult Path(CreatureMovement mover, VoxelHandle startVoxel, GoalRegion goal, ChunkManager chunks,
                                       int maxExpansions, ref List <MoveAction> toReturn, float weight, Func <bool> continueFunc)
        {
            // Create a local clone of the octree, using only the objects belonging to the player.
            var         octree        = new OctTreeNode(mover.Creature.World.ChunkManager.Bounds.Min, mover.Creature.World.ChunkManager.Bounds.Max);
            List <Body> playerObjects = new List <Body>(mover.Creature.World.PlayerFaction.OwnedObjects);

            foreach (var obj in playerObjects)
            {
                octree.Add(obj, obj.GetBoundingBox());
            }

            var start = new MoveState()
            {
                Voxel = startVoxel
            };

            var startTime = DwarfTime.Tick();

            if (mover.IsSessile)
            {
                return(new PlanResult()
                {
                    Expansions = 0,
                    Result = PlanResultCode.Invalid,
                    TimeSeconds = DwarfTime.Tock(startTime)
                });
            }

            // Sometimes a goal may not even be achievable a.priori. If this is true, we know there can't be a path
            // which satisifies that goal.
            if (!goal.IsPossible())
            {
                toReturn = null;
                return(new PlanResult()
                {
                    Expansions = 0,
                    Result = PlanResultCode.Invalid,
                    TimeSeconds = DwarfTime.Tock(startTime)
                });
            }

            // Voxels that have already been explored.
            var closedSet = new HashSet <MoveState>();

            // Voxels which should be explored.
            var openSet = new HashSet <MoveState>
            {
                start
            };

            // Dictionary of voxels to the optimal action that got the mover to that voxel.
            var cameFrom = new Dictionary <MoveState, MoveAction>();

            // Optimal score of a voxel based on the path it took to get there.
            var gScore = new Dictionary <MoveState, float>();

            // Expansion priority of voxels.
            var fScore = new PriorityQueue <MoveState>();

            // Starting conditions of the search.
            gScore[start] = 0.0f;
            fScore.Enqueue(start, gScore[start] + weight * goal.Heuristic(start.Voxel));

            // Keep count of the number of expansions we've taken to get to the goal.
            int numExpansions = 0;

            // Check the voxels adjacent to the current voxel as a quick test of adjacency to the goal.
            //var manhattanNeighbors = new List<VoxelHandle>(6);
            //for (int i = 0; i < 6; i++)
            //{
            //    manhattanNeighbors.Add(new VoxelHandle());
            //}

            // Loop until we've either checked every possible voxel, or we've exceeded the maximum number of
            // expansions.
            while (openSet.Count > 0 && numExpansions < maxExpansions)
            {
                if (numExpansions % 10 == 0 && !continueFunc())
                {
                    return new PlanResult
                           {
                               Result      = PlanResultCode.Cancelled,
                               Expansions  = numExpansions,
                               TimeSeconds = DwarfTime.Tock(startTime)
                           }
                }
                ;


                // Check the next voxel to explore.
                var current = GetStateWithMinimumFScore(fScore);
                if (!current.IsValid)
                {
                    // If there wasn't a voxel to explore, just try to expand from
                    // the start again.
                    numExpansions++;

                    continue;
                }

                numExpansions++;

                // If we've reached the goal already, reconstruct the path from the start to the
                // goal.


                if (goal.IsInGoalRegion(current.Voxel) && cameFrom.ContainsKey(current))
                {
                    toReturn = ReconstructPath(cameFrom, cameFrom[current], start);
                    return(new PlanResult()
                    {
                        Result = PlanResultCode.Success,
                        Expansions = numExpansions,
                        TimeSeconds = DwarfTime.Tock(startTime)
                    });
                }


                //Drawer3D.DrawLine(start.Voxel.GetBoundingBox().Center(), goal.GetVoxel().GetBoundingBox().Center(), Color.Red, 0.1f);
                //Drawer3D.DrawBox(current.Voxel.GetBoundingBox(), Color.Red, 0.1f, true);
                // We've already considered the voxel, so add it to the closed set.
                openSet.Remove(current);
                closedSet.Add(current);

                IEnumerable <MoveAction> neighbors = null;

                // Get the voxels that can be moved to from the current voxel.
                neighbors = mover.GetMoveActions(current, octree).ToList();
                //currentChunk.GetNeighborsManhattan(current, manhattanNeighbors);


                var foundGoalAdjacent = neighbors.FirstOrDefault(n => !n.DestinationState.VehicleState.IsRidingVehicle && goal.IsInGoalRegion(n.DestinationState.Voxel));

                // A quick test to see if we're already adjacent to the goal. If we are, assume
                // that we can just walk to it.
                if (foundGoalAdjacent.DestinationState.IsValid && foundGoalAdjacent.SourceState.IsValid)
                {
                    if (cameFrom.ContainsKey(current))
                    {
                        List <MoveAction> subPath = ReconstructPath(cameFrom, foundGoalAdjacent, start);
                        toReturn = subPath;
                        return(new PlanResult()
                        {
                            Result = PlanResultCode.Success,
                            Expansions = numExpansions,
                            TimeSeconds = DwarfTime.Tock(startTime)
                        });
                    }
                }

                // Otherwise, consider all of the neighbors of the current voxel that can be moved to,
                // and determine how to add them to the list of expansions.
                foreach (MoveAction n in neighbors)
                {
                    // If we've already explored that voxel, don't explore it again.
                    if (closedSet.Contains(n.DestinationState))
                    {
                        continue;
                    }

                    // Otherwise, consider the case of moving to that neighbor.
                    float tenativeGScore = gScore[current] + GetDistance(current.Voxel, n.DestinationState.Voxel, n.MoveType, mover);

                    // IF the neighbor can already be reached more efficiently, ignore it.
                    if (openSet.Contains(n.DestinationState) && !(tenativeGScore < gScore[n.DestinationState]))
                    {
                        continue;
                    }

                    // Otherwise, add it to the list of voxels for consideration.
                    openSet.Add(n.DestinationState);

                    // Add an edge to the voxel from the current voxel.
                    var cameAction = n;
                    cameFrom[n.DestinationState] = cameAction;

                    // Update the expansion scores for the next voxel.
                    gScore[n.DestinationState] = tenativeGScore;
                    fScore.Enqueue(n.DestinationState, gScore[n.DestinationState] + weight * (goal.Heuristic(n.DestinationState.Voxel) + (!n.DestinationState.VehicleState.IsRidingVehicle ? 100.0f : 0.0f)));
                }

                // If we've expanded too many voxels, just give up.
                if (numExpansions >= maxExpansions)
                {
                    return(new PlanResult()
                    {
                        Expansions = numExpansions,
                        Result = PlanResultCode.MaxExpansionsReached,
                        TimeSeconds = DwarfTime.Tock(startTime)
                    });
                }
            }

            // Somehow we've reached this code without having found a path. Return false.
            toReturn = null;
            return(new PlanResult()
            {
                Expansions = numExpansions,
                Result = PlanResultCode.NoSolution,
                TimeSeconds = DwarfTime.Tock(startTime)
            });
        }
Ejemplo n.º 14
0
        /// <summary>
        ///     Creates a path from the start voxel to some goal region, returning a list of movements that can
        ///     take a mover from the start voxel to the goal region.
        /// </summary>
        /// <param name="mover">The agent that we want to find a path for.</param>
        /// <param name="start">The voxel that the agent starts in.</param>
        /// <param name="goal">Goal conditions that the agent is trying to satisfy.</param>
        /// <param name="chunks">The voxels that the agent is moving through</param>
        /// <param name="maxExpansions">Maximum number of voxels to consider before giving up.</param>
        /// <param name="toReturn">The path of movements that the mover should take to reach the goal.</param>
        /// <param name="weight">
        ///     A heuristic weight to apply to the planner. If 1.0, the path is garunteed to be optimal. Higher values
        ///     usually result in faster plans that are suboptimal.
        /// </param>
        /// <returns>True if a path could be found, or false otherwise.</returns>
        private static bool Path(CreatureMovement mover, Voxel start, GoalRegion goal, ChunkManager chunks,
                                 int maxExpansions, ref List <Creature.MoveAction> toReturn, float weight)
        {
            // Sometimes a goal may not even be achievable a.priori. If this is true, we know there can't be a path
            // which satisifies that goal.
            if (!goal.IsPossible())
            {
                toReturn = null;
                return(false);
            }

            // Voxels that have already been explored.
            var closedSet = new HashSet <Voxel>();

            // Voxels which should be explored.
            var openSet = new HashSet <Voxel>
            {
                start
            };

            // Dictionary of voxels to the optimal action that got the mover to that voxel.
            var cameFrom = new Dictionary <Voxel, Creature.MoveAction>();

            // Optimal score of a voxel based on the path it took to get there.
            var gScore = new Dictionary <Voxel, float>();

            // Expansion priority of voxels.
            var fScore = new PriorityQueue <Voxel>();

            // Starting conditions of the search.
            gScore[start] = 0.0f;
            fScore.Enqueue(start, gScore[start] + weight * goal.Heuristic(start));

            // Keep count of the number of expansions we've taken to get to the goal.
            int numExpansions = 0;

            // Check the voxels adjacent to the current voxel as a quick test of adjacency to the goal.
            var manhattanNeighbors = new List <Voxel>(6);

            for (int i = 0; i < 6; i++)
            {
                manhattanNeighbors.Add(new Voxel());
            }

            // Loop until we've either checked every possible voxel, or we've exceeded the maximum number of
            // expansions.
            while (openSet.Count > 0 && numExpansions < maxExpansions)
            {
                // Check the next voxel to explore.
                Voxel current = GetVoxelWithMinimumFScore(fScore);
                if (current == null)
                {
                    // If there wasn't a voxel to explore, just try to expand from
                    // the start again.
                    current = start;
                    numExpansions++;
                }
                numExpansions++;

                // If we've reached the goal already, reconstruct the path from the start to the
                // goal.
                if (goal.IsInGoalRegion(current))
                {
                    // Assume that the last action in the path involves walking to the goal.
                    var first = new Creature.MoveAction
                    {
                        Voxel    = current,
                        MoveType = Creature.MoveType.Walk
                    };
                    toReturn = ReconstructPath(cameFrom, first);
                    return(true);
                }

                // We've already considered the voxel, so add it to the closed set.
                openSet.Remove(current);
                closedSet.Add(current);

                VoxelChunk currentChunk = chunks.ChunkData.ChunkMap[current.ChunkID];

                List <Creature.MoveAction> neighbors = null;

                // Get the voxels that can be moved to from the current voxel.
                neighbors = mover.GetMoveActions(current);
                currentChunk.GetNeighborsManhattan(current, manhattanNeighbors);

                // A quick test to see if we're already adjacent to the goal. If we are, assume
                // that we can just walk to it.
                if (manhattanNeighbors.Contains(goal.GetVoxel()))
                {
                    var first = new Creature.MoveAction
                    {
                        Voxel    = current,
                        MoveType = Creature.MoveType.Walk
                    };
                    var last = new Creature.MoveAction
                    {
                        Voxel    = goal.GetVoxel(),
                        MoveType = Creature.MoveType.Walk
                    };
                    List <Creature.MoveAction> subPath = ReconstructPath(cameFrom, first);
                    subPath.Add(last);
                    toReturn = subPath;
                    return(true);
                }

                // Otherwise, consider all of the neighbors of the current voxel that can be moved to,
                // and determine how to add them to the list of expansions.
                foreach (Creature.MoveAction n in neighbors)
                {
                    // If we've already explored that voxel, don't explore it again.
                    if (closedSet.Contains(n.Voxel))
                    {
                        continue;
                    }

                    // Otherwise, consider the case of moving to that neighbor.
                    float tenativeGScore = gScore[current] + GetDistance(current, n.Voxel, n.MoveType, mover);

                    // IF the neighbor can already be reached more efficiently, ignore it.
                    if (openSet.Contains(n.Voxel) && !(tenativeGScore < gScore[n.Voxel]))
                    {
                        continue;
                    }

                    // Otherwise, add it to the list of voxels for consideration.
                    openSet.Add(n.Voxel);

                    // Add an edge to the voxel from the current voxel.
                    Creature.MoveAction cameAction = n;
                    cameAction.Voxel  = current;
                    cameFrom[n.Voxel] = cameAction;

                    // Update the expansion scores for the next voxel.
                    gScore[n.Voxel] = tenativeGScore;
                    fScore.Enqueue(n.Voxel, gScore[n.Voxel] + weight * goal.Heuristic(n.Voxel));
                }

                // If we've expanded too many voxels, just give up.
                if (numExpansions >= maxExpansions)
                {
                    return(false);
                }
            }

            // Somehow we've reached this code without having found a path. Return false.
            toReturn = null;
            return(false);
        }
Ejemplo n.º 15
0
 public CreatureAI()
 {
     Movement = new CreatureMovement();
 }
Ejemplo n.º 16
0
        private static bool Path(CreatureMovement mover, Voxel start, GoalRegion goal, ChunkManager chunks, int maxExpansions, ref List<Creature.MoveAction> toReturn, bool reverse)
        {
            VoxelChunk startChunk = chunks.ChunkData.ChunkMap[start.ChunkID];
            VoxelChunk endChunk = chunks.ChunkData.ChunkMap[goal.GetVoxel().ChunkID];

            if(startChunk.IsCompletelySurrounded(start) || endChunk.IsCompletelySurrounded(goal.GetVoxel()))
            {
                toReturn = null;
                return false;
            }

            HashSet<Voxel> closedSet = new HashSet<Voxel>();

            HashSet<Voxel> openSet = new HashSet<Voxel>
            {
                start
            };

            Dictionary<Voxel, Creature.MoveAction> cameFrom = new Dictionary<Voxel, Creature.MoveAction>();
            Dictionary<Voxel, float> gScore = new Dictionary<Voxel, float>();
            PriorityQueue<Voxel> fScore = new PriorityQueue<Voxel>();
            gScore[start] = 0.0f;
            fScore.Enqueue(start, gScore[start] + Heuristic(start, goal.GetVoxel()));

            int numExpansions = 0;

            List<Voxel> manhattanNeighbors = new List<Voxel>(6);
            for (int i = 0; i < 6; i++)
            {
                manhattanNeighbors.Add(new Voxel());
            }
            while(openSet.Count > 0 && numExpansions < maxExpansions)
            {
                Voxel current = GetVoxelWithMinimumFScore(fScore, openSet);

                if (current == null)
                {
                    current = start;
                    numExpansions++;
                }
                numExpansions++;
                if (goal.IsInGoalRegion(current))
                {
                    Creature.MoveAction first = new Creature.MoveAction()
                    {
                        Voxel = current,
                        MoveType = Creature.MoveType.Walk
                    };
                    toReturn = ReconstructPath(cameFrom, first);
                    return true;
                }

                openSet.Remove(current);
                closedSet.Add(current);

                VoxelChunk currentChunk = chunks.ChunkData.ChunkMap[current.ChunkID];

                List<Creature.MoveAction> neighbors = null;

                neighbors = mover.GetMoveActions(current);
                currentChunk.GetNeighborsManhattan(current, manhattanNeighbors);

                if(manhattanNeighbors.Contains(goal.GetVoxel()))
                {
                    Creature.MoveAction first = new Creature.MoveAction()
                    {
                        Voxel = current,
                        MoveType = Creature.MoveType.Walk
                    };
                    Creature.MoveAction last = new Creature.MoveAction()
                    {
                        Voxel = goal.GetVoxel(),
                        MoveType = Creature.MoveType.Walk
                    };
                    List<Creature.MoveAction> subPath = ReconstructPath(cameFrom, first);
                    subPath.Add(last);
                    toReturn = subPath;
                    return true;
                }

                foreach(Creature.MoveAction n in neighbors)
                {
                    if(closedSet.Contains(n.Voxel))
                    {
                        continue;
                    }

                    float tenativeGScore = gScore[current] + GetDistance(current, n.Voxel, n.MoveType, chunks);

                    if(openSet.Contains(n.Voxel) && !(tenativeGScore < gScore[n.Voxel]))
                    {
                        continue;
                    }

                    openSet.Add(n.Voxel);
                    Creature.MoveAction cameAction = n;
                    cameAction.Voxel = current;

                    cameFrom[n.Voxel] = cameAction;
                    gScore[n.Voxel] = tenativeGScore;
                    fScore.Enqueue(n.Voxel, gScore[n.Voxel] + Heuristic(n.Voxel, goal.GetVoxel()));
                }

                if(numExpansions >= maxExpansions)
                {
                    return false;
                }
            }
            toReturn = null;
            return false;
        }
Ejemplo n.º 17
0
        private static bool Path(CreatureMovement mover, Voxel start, GoalRegion goal, ChunkManager chunks, int maxExpansions, ref List <Creature.MoveAction> toReturn, bool reverse)
        {
            VoxelChunk startChunk = chunks.ChunkData.ChunkMap[start.ChunkID];
            VoxelChunk endChunk   = chunks.ChunkData.ChunkMap[goal.GetVoxel().ChunkID];

            if (startChunk.IsCompletelySurrounded(start) || endChunk.IsCompletelySurrounded(goal.GetVoxel()))
            {
                toReturn = null;
                return(false);
            }


            HashSet <Voxel> closedSet = new HashSet <Voxel>();

            HashSet <Voxel> openSet = new HashSet <Voxel>
            {
                start
            };

            Dictionary <Voxel, Creature.MoveAction> cameFrom = new Dictionary <Voxel, Creature.MoveAction>();
            Dictionary <Voxel, float> gScore = new Dictionary <Voxel, float>();
            PriorityQueue <Voxel>     fScore = new PriorityQueue <Voxel>();

            gScore[start] = 0.0f;
            fScore.Enqueue(start, gScore[start] + Heuristic(start, goal.GetVoxel()));

            int numExpansions = 0;

            List <Voxel> manhattanNeighbors = new List <Voxel>(6);

            for (int i = 0; i < 6; i++)
            {
                manhattanNeighbors.Add(new Voxel());
            }
            while (openSet.Count > 0 && numExpansions < maxExpansions)
            {
                Voxel current = GetVoxelWithMinimumFScore(fScore, openSet);

                if (current == null)
                {
                    current = start;
                    numExpansions++;
                }
                numExpansions++;
                if (goal.IsInGoalRegion(current))
                {
                    Creature.MoveAction first = new Creature.MoveAction()
                    {
                        Voxel    = current,
                        MoveType = Creature.MoveType.Walk
                    };
                    toReturn = ReconstructPath(cameFrom, first);
                    return(true);
                }

                openSet.Remove(current);
                closedSet.Add(current);

                VoxelChunk currentChunk = chunks.ChunkData.ChunkMap[current.ChunkID];

                List <Creature.MoveAction> neighbors = null;

                neighbors = mover.GetMoveActions(current);
                currentChunk.GetNeighborsManhattan(current, manhattanNeighbors);

                if (manhattanNeighbors.Contains(goal.GetVoxel()))
                {
                    Creature.MoveAction first = new Creature.MoveAction()
                    {
                        Voxel    = current,
                        MoveType = Creature.MoveType.Walk
                    };
                    Creature.MoveAction last = new Creature.MoveAction()
                    {
                        Voxel    = goal.GetVoxel(),
                        MoveType = Creature.MoveType.Walk
                    };
                    List <Creature.MoveAction> subPath = ReconstructPath(cameFrom, first);
                    subPath.Add(last);
                    toReturn = subPath;
                    return(true);
                }

                foreach (Creature.MoveAction n in neighbors)
                {
                    if (closedSet.Contains(n.Voxel))
                    {
                        continue;
                    }

                    float tenativeGScore = gScore[current] + GetDistance(current, n.Voxel, n.MoveType, chunks);

                    if (openSet.Contains(n.Voxel) && !(tenativeGScore < gScore[n.Voxel]))
                    {
                        continue;
                    }

                    openSet.Add(n.Voxel);
                    Creature.MoveAction cameAction = n;
                    cameAction.Voxel = current;

                    cameFrom[n.Voxel] = cameAction;
                    gScore[n.Voxel]   = tenativeGScore;
                    fScore.Enqueue(n.Voxel, gScore[n.Voxel] + Heuristic(n.Voxel, goal.GetVoxel()));
                }

                if (numExpansions >= maxExpansions)
                {
                    return(false);
                }
            }
            toReturn = null;
            return(false);
        }