public EntityAction(MoveAction?moveAction, BuildAction?buildAction, AttackAction?attackAction, RepairAction?repairAction) { MoveAction = moveAction; BuildAction = buildAction; AttackAction = attackAction; RepairAction = repairAction; }
/// <summary> /// Checks both directions of a diagonal movement /// to see if movement or a bump resulting in an interaction is possible. Modifies /// the move action to switch to that direction, otherwise leaves it unmodified. /// Prioritizes the following when there are multiple options: /// 1. Move into empty space if either direction has it /// 2. Push an object if either direction has it /// 3. Open a door if either direction has it /// /// When both directions have the same condition (both doors or pushable objects), x will be preferred to y /// </summary> /// <param name="state">current state to try to slide from</param> /// <param name="action">current player action (which should have a diagonal movement). Will be modified if a slide is performed</param> /// <returns>bumptype of the final direction of movement if action is modified. Null otherwise</returns> private BumpType?TrySlide(PlayerState state, ref PlayerAction action) { Vector2Int direction = action.Direction(); if (Math.Abs(direction.x) + Math.Abs(direction.y) < 2) { //not diagonal, do nothing return(null); } Vector2Int xDirection = new Vector2Int(direction.x, 0); Vector2Int yDirection = new Vector2Int(0, direction.y); BumpType xBump = MatrixManager.GetBumpTypeAt(state.WorldPosition.RoundToInt(), xDirection, gameObject); BumpType yBump = MatrixManager.GetBumpTypeAt(state.WorldPosition.RoundToInt(), yDirection, gameObject); MoveAction?newAction = null; BumpType? newBump = null; if (xBump == BumpType.None) { newAction = PlayerAction.GetMoveAction(xDirection); newBump = xBump; } else if (yBump == BumpType.None) { newAction = PlayerAction.GetMoveAction(yDirection); newBump = yBump; } else if (xBump == BumpType.Push) { newAction = PlayerAction.GetMoveAction(xDirection); newBump = xBump; } else if (yBump == BumpType.Push) { newAction = PlayerAction.GetMoveAction(yDirection); newBump = yBump; } else if (xBump == BumpType.ClosedDoor) { newAction = PlayerAction.GetMoveAction(xDirection); newBump = xBump; } else if (yBump == BumpType.ClosedDoor) { newAction = PlayerAction.GetMoveAction(yDirection); newBump = yBump; } if (newAction.HasValue) { action.moveActions = new int[] { (int)newAction }; return(newBump); } else { return(null); } }
public IEnumerable <Status> FindPath() { Vector3 target = Entity.Position; if (Creature.AI.PositionConstraint.Contains(target) == ContainmentType.Disjoint) { target = MathFunctions.RandVector3Box(Creature.AI.PositionConstraint); } List <MoveAction> path = new List <MoveAction>(); VoxelHandle curr = Creature.Physics.CurrentVoxel; var storage = new MoveActionTempStorage(); for (int i = 0; i < PathLength; i++) { var actions = Creature.AI.Movement.GetMoveActions(new MoveState() { Voxel = curr }, new List <GameComponent>(), storage); MoveAction?bestAction = null; float bestDist = float.MinValue; foreach (MoveAction action in actions) { float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared(); if (dist > bestDist) { 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("FleePath", path); yield return(Status.Success); } else { yield return(Status.Fail); } }
private static EntityAction GetEntityAction(PlayerView playerView, Entity entity) { int myId = playerView.MyId; EntityProperties properties = playerView.EntityProperties[entity.EntityType]; MoveAction? moveAction = null; BuildAction? buildAction = null; if (properties.CanMove) { moveAction = new MoveAction( new Vec2Int(playerView.MapSize - 1, playerView.MapSize - 1), true, true); } else if (properties.Build != null) { EntityType entityType = properties.Build.Value.Options[0]; int currentUnits = 0; foreach (var otherEntity in playerView.Entities) { if (otherEntity.PlayerId != null && otherEntity.PlayerId == myId && otherEntity.EntityType == entityType) { currentUnits++; } } if ((currentUnits + 1) * playerView.EntityProperties[entityType].PopulationUse <= properties.PopulationProvide) { buildAction = new BuildAction( entityType, new Vec2Int(entity.Position.X + properties.Size, entity.Position.Y + properties.Size - 1)); } } EntityType[] validAutoAttackTargets; if (entity.EntityType == EntityType.BuilderUnit) { validAutoAttackTargets = new EntityType[] { EntityType.Resource }; } else { validAutoAttackTargets = new EntityType[0]; } EntityAction entityAction = new EntityAction( moveAction, buildAction, new AttackAction( null, new AutoAttack(properties.SightRange, validAutoAttackTargets)), null); return(entityAction); }
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(); if (dist < bestDist) { 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 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> 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> 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 Action GetAction(PlayerView playerView, DebugInterface debugInterface) { Action result = new Action(new System.Collections.Generic.Dictionary <int, Model.EntityAction>()); int myId = playerView.MyId; foreach (var entity in playerView.Entities) { if (entity.PlayerId != myId) { continue; } EntityProperties properties = playerView.EntityProperties[entity.EntityType]; MoveAction? moveAction = null; BuildAction? buildAction = null; if (properties.CanMove) { moveAction = new MoveAction( new Vec2Int(playerView.MapSize - 1, playerView.MapSize - 1), true, true ); } else if (properties.Build != null) { EntityType entityType = properties.Build.Value.Options[0]; int currentUnits = 0; foreach (var otherEntity in playerView.Entities) { if (otherEntity.PlayerId != null && otherEntity.PlayerId == myId && otherEntity.EntityType == entityType) { currentUnits++; } } if ((currentUnits + 1) * playerView.EntityProperties[entityType].PopulationUse <= properties.PopulationProvide) { buildAction = new BuildAction( entityType, new Vec2Int(entity.Position.X + properties.Size, entity.Position.Y + properties.Size - 1) ); } } EntityType[] validAutoAttackTargets; if (entity.EntityType == EntityType.BuilderUnit) { validAutoAttackTargets = new EntityType[] { EntityType.Resource }; } else { validAutoAttackTargets = new EntityType[0]; } result.EntityActions[entity.Id] = new EntityAction( moveAction, buildAction, new AttackAction( null, new AutoAttack(properties.SightRange, validAutoAttackTargets) ), null ); } return(result); }