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); } }