Exemple #1
0
        public static BTResult MoveTo(Animal agent, Vector3 target, bool wandering)
        {
            var routeProps = new RouteProperties {
                MaxTargetLocationHeightDelta = agent.Species.ClimbHeight
            };
            var route = AIUtil.GetRouteFacingTarget(agent.FacingDir, agent.Position, target, agent.Species.GetTraversalData(wandering), agent.Species.HeadDistance * 2, routeProps: routeProps, allowBasic: false);

            if (!route.IsValid)
            {
                return(BTResult.Failure("Can't build route"));
            }

            // Prevent setting route with 0 time length
            var timeToFinishRoute = agent.SetRoute(route, wandering ? AnimalState.Wander : AnimalState.Flee);

            if (timeToFinishRoute < float.Epsilon)
            {
                return(BTResult.Failure("route not set"));
            }
            return(BTResult.RunningChanged("Moving to target"));
        }
Exemple #2
0
        public static BTResult LandMovement(Animal agent,
                                            Vector2 direction,
                                            bool wandering,
                                            AnimalState state,
                                            float minDistance = 1f,
                                            float maxDistance = 20f,
                                            float minDirectionOffsetDegrees = 0,
                                            float maxDirectionOffsetDegrees = 360,
                                            int tryCount             = 10,
                                            bool isUnstuckable       = true,
                                            bool skipRouteProperties = false)
        {
            var routeProps = skipRouteProperties ? null : new RouteProperties
            {
                MaxTargetLocationHeightDelta = agent.Species.ClimbHeight,
                MinDirectionOffsetDegrees    = minDirectionOffsetDegrees,
                MaxDirectionOffsetDegrees    = maxDirectionOffsetDegrees
            };

            var groundPos = agent.GroundPosition;
            var search    = RouteProbingUtils.FindRandomGroundRoute(agent.FacingDir, groundPos, minDistance, maxDistance, agent.FacingDir.XZ.Normalized, direction, routeProps);

            if (search != null)
            {
                var smoothed = search.LineOfSightSmoothGroundPosition(groundPos);
                var route    = new Route(agent.Species.GetTraversalData(wandering), agent.FacingDir, smoothed);
                // Apply route if its need more than 0 time to finish
                var timeToFinishRoute = agent.SetRoute(route, state);
                if (timeToFinishRoute > float.Epsilon)
                {
                    agent.RemoveMemory(Animal.TriesToUnStuckMemory);
                    return(BTResult.RunningChanged($"Picked new point."));
                }
            }

            agent.RemoveMemory(Animal.ShouldFleeTillMemory);
            return(isUnstuckable ? LandAnimalUnStuckOrDie(agent) : BTResult.Failure("Stuck!"));
        }
Exemple #3
0
        public static IEnumerator <BTResult> FindAndEatSomething(Animal agent, Behavior <Animal> noNearbyFoodBehavior, Func <IEnumerable <Vector3> > getFoodSources, float hungerRestoredPerEat)
        {
            var lastFoodSearchPos = Vector3.Zero;
            var foodSources       = new Queue <Vector3>();

            //While we're still hungry and don't have prey
            while (agent.Hunger > Brain.HungerToStopEating)
            {
                foodSources.Clear();
                while (foodSources.Count == 0)
                {
                    //Look for food sources, if we havent checked already and found it empty or just killed an enemy animal
                    if (Vector3.WrappedDistance(lastFoodSearchPos, agent.Position) > 10 || (agent.TryGetMemory(Animal.IsAnimalKilledMemory, out bool isKilled) && isKilled))
                    {
                        foodSources.AddRange(getFoodSources());
                        lastFoodSearchPos = agent.Position;
                        agent.RemoveMemory(Animal.IsAnimalKilledMemory);
                    }
                    else //None found, get outta here
                    {
                        yield return(new BTResult(noNearbyFoodBehavior.Do(agent), "No food in 10m radius of last query. Moving till we're > 10m from last query."));
                    }
                }

                //Food sources available, find paths to them.
                var routeProps = new RouteProperties()
                {
                    MaxTargetLocationHeightDelta = agent.Species.ClimbHeight
                };
                while (foodSources.Count > 0 && Vector3.WrappedDistance(lastFoodSearchPos, agent.Position) < 10)
                {
                    // Low-effort search for the first option or any other option visited while trying to hit the first with randomizing it in that area
                    var route            = AIUtil.GetRouteToAny(agent.FacingDir, agent.Position, foodSources, agent.Species.GetTraversalData(true), out var targetPosition, 100, 20, agent.Species.HeadDistance, routeProps);
                    var target           = targetPosition.Round;
                    var distanceToTarget = Vector3.WrappedDistanceSq(agent.Position, target);

                    // Move to target if it's far away
                    if (distanceToTarget > 2f)
                    {
                        if (!route.HasValue)
                        {
                            break;
                        }

                        agent.SetRoute(route.Value, AnimalState.LookingForFood, route.Value.EndPosition.Round);
                        yield return(BTResult.RunningChanged("walking to food"));

                        // Stop walking to food if the distance to it has changed or it disappeared
                        var agentTarget = agent.Target;
                        if (agentTarget == null || Vector3.WrappedDistanceSq(agentTarget.Value, target) > 2f)
                        {
                            break;
                        }
                    }

                    // Start eating food if it's close to us
                    if (Vector3.WrappedDistanceSq(target, agent.Position) <= 2f)
                    {
                        agent.ClearRoute();
                        agent.LookAt(target);
                        agent.ChangeState(AnimalState.Eating, 5, false);
                        agent.Hunger -= hungerRestoredPerEat;
                        yield return(BTResult.RunningChanged("chowing down"));

                        agent.LookAt(null);
                        lastFoodSearchPos = Vector3.Zero;
                        //Don't actually destroy the plant, because that's handled in the world layer simulation.
                        //var plant = EcoSim.PlantSim.GetPlant(targetPlantPosition.WorldPosition3i + Vector3i.Up);
                        //if (plant != null) EcoSim.PlantSim.DestroyPlant(plant, DeathType.EatenByAnimal);
                    }
                }
            }
        }