예제 #1
0
        public override IEnumerable <Status> Run()
        {
            PerchTime.Reset();
            WanderTime.Reset();
            TurnTime.Reset();
            while (true)
            {
                if (State == FlyState.Perching)
                {
                    PerchTime.Reset();
                    while (!PerchTime.HasTriggered)
                    {
                        Agent.Creature.Physics.Velocity     = Vector3.Zero;
                        Agent.Creature.CurrentCharacterMode = Creature.CharacterMode.Idle;
                        PerchTime.Update(DwarfTime.LastTime);
                        yield return(Act.Status.Running);
                    }
                    // When we're done flying, go back to walking and just fall.
                    Agent.Creature.CurrentCharacterMode = Creature.CharacterMode.Walking;
                    Agent.Creature.Physics.Gravity      = OriginalGravity;
                    yield return(Act.Status.Success);
                }

                Agent.Creature.Physics.Gravity = Vector3.Zero;
                // Store the last position of the bird to sample from
                Vector3 oldPosition = Agent.Position;

                // Get the height of the terrain beneath the bird.
                float surfaceHeight = Agent.Chunks.ChunkData.GetFilledVoxelGridHeightAt(oldPosition.X, oldPosition.Y,
                                                                                        oldPosition.Z);

                // Immediately start flying.
                Agent.Creature.CurrentCharacterMode = Creature.CharacterMode.Flying;

                // Use this to determine when to start turning.
                float currentDistance = 999;

                {
                    // Pick a target within a box floating some distance above the surface.
                    float randomX = MathFunctions.Rand() * Radius - Radius / 2.0f;
                    float randomZ = MathFunctions.Rand() * Radius - Radius / 2.0f;
                    float randomY = (float)PlayState.Random.NextDouble() * YRadius + Altitude + surfaceHeight;

                    // Set the target to that random location.
                    LocalTarget = new Vector3(randomX + oldPosition.X, randomY, randomZ + oldPosition.Z);
                }


                // Keep flying until a timer has trigerred.
                while ((!WanderTime.HasTriggered && State == FlyState.Wandering) || (State == FlyState.SearchingForPerch))
                {
                    // If we hit the ground, switch to walking, otherwise switch to flying.
                    Agent.Creature.CurrentCharacterMode = Creature.CharacterMode.Flying;

                    WanderTime.Update(DwarfTime.LastTime);

                    // If we're near a target, or a timeout occured, pick a new ranodm target.
                    if (TurnTime.Update(DwarfTime.LastTime) || TurnTime.HasTriggered || currentDistance < TurnThreshold)
                    {
                        // Pick a target within a box floating some distance above the surface.
                        float randomX = MathFunctions.Rand() * Radius - Radius / 2.0f;
                        float randomZ = MathFunctions.Rand() * Radius - Radius / 2.0f;
                        float randomY = (float)PlayState.Random.NextDouble() * YRadius + Altitude + surfaceHeight;

                        // Set the target to that random location.
                        LocalTarget = new Vector3(randomX + oldPosition.X, randomY, randomZ + oldPosition.Z);
                    }

                    // Set the current distance to the target so we know when to go to a new target.
                    currentDistance = (Agent.Position - LocalTarget).Length();

                    // Output from the force controller.
                    Vector3 output =
                        Creature.Controller.GetOutput((float)DwarfTime.LastTime.ElapsedGameTime.TotalSeconds,
                                                      LocalTarget, Creature.Physics.GlobalTransform.Translation);

                    // We apply a linear combination of the force controller and the
                    // feed forward force to the bird to make it lazily turn around and fly.
                    Creature.Physics.ApplyForce(output * Damping * GravityCompensation,
                                                (float)DwarfTime.LastTime.ElapsedGameTime.TotalSeconds);


                    if (State == FlyState.Wandering && WanderTime.HasTriggered)
                    {
                        State = FlyState.SearchingForPerch;
                    }

                    if (State == FlyState.SearchingForPerch)
                    {
                        Voxel vox = Creature.Physics.CurrentVoxel;

                        if (vox.WaterLevel > 0)
                        {
                            yield return(Act.Status.Running);

                            continue;
                        }

                        if (CanPerchOnGround)
                        {
                            Creature.Physics.ApplyForce(OriginalGravity, (float)DwarfTime.LastTime.ElapsedGameTime.TotalSeconds);
                            Voxel below = vox.GetVoxelBelow();

                            if (below != null && !below.IsEmpty && below.WaterLevel == 0)
                            {
                                State = FlyState.Perching;
                                continue;
                            }
                        }

                        if (CanPerchOnWalls)
                        {
                            foreach (Voxel n in Creature.Physics.Neighbors)
                            {
                                if (n != null && n.GridPosition.Y >= vox.GridPosition.Y && !n.IsEmpty)
                                {
                                    State = FlyState.Perching;
                                    continue;
                                }
                            }
                        }

                        /*
                         * if (CanPerchOnObjects)
                         * {
                         *  List<Body> objetcs = new List<Body>();
                         *  PlayState.ComponentManager.GetBodiesIntersecting(Creature.Physics.BoundingBox, objetcs, CollisionManager.CollisionType.Static);
                         *
                         *  if (objetcs.Count > 0)
                         *  {
                         *      State = FlyState.Perching;
                         *      continue;
                         *  }
                         * }
                         */
                    }

                    yield return(Status.Running);
                }

                yield return(Status.Running);
            }
        }