public IEnumerable <Status> PerformCurrentAction() { MoveAction action = Path.First(); float t = 0; int currentIndex = 0; if (!GetCurrentAction(ref action, ref t, ref currentIndex)) { CleanupMinecart(); yield break; } Trace.Assert(t >= 0); Trace.Assert(action.SourceVoxel.IsValid); int nextID = currentIndex + 1; bool hasNextAction = false; Vector3 half = GetBoundingBoxOffset(); Vector3 nextPosition = Vector3.Zero; Vector3 currPosition = action.SourceVoxel.WorldPosition + half; currPosition += RandomPositionOffsets[currentIndex]; if (nextID < Path.Count) { hasNextAction = true; nextPosition = Path[nextID].SourceVoxel.WorldPosition; nextPosition += RandomPositionOffsets[nextID] + half; } else { hasNextAction = true; nextPosition = action.DestinationVoxel.WorldPosition + half; } Matrix transform = Agent.Physics.LocalTransform; Vector3 diff = (nextPosition - currPosition); Agent.GetRoot().SetFlag(GameComponent.Flag.Visible, true); switch (action.MoveType) { case MoveType.EnterVehicle: if (t < 0.5f) { Creature.NoiseMaker.MakeNoise("Jump", Agent.Position, false); } Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = Creature.Physics.Velocity.Y > 0 ? CharacterMode.Jumping : CharacterMode.Falling; if (hasNextAction) { float z = Easing.Ballistic(t, 1.0f, 1.0f); Vector3 start = currPosition; Vector3 end = nextPosition + Vector3.Up * 0.5f; Vector3 dx = (end - start) * t + start; dx.Y = start.Y * (1 - t) + end.Y * (t) + z; transform.Translation = dx; Agent.Physics.Velocity = new Vector3(diff.X, (dx.Y - Agent.Physics.Position.Y), diff.Z); } else { transform.Translation = currPosition; } if (t > 0.9f) { SetupMinecart(); } break; case MoveType.ExitVehicle: CleanupMinecart(); transform.Translation = currPosition; break; case MoveType.RideVehicle: SetupMinecart(); Creature.CurrentCharacterMode = CharacterMode.Minecart; var rail = action.SourceState.VehicleState.Rail; if (rail == null) { if (hasNextAction) { transform.Translation = diff * t + currPosition; Agent.Physics.Velocity = diff; } else { transform.Translation = currPosition; } } else { //Drawer3D.DrawBox(rail.GetContainingVoxel().GetBoundingBox(), Color.Green, 0.1f, true); var pos = rail.InterpolateSpline(t, action.SourceVoxel.WorldPosition + Vector3.One * 0.5f, action.DestinationVoxel.WorldPosition + Vector3.One * 0.5f); transform.Translation = pos + Vector3.Up * 0.5f; Agent.Physics.Velocity = diff; } break; case MoveType.Walk: CleanupMinecart(); Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = CharacterMode.Walking; if (hasNextAction) { transform.Translation = diff * t + currPosition; Agent.Physics.Velocity = diff; } else { transform.Translation = currPosition; } break; case MoveType.Swim: CleanupMinecart(); Creature.NoiseMaker.MakeNoise("Swim", Agent.Position, true); Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = CharacterMode.Swimming; if (hasNextAction) { transform.Translation = diff * t + currPosition; Agent.Physics.Velocity = diff; } else { transform.Translation = currPosition; } break; case MoveType.Jump: CleanupMinecart(); if (t < 0.5f) { Creature.NoiseMaker.MakeNoise("Jump", Agent.Position, false); } Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = Creature.Physics.Velocity.Y > 0 ? CharacterMode.Jumping : CharacterMode.Falling; if (hasNextAction) { float z = Easing.Ballistic(t, 1.0f, 1.0f); Vector3 start = currPosition; Vector3 end = nextPosition; Vector3 dx = (end - start) * t + start; dx.Y = start.Y * (1 - t) + end.Y * (t) + z; transform.Translation = dx; Agent.Physics.Velocity = new Vector3(diff.X, (dx.Y - Agent.Physics.Position.Y), diff.Z); } else { transform.Translation = currPosition; } break; case MoveType.Fall: CleanupMinecart(); Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = CharacterMode.Falling; if (hasNextAction) { transform.Translation = diff * t + currPosition; Agent.Physics.Velocity = diff; } else { transform.Translation = currPosition; } break; case MoveType.Climb: case MoveType.ClimbWalls: CleanupMinecart(); if (((int)((t + 1) * 100)) % 50 == 0) { Creature.NoiseMaker.MakeNoise("Climb", Agent.Position, false); } Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = CharacterMode.Climbing; Creature.OverrideCharacterMode = true; if (hasNextAction) { if (action.MoveType == MoveType.ClimbWalls && action.ActionVoxel.IsValid) { Agent.Physics.Velocity = (action.DestinationVoxel.WorldPosition + Vector3.One * 0.5f) - currPosition; transform.Translation = diff * t + currPosition; } else if (action.MoveType == MoveType.Climb && action.InteractObject != null) { var ladderPosition = action.InteractObject.GetRoot().GetComponent <Body>().Position; transform.Translation = diff * t + currPosition; Agent.Physics.Velocity = ladderPosition - currPosition; } } else { transform.Translation = currPosition; } break; case MoveType.Fly: CleanupMinecart(); if (((int)((t + 1) * 100)) % 2 == 0) { Creature.NoiseMaker.MakeNoise("Flap", Agent.Position, false); } Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = CharacterMode.Flying; Creature.OverrideCharacterMode = true; if (hasNextAction) { transform.Translation = diff * t + currPosition; Agent.Physics.Velocity = diff; } else { transform.Translation = currPosition; } break; case MoveType.DestroyObject: CleanupMinecart(); var melee = new MeleeAct(Creature.AI, (Body)action.InteractObject); melee.Initialize(); foreach (var status in melee.Run()) { if (status == Act.Status.Fail) { yield return(Act.Status.Fail); } yield return(Act.Status.Running); } yield return(Act.Status.Success); yield break; case MoveType.Teleport: if (lastMovement != MoveType.Teleport) { if (action.InteractObject != null) { var teleporter = action.InteractObject.GetComponent <MagicalObject>(); if (teleporter != null) { teleporter.CurrentCharges--; } } SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_ic_dwarf_magic_research, currPosition, true, 1.0f); } Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, false); Agent.World.ParticleManager.Trigger("star_particle", diff * t + currPosition, Color.White, 1); if (action.InteractObject != null) { Agent.World.ParticleManager.Trigger("green_flame", (action.InteractObject as Body).Position, Color.White, 1); } transform.Translation = action.DestinationVoxel.WorldPosition + Vector3.One * 0.5f; break; } Agent.Physics.LocalTransform = transform; lastMovement = action.MoveType; }
public IEnumerable <Status> FindGreedyPath() { Vector3 target = Target.Position; if (Is2D) { target.Y = Creature.AI.Position.Y; } List <MoveAction> path = new List <MoveAction>(); var curr = Creature.Physics.CurrentVoxel; for (int i = 0; i < PathLength; i++) { IEnumerable <MoveAction> actions = Creature.AI.Movement.GetMoveActions(curr); MoveAction?bestAction = null; float bestDist = float.MaxValue; foreach (MoveAction action in actions) { float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared(); if (dist < bestDist) { bestDist = dist; bestAction = action; } } Vector3 half = Vector3.One * 0.5f; if (bestAction.HasValue && !path.Any(p => p.DestinationVoxel.Equals(bestAction.Value.DestinationVoxel) && p.MoveType == bestAction.Value.MoveType)) { path.Add(bestAction.Value); MoveAction action = bestAction.Value; action.DestinationVoxel = curr; curr = bestAction.Value.DestinationVoxel; bestAction = action; if (((bestAction.Value.DestinationVoxel.WorldPosition + half) - target).Length() < Threshold) { break; } } } if (path.Count > 0) { path.Insert(0, new MoveAction() { Diff = Vector3.Zero, DestinationVoxel = path[0].SourceVoxel, SourceVoxel = Creature.Physics.CurrentVoxel, MoveType = MoveType.Walk }); Creature.AI.Blackboard.SetData("RandomPath", path); yield return(Status.Success); } else { yield return(Status.Fail); } }
public IEnumerable <Status> PerformStep(MoveAction Step) { var actionSpeed = GetAgentSpeed(Step.MoveType); switch (Step.MoveType) { #region Ride Elevator case MoveType.RideElevator: var shafts = Step.DestinationState.Tag as Elevators.ElevatorMoveState; if (shafts == null || shafts.Entrance == null || shafts.Entrance.IsDead || shafts.Exit == null || shafts.Exit.IsDead) { yield return(Status.Fail); } var shaft = shafts.Entrance.Shaft; if (shaft == null || shaft.Invalid) { yield return(Status.Fail); } if (!shaft.EnqueuDwarf(Agent, shafts)) { yield return(Status.Fail); } while (!shaft.ReadyToBoard(Agent)) { if (DeltaTime > 30.0f) { yield return(Status.Fail); // We waited too long. } if (shaft.Invalid) { yield return(Status.Fail); } SetCharacterMode(CharacterMode.Idle); if (Debugger.Switches.DebugElevators) { Drawer3D.DrawBox(shafts.Entrance.GetBoundingBox(), Color.Red, 0.1f, false); Drawer3D.DrawBox(shafts.Exit.GetBoundingBox(), Color.Red, 0.1f, false); Drawer3D.DrawBox(Step.DestinationVoxel.GetBoundingBox(), Color.Red, 0.1f, false); } yield return(Status.Running); } DeltaTime = 0; foreach (var bit in Translate(Agent.Position, GetPathPoint(shafts.Entrance.GetContainingVoxel()), actionSpeed)) { if (shaft.Invalid) { yield return(Status.Fail); } shaft.WaitForMe(Agent); SetCharacterMode(CharacterMode.Walking); if (Debugger.Switches.DebugElevators) { Drawer3D.DrawBox(shafts.Entrance.GetBoundingBox(), Color.Green, 0.1f, false); Drawer3D.DrawBox(shafts.Exit.GetBoundingBox(), Color.Green, 0.1f, false); Drawer3D.DrawBox(Step.DestinationVoxel.GetBoundingBox(), Color.Green, 0.1f, false); } yield return(Status.Running); } shaft.StartMotion(Agent); var grav = Creature.Physics.Gravity; //Creature.Physics.Gravity = Vector3.Zero; while (!shaft.AtDestination(Agent)) { if (shaft.Invalid) { yield return(Status.Fail); } SetCharacterMode(CharacterMode.Idle); if (Debugger.Switches.DebugElevators) { Drawer3D.DrawBox(shafts.Entrance.GetBoundingBox(), Color.Red, 0.1f, false); Drawer3D.DrawBox(shafts.Exit.GetBoundingBox(), Color.Red, 0.1f, false); Drawer3D.DrawBox(Step.DestinationVoxel.GetBoundingBox(), Color.Red, 0.1f, false); } yield return(Status.Running); } DeltaTime = 0; foreach (var bit in Translate(Agent.Physics.LocalPosition, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { if (shaft.Invalid) { yield return(Status.Fail); } shaft.WaitForMe(Agent); SetCharacterMode(CharacterMode.Walking); if (Debugger.Switches.DebugElevators) { Drawer3D.DrawBox(shafts.Entrance.GetBoundingBox(), Color.Green, 0.1f, false); Drawer3D.DrawBox(shafts.Exit.GetBoundingBox(), Color.Green, 0.1f, false); Drawer3D.DrawBox(Step.DestinationVoxel.GetBoundingBox(), Color.Green, 0.1f, false); } yield return(Status.Running); } Creature.Physics.Gravity = grav; shaft.Done(Agent); break; #endregion case MoveType.EnterVehicle: Creature.NoiseMaker.MakeNoise("Jump", Agent.Position, false); foreach (var bit in Jump(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), Step.DestinationVoxel.Center - Step.SourceVoxel.Center, actionSpeed)) { SetCharacterMode(Creature.Physics.Velocity.Y > 0 ? CharacterMode.Jumping : CharacterMode.Falling); yield return(Status.Running); } DeltaTime = 0.0f; SetupMinecart(); break; case MoveType.ExitVehicle: CleanupMinecart(); SetAgentTranslation(GetPathPoint(Step.DestinationVoxel)); break; case MoveType.RideVehicle: SetupMinecart(); var rail = Step.SourceState.Rail; if (rail == null) { yield return(Status.Fail); } while (DeltaTime < 1.0f / actionSpeed) { var pos = rail.InterpolateSpline(DeltaTime, GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel)); var transform = Agent.Physics.LocalTransform; transform.Translation = pos + Vector3.Up * 0.5f; Agent.Physics.LocalTransform = transform; Agent.Physics.Velocity = GetPathPoint(Step.DestinationVoxel) - GetPathPoint(Step.SourceVoxel); SetCharacterMode(CharacterMode.Minecart); yield return(Status.Running); } DeltaTime -= (1.0f / actionSpeed); break; case MoveType.Walk: // Todo: Fail if distance is too great. CleanupMinecart(); foreach (var bit in Translate(Agent.Position, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { SetCharacterMode(CharacterMode.Walking); yield return(Status.Running); } break; case MoveType.Swim: CleanupMinecart(); foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel) + (0.5f * Vector3.Up * Agent.Physics.BoundingBox.Extents().Y), actionSpeed)) { Creature.NoiseMaker.MakeNoise("Swim", Agent.Position, true); SetCharacterMode(CharacterMode.Swimming); yield return(Status.Running); } break; case MoveType.Jump: CleanupMinecart(); Creature.NoiseMaker.MakeNoise("Jump", Agent.Position, false); var dest = GetPathPoint(Step.DestinationVoxel); foreach (var bit in Jump(Agent.Position, dest, dest - Agent.Position, actionSpeed / 2.0f)) { Creature.OverrideCharacterMode = false; SetCharacterMode(Creature.Physics.Velocity.Y > 0 ? CharacterMode.Jumping : CharacterMode.Falling); yield return(Status.Running); } SetAgentTranslation(dest); break; case MoveType.Fall: CleanupMinecart(); foreach (var bit in Translate(Agent.Position, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { SetCharacterMode(CharacterMode.Falling); yield return(Status.Running); } break; case MoveType.Climb: CleanupMinecart(); DeltaTime = 0.0f; foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), actionSpeed)) { if (Step.InteractObject == null || Step.InteractObject.IsDead) { yield return(Status.Fail); } if (DeltaTime - LastNoiseTime > 1.0f) { Creature.NoiseMaker.MakeNoise("Climb", Agent.Position, false); LastNoiseTime = DeltaTime; } SetCharacterMode(CharacterMode.Climbing); yield return(Status.Running); } break; case MoveType.ClimbWalls: CleanupMinecart(); DeltaTime = 0.0f; foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), actionSpeed)) { if (DeltaTime - LastNoiseTime > 1.0f) { Creature.NoiseMaker.MakeNoise("Climb", Agent.Position, false); LastNoiseTime = DeltaTime; } SetCharacterMode(CharacterMode.Climbing); if (Step.ActionVoxel.IsValid) { var voxelVector = new Vector3(Step.ActionVoxel.Coordinate.X + 0.5f, Agent.Physics.Position.Y, Step.ActionVoxel.Coordinate.Z + 0.5f); Agent.Physics.Velocity = Vector3.Normalize(voxelVector - Agent.Physics.Position) * actionSpeed; } yield return(Status.Running); } break; case MoveType.Fly: CleanupMinecart(); DeltaTime = 0.0f; foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), actionSpeed)) { if ((int)(DeltaTime * 100) % 2 == 0) { Creature.NoiseMaker.MakeNoise("Flap", Agent.Position, false); } SetCharacterMode(CharacterMode.Flying); yield return(Status.Running); } break; case MoveType.Dig: CleanupMinecart(); var destroy = new DigAct(Creature.AI, new KillVoxelTask(Step.DestinationVoxel)) { CheckOwnership = false }; destroy.Initialize(); foreach (var status in destroy.Run()) { if (status == Act.Status.Fail) { yield return(Act.Status.Fail); } yield return(Act.Status.Running); } yield return(Act.Status.Fail); // Abort the path so that they stop digging if a path has opened. break; case MoveType.DestroyObject: CleanupMinecart(); var melee = new MeleeAct(Creature.AI, (GameComponent)Step.InteractObject); melee.Initialize(); foreach (var status in melee.Run()) { if (status == Act.Status.Fail) { yield return(Act.Status.Fail); } yield return(Act.Status.Running); } yield return(Act.Status.Fail); // Abort the path so that they stop destroying things if a path has opened. break; case MoveType.Teleport: if (Step.InteractObject == null || Step.InteractObject.IsDead) { yield return(Status.Fail); } var teleporter = Step.InteractObject.GetComponent <MagicalObject>(); if (teleporter != null) { teleporter.CurrentCharges--; } SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_ic_dwarf_magic_research, Agent.Position, true, 1.0f); Agent.World.ParticleManager.Trigger("green_flame", (Step.InteractObject as GameComponent).Position, Color.White, 1); Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, false); foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), actionSpeed)) { Agent.World.ParticleManager.Trigger("star_particle", Agent.Position, Color.White, 1); yield return(Status.Running); } Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true); break; } }
public IEnumerable <Act.Status> GreedyFallbackBehavior(Creature agent) { var edgeGoal = new EdgeGoalRegion(); while (true) { DieTimer.Update(DwarfTime.LastTime); if (DieTimer.HasTriggered) { foreach (var status in Die(agent)) { continue; } yield break; } var creatureVoxel = agent.Physics.CurrentVoxel; List <MoveAction> path = new List <MoveAction>(); var storage = new MoveActionTempStorage(); for (int i = 0; i < 10; i++) { if (edgeGoal.IsInGoalRegion(creatureVoxel)) { foreach (var status in Die(agent)) { continue; } yield return(Act.Status.Success); yield break; } var actions = agent.AI.Movement.GetMoveActions(new MoveState { Voxel = creatureVoxel }, new List <GameComponent>(), storage); float minCost = float.MaxValue; var minAction = new MoveAction(); bool hasMinAction = false; foreach (var action in actions) { var vox = action.DestinationVoxel; float cost = edgeGoal.Heuristic(vox) * 10 + MathFunctions.Rand(0.0f, 0.1f) + agent.AI.Movement.Cost(action.MoveType); if (cost < minCost) { minAction = action; minCost = cost; hasMinAction = true; } } if (hasMinAction) { path.Add(minAction); creatureVoxel = minAction.DestinationVoxel; } else { foreach (var status in Die(agent)) { continue; } yield return(Act.Status.Success); yield break; } } if (path.Count == 0) { foreach (var status in Die(agent)) { continue; } yield return(Act.Status.Success); yield break; } agent.AI.Blackboard.SetData("GreedyPath", path); var pathAct = new FollowPathAct(agent.AI, "GreedyPath"); pathAct.Initialize(); foreach (Act.Status status in pathAct.Run()) { yield return(Act.Status.Running); } yield return(Act.Status.Running); } }
public IEnumerable <Status> AvoidTarget(float range, float time) { if (Target == null) { yield return(Status.Fail); yield break; } Timer avoidTimer = new Timer(time, true, Timer.TimerMode.Game); while (true) { avoidTimer.Update(DwarfTime.LastTime); if (avoidTimer.HasTriggered) { yield return(Status.Success); } float dist = (Target.Position - Agent.Position).Length(); if (dist > range) { yield return(Status.Success); yield break; } List <MoveAction> neighbors = Agent.Movement.GetMoveActions(Agent.Position).ToList(); neighbors.Sort((a, b) => { if (a.Equals(b)) { return(0); } float da = (a.DestinationVoxel.WorldPosition - Target.Position).LengthSquared(); float db = (b.DestinationVoxel.WorldPosition - Target.Position).LengthSquared(); return(da.CompareTo(db)); }); neighbors.RemoveAll( a => a.MoveType == MoveType.Jump || a.MoveType == MoveType.Climb); if (neighbors.Count == 0) { yield return(Status.Fail); yield break; } MoveAction furthest = neighbors.Last(); bool reachedTarget = false; Timer timeout = new Timer(2.0f, true); while (!reachedTarget) { Vector3 output = Creature.Controller.GetOutput(DwarfTime.Dt, furthest.DestinationVoxel.WorldPosition + Vector3.One * 0.5f, Agent.Position); Creature.Physics.ApplyForce(output, DwarfTime.Dt); if (Creature.AI.Movement.CanFly) { Creature.Physics.ApplyForce(Vector3.Up * 10, DwarfTime.Dt); } timeout.Update(DwarfTime.LastTime); yield return(Status.Running); if (timeout.HasTriggered || (furthest.DestinationVoxel.WorldPosition - Agent.Position).Length() < 1) { reachedTarget = true; } Agent.Creature.CurrentCharacterMode = CharacterMode.Walking; } yield return(Status.Success); yield break; } }
public List <MoveAction> ComputeGreedyFallback(int maxsteps = 10, List <VoxelHandle> exploredVoxels = null) { List <MoveAction> toReturn = new List <MoveAction>(); GoalRegion goal = GetGoal(); var creatureVoxel = Agent.Physics.CurrentVoxel; if (goal.IsInGoalRegion(creatureVoxel)) { return(toReturn); } var currentVoxel = creatureVoxel; while (toReturn.Count < maxsteps) { var actions = Agent.Movement.GetMoveActions(new MoveState() { Voxel = currentVoxel }, Creature.World.OctTree); float minCost = float.MaxValue; var minAction = new MoveAction(); bool hasMinAction = false; foreach (var action in actions) { if (toReturn.Any(a => a.DestinationVoxel == action.DestinationVoxel && a.MoveType == action.MoveType)) { continue; } var vox = action.DestinationVoxel; float cost = goal.Heuristic(vox) * MathFunctions.Rand(1.0f, 1.1f) + Agent.Movement.Cost(action.MoveType); if (exploredVoxels != null && exploredVoxels.Contains(action.DestinationVoxel)) { cost *= 10; } if (cost < minCost) { minAction = action; minCost = cost; hasMinAction = true; } } if (hasMinAction) { MoveAction action = minAction; action.DestinationVoxel = currentVoxel; toReturn.Add(action); currentVoxel = minAction.DestinationVoxel; if (goal.IsInGoalRegion(minAction.DestinationVoxel)) { return(toReturn); } } else { return(toReturn); } } return(toReturn); }
/// <summary> gets the list of actions that the creature can take from a given voxel. </summary> public IEnumerable <MoveAction> GetMoveActions(MoveState state, OctTreeNode <Body> OctTree, List <Body> teleportObjects, MoveActionTempStorage Storage) { if (Parent == null) { yield break; } if (!state.Voxel.IsValid) { yield break; } if (Creature == null) { yield break; } if (Storage == null) { Storage = new MoveActionTempStorage(); } GetNeighborhood(state.Voxel.Chunk.Manager.ChunkData, state.Voxel, Storage.Neighborhood); bool inWater = (Storage.Neighborhood[1, 1, 1].IsValid && Storage.Neighborhood[1, 1, 1].LiquidLevel > WaterManager.inWaterThreshold); bool standingOnGround = (Storage.Neighborhood[1, 0, 1].IsValid && !Storage.Neighborhood[1, 0, 1].IsEmpty); bool topCovered = (Storage.Neighborhood[1, 2, 1].IsValid && !Storage.Neighborhood[1, 2, 1].IsEmpty); bool hasNeighbors = HasNeighbors(Storage.Neighborhood); bool isRiding = state.VehicleState.IsRidingVehicle; var neighborHoodBounds = new BoundingBox(Storage.Neighborhood[0, 0, 0].GetBoundingBox().Min, Storage.Neighborhood[2, 2, 2].GetBoundingBox().Max); Storage.NeighborObjects.Clear(); OctTree.EnumerateItems(neighborHoodBounds, Storage.NeighborObjects); if (Can(MoveType.Teleport)) { foreach (var obj in teleportObjects) { if ((obj.Position - state.Voxel.WorldPosition).LengthSquared() < TeleportDistanceSquared) { yield return new MoveAction() { InteractObject = obj, MoveType = MoveType.Teleport, SourceVoxel = state.Voxel, DestinationState = new MoveState() { Voxel = new VoxelHandle(state.Voxel.Chunk.Manager.ChunkData, GlobalVoxelCoordinate.FromVector3(obj.Position)) } } } } } ; var successors = EnumerateSuccessors(state, state.Voxel, Storage, inWater, standingOnGround, topCovered, hasNeighbors, isRiding); // Now, validate each move action that the creature might take. foreach (MoveAction v in successors) { var n = v.DestinationVoxel.IsValid ? v.DestinationVoxel : Storage.Neighborhood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z]; if (n.IsValid && (v.MoveType == MoveType.Dig || isRiding || n.IsEmpty || n.LiquidLevel > 0)) { // Do one final check to see if there is an object blocking the motion. bool blockedByObject = false; if (!isRiding) { var objectsAtNeighbor = Storage.NeighborObjects.Where(o => o.GetBoundingBox().Intersects(n.GetBoundingBox())); // If there is an object blocking the motion, determine if it can be passed through. foreach (var body in objectsAtNeighbor) { var door = body as Door; // ** Doors are in the octtree, pretty sure this was always pointless -- var door = body.GetRoot().EnumerateAll().OfType<Door>().FirstOrDefault(); // If there is an enemy door blocking movement, we can destroy it to get through. if (door != null) { if ( Creature.World.Diplomacy.GetPolitics(door.TeamFaction, Creature.Faction) .GetCurrentRelationship() == Relationship.Hateful) { if (Can(MoveType.DestroyObject)) { yield return(new MoveAction { Diff = v.Diff, MoveType = MoveType.DestroyObject, InteractObject = door, DestinationVoxel = n, SourceState = state }); } blockedByObject = true; } } } } // If no object blocked us, we can move freely as normal. if (!blockedByObject && n.LiquidType != LiquidType.Lava) { MoveAction newAction = v; newAction.SourceState = state; newAction.DestinationVoxel = n; yield return(newAction); } } } }
public IEnumerable <MoveAction> GetInverseMoveActions_Experimental(VoxelHandle voxel) { if (!voxel.IsValid || !voxel.IsEmpty) { yield break; } CollisionManager objectHash = Creature.Manager.World.CollisionManager; var neighborHood = GetNeighborhood(voxel); bool inWater = (neighborHood[1, 1, 1].IsValid && neighborHood[1, 1, 1].WaterCell.WaterLevel > WaterManager.inWaterThreshold); bool standingOnGround = (neighborHood[1, 0, 1].IsValid && !neighborHood[1, 0, 1].IsEmpty); bool topCovered = (neighborHood[1, 2, 1].IsValid && !neighborHood[1, 2, 1].IsEmpty); bool hasNeighbors = HasNeighbors(neighborHood); bool isClimbing = false; var successors = new List <MoveAction>(); if (CanClimb) { var ladderAt = GetBodyAt(voxel, objectHash, "Climbable"); var ladderAbove = GetBodyAt(VoxelHelpers.GetVoxelAbove(voxel), objectHash, "Climbable"); var ladderBelow = GetBodyAt(VoxelHelpers.GetNeighbor(voxel, new GlobalVoxelOffset(0, -1, 0)), objectHash, "Climbable"); // If there was a ladder above the creature, we could have climbed down it to get here. if (ladderAbove != null) { successors.Add(new MoveAction { Diff = new Vector3(1, 2, 1), MoveType = MoveType.Climb, InteractObject = ladderAbove }); } // If there was a ladder below the creature, we could have climbed up to get here. if (ladderBelow != null) { successors.Add(new MoveAction { Diff = new Vector3(1, 0, 1), MoveType = MoveType.Climb, InteractObject = ladderBelow }); } if (ladderAt != null) { standingOnGround = true; isClimbing = true; } } // If the creature can climb walls, check to see if there are any walls nearby that we could have climbed here from. if (CanClimbWalls && !topCovered) { // First check the voxel above to see if it has any walls nearby. if (!topCovered) { var wallsAbove = new VoxelHandle[] { neighborHood[2, 2, 1], neighborHood[0, 2, 1], neighborHood[1, 2, 2], neighborHood[1, 2, 0] }; var wallAbove = VoxelHandle.InvalidHandle; foreach (var w in wallsAbove) { if (w.IsValid && !w.IsEmpty) { wallAbove = w; break; } } // If there was a wall above us, we could have climbed down to get here. if (wallAbove.IsValid) { successors.Add(new MoveAction { Diff = new Vector3(1, 2, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wallAbove }); } } // Now check the walls below if (!standingOnGround) { var wallsBelow = new VoxelHandle[] { neighborHood[2, 0, 1], neighborHood[0, 0, 1], neighborHood[1, 0, 2], neighborHood[1, 0, 0] }; var wallBelow = VoxelHandle.InvalidHandle; foreach (var w in wallsBelow) { if (w.IsValid && !w.IsEmpty) { wallBelow = w; break; } } // If there was a wall below us, we could have climbed up to get here. if (wallBelow.IsValid) { successors.Add(new MoveAction { Diff = new Vector3(1, 0, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wallBelow }); } } } // If the creature either can walk or is in water, add the // eight-connected free neighbors around the voxel. if (CanWalk || CanSwim) { // If the creature is in water, it can swim. Otherwise, it will walk. var moveType = inWater ? MoveType.Swim : MoveType.Walk; if (neighborHood[0, 1, 1].IsValid && neighborHood[0, 1, 1].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[0, 0, 1].IsValid && !neighborHood[0, 0, 1].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(0, 1, 1), MoveType = moveType }); } } if (neighborHood[2, 1, 1].IsValid && neighborHood[2, 1, 1].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[2, 0, 1].IsValid && !neighborHood[2, 0, 1].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(2, 1, 1), MoveType = moveType }); } } if (neighborHood[1, 1, 0].IsValid && neighborHood[1, 1, 0].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[1, 0, 0].IsValid && !neighborHood[1, 0, 0].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(1, 1, 0), MoveType = moveType }); } } if (neighborHood[1, 1, 2].IsValid && neighborHood[1, 1, 2].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[1, 0, 2].IsValid && !neighborHood[1, 0, 2].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(1, 1, 2), MoveType = moveType }); } } // Only bother worrying about 8-connected movement if there are // no full neighbors around the voxel. if (!hasNeighbors) { if (neighborHood[2, 1, 2].IsValid && neighborHood[2, 1, 2].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[2, 0, 2].IsValid && !neighborHood[2, 0, 2].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(2, 1, 2), MoveType = moveType }); } } if (neighborHood[2, 1, 0].IsValid && neighborHood[2, 1, 0].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[2, 0, 0].IsValid && !neighborHood[2, 0, 0].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(2, 1, 0), MoveType = moveType }); } } if (neighborHood[0, 1, 2].IsValid && neighborHood[0, 1, 2].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[0, 0, 2].IsValid && !neighborHood[0, 0, 2].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(0, 1, 2), MoveType = moveType }); } } if (neighborHood[0, 1, 0].IsValid && neighborHood[0, 1, 0].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[0, 0, 0].IsValid && !neighborHood[0, 0, 0].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(0, 1, 0), MoveType = moveType }); } } } } // Now a somewhat tricky part. We've got to figure out which cells can jump to this cell. // The rules for jumping are as follows: // 1) The voxel must be exactly 1 below this one. // 2) The voxel must be exactly 1 away in the other dimensions // 3) The voxel above the one we're jumping from must be free. // 4) The voxel below the one we're jumping from must be filled, or be in water, or // must be part of a climb action. // Step 4 is really hard, so let's ignore it for now. // First, check the 3x3 neighborhood around the voxel. if (standingOnGround) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { // Ignore the current voxel (can't jump from there) if (dx == 1 && dz == 1) { continue; } // Can't jump from neighbor because neighbor's head isn't clear. if (!(neighborHood[dx, 1, dz].IsValid && neighborHood[dx, 1, dz].IsEmpty)) { continue; } // Now just assume we can jump from the neighbor below us. TODO (step 4) successors.Add(new MoveAction { Diff = new Vector3(dx, 0, dz), MoveType = MoveType.Jump }); } } } // If the creature is not in water and is not standing on ground, // it can fall one voxel downward in free space. So check the voxel above, // if it is free and has no water, then we could have fallen from it. if (neighborHood[1, 2, 1].IsValid && neighborHood[1, 2, 1].IsEmpty && neighborHood[1, 2, 1].WaterCell.WaterLevel == 0) { successors.Add(new MoveAction { Diff = new Vector3(1, 2, 1), MoveType = MoveType.Fall }); } // If the creature can fly and is not underwater, it can fly // to any adjacent empty cell. Luckily this is reversible so we don't have to change // anything from GetMoveactions if (CanFly && !inWater) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { for (int dy = 0; dy <= 2; dy++) { if (dx == 1 && dz == 1 && dy == 1) { continue; } if (!neighborHood[dx, 1, dz].IsValid || neighborHood[dx, 1, dz].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(dx, dy, dz), MoveType = MoveType.Fly }); } } } } } // Now, validate each move action that the creature might take. foreach (MoveAction v in successors) { var n = neighborHood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z]; if (n.IsValid && (n.IsEmpty || n.WaterCell.WaterLevel > 0)) { // Do one final check to see if there is an object blocking the motion. bool blockedByObject = false; var objectsAtNeighbor = Creature.Manager.World.CollisionManager.EnumerateIntersectingObjects( n.GetBoundingBox(), CollisionManager.CollisionType.Static); // If there is an object blocking the motion, determine if it can be passed through. foreach (var body in objectsAtNeighbor.OfType <GameComponent>()) { var door = body.GetRoot().EnumerateAll().OfType <Door>().FirstOrDefault(); // If there is an enemy door blocking movement, we can destroy it to get through. if (door != null) { if ( Creature.World.Diplomacy.GetPolitics(door.TeamFaction, Creature.Faction) .GetCurrentRelationship() != Relationship.Loving) { if (Can(MoveType.DestroyObject)) { yield return(new MoveAction { Diff = -(v.Diff - Vector3.One), MoveType = MoveType.DestroyObject, InteractObject = door, DestinationVoxel = voxel, SourceVoxel = n }); } blockedByObject = true; } } } // If no object blocked us, we can move freely as normal. if (!blockedByObject) { MoveAction newAction = v; newAction.Diff = -(v.Diff - Vector3.One); newAction.DestinationVoxel = voxel; newAction.SourceVoxel = n; yield return(newAction); } } } }
public override IEnumerable <Status> Run() { InitializePath(); if (Path == null || Path.Count == 0) { yield return(Act.Status.Success); } if (TrajectoryTimer == null) { yield break; } while (!TrajectoryTimer.HasTriggered) { Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true); TrajectoryTimer.Update(DwarfTime.LastTime); ValidPathTimer.Update(DwarfTime.LastTime); foreach (Status status in PerformCurrentAction()) { if (status == Status.Fail) { CleanupMinecart(); yield return(Status.Fail); } else if (status == Status.Success) { break; } Creature.Physics.AnimationQueue.Clear(); yield return(Status.Running); } if (Debugger.Switches.DrawPaths) { List <Vector3> points = Path.Select( (v, i) => v.SourceVoxel.WorldPosition + new Vector3(0.5f, 0.5f, 0.5f) + RandomPositionOffsets[i]) .ToList(); points.Add(Path[Path.Count - 1].DestinationVoxel.WorldPosition + new Vector3(0.5f, 0.5f, 0.5f)); List <Color> colors = Path.Select((v, i) => { switch (v.MoveType) { case MoveType.Climb: return(Color.Cyan); case MoveType.ClimbWalls: return(Color.DarkCyan); case MoveType.DestroyObject: return(Color.Orange); case MoveType.Fall: return(Color.LightBlue); case MoveType.Fly: return(Color.Green); case MoveType.Jump: return(Color.Yellow); case MoveType.Swim: return(Color.Blue); case MoveType.Walk: return(Color.Red); } return(Color.White); }) .ToList(); colors.Add(Color.White); Drawer3D.DrawLineList(points, colors, 0.1f); } float t = 0; int currentIndex = 0; MoveAction action = new MoveAction(); if (GetCurrentAction(ref action, ref t, ref currentIndex)) { // Check if the path has been made invalid if (ValidPathTimer.HasTriggered && !IsPathValid(Path, currentIndex)) { Creature.OverrideCharacterMode = false; Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question); CleanupMinecart(); Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true); yield return(Status.Fail); } } Creature.Physics.AnimationQueue.Clear(); yield return(Status.Running); } Creature.OverrideCharacterMode = false; SetPath(null); Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true); CleanupMinecart(); yield return(Status.Success); }
/// <summary> gets the list of actions that the creature can take from a given voxel. </summary> public IEnumerable <MoveAction> GetMoveActions(VoxelHandle voxel) { if (!voxel.IsValid || !voxel.IsEmpty) { yield break; } CollisionManager objectHash = Creature.Manager.World.CollisionManager; var neighborHood = GetNeighborhood(voxel); bool inWater = (neighborHood[1, 1, 1].IsValid && neighborHood[1, 1, 1].WaterCell.WaterLevel > WaterManager.inWaterThreshold); bool standingOnGround = (neighborHood[1, 0, 1].IsValid && !neighborHood[1, 0, 1].IsEmpty); bool topCovered = (neighborHood[1, 2, 1].IsValid && !neighborHood[1, 2, 1].IsEmpty); bool hasNeighbors = HasNeighbors(neighborHood); bool isClimbing = false; var successors = new List <MoveAction>(); if (CanClimb) { //Climbing ladders. var bodies = objectHash.EnumerateIntersectingObjects(voxel.GetBoundingBox(), CollisionManager.CollisionType.Static).OfType <GameComponent>(); var ladder = bodies.FirstOrDefault(component => component.Tags.Contains("Climbable")); // if the creature can climb objects and a ladder is in this voxel, // then add a climb action. if (ladder != null) { successors.Add(new MoveAction { Diff = new Vector3(1, 2, 1), MoveType = MoveType.Climb, InteractObject = ladder }); isClimbing = true; if (!standingOnGround) { successors.Add(new MoveAction { Diff = new Vector3(1, 0, 1), MoveType = MoveType.Climb, InteractObject = ladder }); } standingOnGround = true; } } // If the creature can climb walls and is not blocked by a voxl above. if (CanClimbWalls && !topCovered) { var walls = new VoxelHandle[] { neighborHood[2, 1, 1], neighborHood[0, 1, 1], neighborHood[1, 1, 2], neighborHood[1, 1, 0] }; var wall = VoxelHandle.InvalidHandle; foreach (var w in walls) { if (w.IsValid && !w.IsEmpty) { wall = w; } } if (wall.IsValid) { isClimbing = true; successors.Add(new MoveAction { Diff = new Vector3(1, 2, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wall }); if (!standingOnGround) { successors.Add(new MoveAction { Diff = new Vector3(1, 0, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wall }); } } } // If the creature either can walk or is in water, add the // eight-connected free neighbors around the voxel. if ((CanWalk && standingOnGround) || (CanSwim && inWater)) { // If the creature is in water, it can swim. Otherwise, it will walk. var moveType = inWater ? MoveType.Swim : MoveType.Walk; if (!neighborHood[0, 1, 1].IsValid || neighborHood[0, 1, 1].IsEmpty) { // +- x successors.Add(new MoveAction { Diff = new Vector3(0, 1, 1), MoveType = moveType }); } if (!neighborHood[2, 1, 1].IsValid || neighborHood[2, 1, 1].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(2, 1, 1), MoveType = moveType }); } if (!neighborHood[1, 1, 0].IsValid || neighborHood[1, 1, 0].IsEmpty) { // +- z successors.Add(new MoveAction { Diff = new Vector3(1, 1, 0), MoveType = moveType }); } if (!neighborHood[1, 1, 2].IsValid || neighborHood[1, 1, 2].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(1, 1, 2), MoveType = moveType }); } // Only bother worrying about 8-connected movement if there are // no full neighbors around the voxel. if (!hasNeighbors) { if (!neighborHood[2, 1, 2].IsValid || neighborHood[2, 1, 2].IsEmpty) { // +x + z successors.Add(new MoveAction { Diff = new Vector3(2, 1, 2), MoveType = moveType }); } if (!neighborHood[2, 1, 0].IsValid || neighborHood[2, 1, 0].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(2, 1, 0), MoveType = moveType }); } if (!neighborHood[0, 1, 2].IsValid || neighborHood[0, 1, 2].IsEmpty) { // -x -z successors.Add(new MoveAction { Diff = new Vector3(0, 1, 2), MoveType = moveType }); } if (!neighborHood[0, 1, 0].IsValid || neighborHood[0, 1, 0].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(0, 1, 0), MoveType = moveType }); } } } // If the creature's head is free, and it is standing on ground, // or if it is in water, or if it is climbing, it can also jump // to voxels that are 1 cell away and 1 cell up. if (!topCovered && (standingOnGround || (CanSwim && inWater) || isClimbing)) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { if (dx == 1 && dz == 1) { continue; } if (neighborHood[dx, 1, dz].IsValid && !neighborHood[dx, 1, dz].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(dx, 2, dz), MoveType = MoveType.Jump }); } } } } // If the creature is not in water and is not standing on ground, // it can fall one voxel downward in free space. if (!inWater && !standingOnGround) { successors.Add(new MoveAction { Diff = new Vector3(1, 0, 1), MoveType = MoveType.Fall }); } // If the creature can fly and is not underwater, it can fly // to any adjacent empty cell. if (CanFly && !inWater) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { for (int dy = 0; dy <= 2; dy++) { if (dx == 1 && dz == 1 && dy == 1) { continue; } if (!neighborHood[dx, 1, dz].IsValid || neighborHood[dx, 1, dz].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(dx, dy, dz), MoveType = MoveType.Fly }); } } } } } // Now, validate each move action that the creature might take. foreach (MoveAction v in successors) { var n = neighborHood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z]; if (n.IsValid && (n.IsEmpty || n.WaterCell.WaterLevel > 0)) { // Do one final check to see if there is an object blocking the motion. bool blockedByObject = false; var objectsAtNeighbor = Creature.Manager.World.CollisionManager.EnumerateIntersectingObjects( n.GetBoundingBox(), CollisionManager.CollisionType.Static); // If there is an object blocking the motion, determine if it can be passed through. foreach (var body in objectsAtNeighbor.OfType <GameComponent>()) { var door = body.GetRoot().EnumerateAll().OfType <Door>().FirstOrDefault(); // If there is an enemy door blocking movement, we can destroy it to get through. if (door != null) { if ( Creature.World.Diplomacy.GetPolitics(door.TeamFaction, Creature.Faction) .GetCurrentRelationship() != Relationship.Loving) { if (Can(MoveType.DestroyObject)) { yield return(new MoveAction { Diff = v.Diff, MoveType = MoveType.DestroyObject, InteractObject = door, DestinationVoxel = n, SourceVoxel = voxel }); } blockedByObject = true; } } } // If no object blocked us, we can move freely as normal. if (!blockedByObject) { MoveAction newAction = v; newAction.SourceVoxel = voxel; newAction.DestinationVoxel = n; yield return(newAction); } } } }
public IEnumerable <Status> FindGreedyPath() { Vector3 target = Target.Position; if (Is2D) { target.Y = Creature.AI.Position.Y; } List <MoveAction> path = new List <MoveAction>(); var curr = Creature.Physics.CurrentVoxel; var bodies = Agent.World.PlayerFaction.OwnedObjects.Where(o => o.Tags.Contains("Teleporter")).ToList(); var storage = new MoveActionTempStorage(); for (int i = 0; i < PathLength; i++) { IEnumerable <MoveAction> actions = Creature.AI.Movement.GetMoveActions(new MoveState() { Voxel = curr }, bodies, storage); MoveAction?bestAction = null; float bestDist = float.MaxValue; foreach (MoveAction action in actions) { // Prevents a stack overflow due to "DestroyObject" task creating a FollowPathAct! if (action.MoveType == MoveType.DestroyObject) { continue; } float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared(); if (dist < bestDist) { bestDist = dist; bestAction = action; } } Vector3 half = Vector3.One * 0.5f; if (bestAction.HasValue && !path.Any(p => p.DestinationVoxel.Equals(bestAction.Value.DestinationVoxel) && p.MoveType == bestAction.Value.MoveType)) { path.Add(bestAction.Value); MoveAction action = bestAction.Value; action.DestinationVoxel = curr; curr = bestAction.Value.DestinationVoxel; bestAction = action; if (((bestAction.Value.DestinationVoxel.WorldPosition + half) - target).Length() < Threshold) { break; } } } if (path.Count > 0) { Creature.AI.Blackboard.SetData("RandomPath", path); yield return(Status.Success); } else { yield return(Status.Fail); } }
public IEnumerable <Status> FindRandomPath() { var target = MathFunctions.RandVector3Cube() * Radius + Creature.AI.Position; if (Creature.AI.PositionConstraint.Contains(target) == ContainmentType.Disjoint) { target = MathFunctions.RandVector3Box(Creature.AI.PositionConstraint); } if (Is2D) { target.Y = Creature.AI.Position.Y; } var path = new List <MoveAction>(); var curr = Creature.Physics.CurrentVoxel; var bodies = Agent.World.PlayerFaction.OwnedObjects.Where(o => o.Tags.Contains("Teleporter")).ToList(); var storage = new MoveActionTempStorage(); var previousMoveState = new MoveState { Voxel = curr }; for (int i = 0; i < PathLength; i++) { var actions = Creature.AI.Movement.GetMoveActions(previousMoveState, bodies, storage); MoveAction?bestAction = null; var bestDist = float.MaxValue; foreach (MoveAction action in actions) { if (Is2D && (action.MoveType == MoveType.Climb || action.MoveType == MoveType.ClimbWalls || action.MoveType == MoveType.Fall)) { continue; } float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared() * Creature.AI.Movement.Cost(action.MoveType); if (dist < bestDist && !path.Any(a => a.DestinationVoxel == action.DestinationVoxel)) { bestDist = dist; bestAction = action; } } if (bestAction.HasValue && !path.Any(p => p.DestinationVoxel.Equals(bestAction.Value.DestinationVoxel) && p.MoveType == bestAction.Value.MoveType && Creature.AI.PositionConstraint.Contains(bestAction.Value.DestinationVoxel.WorldPosition + Vector3.One * 0.5f) == ContainmentType.Contains)) { MoveAction action = bestAction.Value; path.Add(action); previousMoveState = action.DestinationState; } else { break; } } if (path.Count > 0) { Creature.AI.Blackboard.SetData("RandomPath", path); yield return(Status.Success); } else { yield return(Status.Fail); } }
public IEnumerable <Status> FindRandomPath() { Vector3 target = MathFunctions.RandVector3Cube() * Radius + Creature.AI.Position; if (Creature.AI.PositionConstraint.Contains(target) == ContainmentType.Disjoint) { target = MathFunctions.RandVector3Box(Creature.AI.PositionConstraint); } if (Is2D) { target.Y = Creature.AI.Position.Y; } List <MoveAction> path = new List <MoveAction>(); VoxelHandle curr = Creature.Physics.CurrentVoxel; for (int i = 0; i < PathLength; i++) { var actions = Creature.AI.Movement.GetMoveActions(new MoveState() { Voxel = curr }, Creature.World.OctTree); MoveAction?bestAction = null; float bestDist = float.MaxValue; foreach (MoveAction action in actions) { if (Is2D && (action.MoveType == MoveType.Climb || action.MoveType == MoveType.ClimbWalls)) { continue; } float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared() * Creature.AI.Movement.Cost(action.MoveType); if (dist < bestDist && !path.Any(a => a.DestinationVoxel == action.DestinationVoxel)) { bestDist = dist; bestAction = action; } } if (bestAction.HasValue && !path.Any(p => p.DestinationVoxel.Equals(bestAction.Value.DestinationVoxel) && p.MoveType == bestAction.Value.MoveType && Creature.AI.PositionConstraint.Contains(bestAction.Value.DestinationVoxel.WorldPosition + Vector3.One * 0.5f) == ContainmentType.Contains)) { MoveAction action = bestAction.Value; action.DestinationVoxel = curr; path.Add(action); curr = bestAction.Value.DestinationVoxel; } else { break; } } if (path.Count > 0) { Creature.AI.Blackboard.SetData("RandomPath", path); yield return(Status.Success); } else { yield return(Status.Fail); } }
public static List <MoveAction> ReconstructInversePath(GoalRegion goal, Dictionary <MoveState, MoveAction> cameFrom, MoveAction currentNode) { var toReturn = new List <MoveAction>() { currentNode }; while (true) { if (!cameFrom.ContainsKey(currentNode.DestinationState)) { break; } currentNode = cameFrom[currentNode.DestinationState]; toReturn.Add(currentNode); /* * for (int frames = 0; frames < 6; frames++) * { * var sourceColor = goal.IsInGoalRegion(currentNode.SourceVoxel) ? Color.Green : Color.Red; * Drawer3D.DrawLine(currentNode.SourceVoxel.WorldPosition + Vector3.One * 0.5f, * currentNode.DestinationVoxel.WorldPosition + Vector3.One * 0.5f, Color.Red, 0.1f); * Drawer3D.DrawBox(currentNode.SourceVoxel.GetBoundingBox(), sourceColor, 0.1f, true); * Drawer3D.DrawBox(currentNode.DestinationVoxel.GetBoundingBox(), Color.Yellow, 0.1f, true); * foreach (var pair in cameFrom) * { * var color = Color.White; * if (goal.IsInGoalRegion(pair.Value.SourceVoxel)) * color = Color.Green; * Drawer3D.DrawLine(pair.Value.SourceVoxel.WorldPosition + Vector3.One * 0.5f, * pair.Value.DestinationVoxel.WorldPosition + Vector3.One * 0.5f, color, 0.05f); * * } * System.Threading.Thread.Sleep(16); * } */ if (goal.IsInGoalRegion(currentNode.DestinationState.Voxel)) { break; } } return(toReturn); }