/// <summary> /// Gets the 1-voxel shell of a bounding box. /// </summary> /// <param name="box">The box.</param> /// <returns>A list of points on the boundary of the box.</returns> private IEnumerable <GlobalVoxelCoordinate> EnumerateShell(BoundingBox box) { int minX = MathFunctions.FloorInt(box.Min.X + 0.5f); int minY = MathFunctions.FloorInt(box.Min.Y + 0.5f); int minZ = MathFunctions.FloorInt(box.Min.Z + 0.5f); int maxX = MathFunctions.FloorInt(box.Max.X - 0.5f); int maxY = MathFunctions.FloorInt(box.Max.Y - 0.5f); int maxZ = MathFunctions.FloorInt(box.Max.Z - 0.5f); for (var y = minY; y <= maxY; y++) { // yx planes for (var z = minZ; z <= maxZ; z++) { yield return(new GlobalVoxelCoordinate(minX, y, z)); yield return(new GlobalVoxelCoordinate(maxX, y, z)); } // yz planes for (var x = minX + 1; x < maxX; x++) { yield return(new GlobalVoxelCoordinate(x, y, minZ)); yield return(new GlobalVoxelCoordinate(x, y, maxZ)); } } }
public void GetItemsInBox <TObject>(BoundingBox box, HashSet <TObject> items) where TObject : T { Point3 minPoint = new Point3(MathFunctions.FloorInt(box.Min.X), MathFunctions.FloorInt(box.Min.Y), MathFunctions.FloorInt(box.Min.Z)); Point3 maxPoint = new Point3(MathFunctions.FloorInt(box.Max.X), MathFunctions.FloorInt(box.Max.Y), MathFunctions.FloorInt(box.Max.Z)); Point3 iter = new Point3(); for (iter.X = minPoint.X; iter.X <= maxPoint.X; iter.X++) { for (iter.Y = minPoint.Y; iter.Y <= maxPoint.Y; iter.Y++) { for (iter.Z = minPoint.Z; iter.Z <= maxPoint.Z; iter.Z++) { List <T> itemsInVoxel = GetItems(iter); if (itemsInVoxel == null) { continue; } foreach (TObject item in itemsInVoxel.OfType <TObject>()) { items.Add(item); } } } } }
public IEnumerable <GlobalVoxelCoordinate> Select(BoundingBox Bounds, Vector3 Start, Vector3 End, bool Invert) { int minX = MathFunctions.FloorInt(Bounds.Min.X + 0.5f); int minY = MathFunctions.FloorInt(Bounds.Min.Y + 0.5f); int minZ = MathFunctions.FloorInt(Bounds.Min.Z + 0.5f); int maxX = MathFunctions.FloorInt(Bounds.Max.X - 0.5f); int maxY = MathFunctions.FloorInt(Bounds.Max.Y - 0.5f); int maxZ = MathFunctions.FloorInt(Bounds.Max.Z - 0.5f); for (var y = minY; y <= maxY; y++) { // yx planes for (var z = minZ; z <= maxZ; z++) { yield return(new GlobalVoxelCoordinate(minX, y, z)); yield return(new GlobalVoxelCoordinate(maxX, y, z)); } // yz planes for (var x = minX + 1; x < maxX; x++) { yield return(new GlobalVoxelCoordinate(x, y, minZ)); yield return(new GlobalVoxelCoordinate(x, y, maxZ)); } } }
public Vector3 RoundToChunkCoords(Vector3 location) { int x = MathFunctions.FloorInt(location.X * InvCSX); int y = MathFunctions.FloorInt(location.Y * InvCSY); int z = MathFunctions.FloorInt(location.Z * InvCSZ); return(new Vector3(x, y, z)); }
/// <summary> /// Gets the 1-voxel shell of a bounding box. /// </summary> /// <param name="box">The box.</param> /// <returns>A list of points on the boundary of the box.</returns> private IEnumerable <Vector3> GetShell(BoundingBox box) { int minX = MathFunctions.FloorInt(box.Min.X + 0.5f); int minY = MathFunctions.FloorInt(box.Min.Y + 0.5f); int minZ = MathFunctions.FloorInt(box.Min.Z + 0.5f); int maxX = MathFunctions.FloorInt(box.Max.X - 0.5f); int maxY = MathFunctions.FloorInt(box.Max.Y - 0.5f); int maxZ = MathFunctions.FloorInt(box.Max.Z - 0.5f); for (int y = minY; y <= maxY; y++) { // yx planes for (int z = minZ; z <= maxZ; z++) { yield return(new Vector3(minX + 0.5f, y + 0.5f, z + 0.5f)); yield return(new Vector3(maxX + 0.5f, y + 0.5f, z + 0.5f)); } // yz planes for (int x = minX; x <= maxX; x++) { yield return(new Vector3(x + 0.5f, y + 0.5f, minZ + 0.5f)); yield return(new Vector3(x + 0.5f, y + 0.5f, maxZ + 0.5f)); } } /* * if (maxY - minY > 1) * { * for (int x = minX; x < maxX; x++) * { * // xz planes * for (int z = minZ; z < maxZ; z++) * { * yield return new Vector3(x + 0.5f, minY + 0.5f, z + 0.5f); * yield return new Vector3(x + 0.5f, maxY + 0.5f, z + 0.5f); * } * } * } */ }
public void RemoveObject(IBoundedObject bounded, BoundingBox oldLocation, CollisionType type) { if (type == CollisionType.None) { return; } Point3 minPoint = new Point3(MathFunctions.FloorInt(oldLocation.Min.X), MathFunctions.FloorInt(oldLocation.Min.Y), MathFunctions.FloorInt(oldLocation.Min.Z)); Point3 maxPoint = new Point3(MathFunctions.FloorInt(oldLocation.Max.X), MathFunctions.FloorInt(oldLocation.Max.Y), MathFunctions.FloorInt(oldLocation.Max.Z)); Point3 iter = new Point3(); for (iter.X = minPoint.X; iter.X <= maxPoint.X; iter.X++) { for (iter.Y = minPoint.Y; iter.Y <= maxPoint.Y; iter.Y++) { for (iter.Z = minPoint.Z; iter.Z <= maxPoint.Z; iter.Z++) { Hashes[type].RemoveItem(iter, bounded); } } } }
public void AddObject(IBoundedObject bounded, CollisionType type) { if (type == CollisionType.None) { return; } BoundingBox box = bounded.GetBoundingBox(); Point3 minPoint = new Point3(MathFunctions.FloorInt(box.Min.X), MathFunctions.FloorInt(box.Min.Y), MathFunctions.FloorInt(box.Min.Z)); Point3 maxPoint = new Point3(MathFunctions.FloorInt(box.Max.X), MathFunctions.FloorInt(box.Max.Y), MathFunctions.FloorInt(box.Max.Z)); Point3 iter = new Point3(); for (iter.X = minPoint.X; iter.X <= maxPoint.X; iter.X++) { for (iter.Y = minPoint.Y; iter.Y <= maxPoint.Y; iter.Y++) { for (iter.Z = minPoint.Z; iter.Z <= maxPoint.Z; iter.Z++) { Hashes[type].AddItem(iter, bounded); } } } }
/// <summary> /// Gets a stairstep stretching accross the box. /// </summary> /// <param name="box">The box.</param> /// <returns>A stairstep starting filled on the bottom row, pointing in the maximum x or z direction</returns> private IEnumerable <GlobalVoxelCoordinate> EnumerateStairVoxels(BoundingBox box, Vector3 start, Vector3 end, bool invert) { // Todo: Can this be simplified to return voxels above or below the line? int minX = MathFunctions.FloorInt(box.Min.X + 0.5f); int minY = MathFunctions.FloorInt(box.Min.Y + 0.5f); int minZ = MathFunctions.FloorInt(box.Min.Z + 0.5f); int maxX = MathFunctions.FloorInt(box.Max.X - 0.5f); int maxY = MathFunctions.FloorInt(box.Max.Y - 0.5f); int maxZ = MathFunctions.FloorInt(box.Max.Z - 0.5f); // If not inverted, selects the Xs // If inverted, selects the Os //max y ----xOOOO // --- xxOOO // --- xxxOO // --- xxxxO //min y --- xxxxx // minx --- maxx float dx = box.Max.X - box.Min.X; float dz = box.Max.Z - box.Min.Z; Vector3 dir = end - start; bool direction = dx > dz; bool positiveDir = direction ? dir.X < 0 : dir.Z < 0; int step = 0; // Always make staircases go exactly to the top or bottom of the selection. if (direction && invert) { minY = maxY - (maxX - minX); } else if (direction) { maxY = minY + (maxX - minX); } else if (invert) { minY = maxY - (maxZ - minZ); } else { maxY = minY + (maxZ - minZ); } int dy = maxY - minY; // Start from the bottom of the stairs up to the top. for (int y = minY; y <= maxY; y++) { int carve = invert ? MathFunctions.Clamp(dy - step, 0, dy) : step; // If stairs are in x direction if (direction) { if (positiveDir) { // Start from min x, and march up to maxY - y for (int x = minX; x <= MathFunctions.Clamp(maxX - carve, minX, maxX); x++) { for (int z = minZ; z <= maxZ; z++) { yield return(new GlobalVoxelCoordinate(x, y, z)); } } } else { // Start from min x, and march up to maxY - y for (int x = maxX; x >= MathFunctions.Clamp(minX + carve, minX, maxX); x--) { for (int z = minZ; z <= maxZ; z++) { yield return(new GlobalVoxelCoordinate(x, y, z)); } } } step++; } // Otherwise, they are in the z direction. else { if (positiveDir) { // Start from min z, and march up to maxY - y for (int z = minZ; z <= MathFunctions.Clamp(maxZ - carve, minZ, maxZ); z++) { for (int x = minX; x <= maxX; x++) { yield return(new GlobalVoxelCoordinate(x, y, z)); } } } else { // Start from min z, and march up to maxY - y for (int z = maxZ; z >= MathFunctions.Clamp(minZ + carve, minZ, maxZ); z--) { for (int x = minX; x <= maxX; x++) { yield return(new GlobalVoxelCoordinate(x, y, z)); } } } step++; } } }
public List <T> GetItems(Voxel voxel) { return(GetItems(new Point3(MathFunctions.FloorInt(voxel.Position.X), MathFunctions.FloorInt(voxel.Position.Y), MathFunctions.FloorInt(voxel.Position.Z)))); }
public List <IBoundedObject> GetObjectsAt(Voxel voxel, CollisionType queryType) { return(GetObjectsAt(new Point3(MathFunctions.FloorInt(voxel.Position.X), MathFunctions.FloorInt(voxel.Position.Y), MathFunctions.FloorInt(voxel.Position.Z)), queryType)); }
public List <Creature.MoveAction> GetMoveActions(Voxel voxel) { List <Creature.MoveAction> toReturn = new List <Creature.MoveAction>(); CollisionManager objectHash = PlayState.ComponentManager.CollisionManager; Voxel[,,] neighborHood = GetNeighborhood(voxel); int x = (int)voxel.GridPosition.X; int y = (int)voxel.GridPosition.Y; int z = (int)voxel.GridPosition.Z; bool inWater = (neighborHood[1, 1, 1] != null && neighborHood[1, 1, 1].WaterLevel > 5); bool standingOnGround = (neighborHood[1, 0, 1] != null && !neighborHood[1, 0, 1].IsEmpty); bool topCovered = (neighborHood[1, 2, 1] != null && !neighborHood[1, 2, 1].IsEmpty); bool hasNeighbors = HasNeighbors(neighborHood); List <Creature.MoveAction> successors = new List <Creature.MoveAction>(); //Climbing ladders List <IBoundedObject> bodiesInside = objectHash.Hashes[CollisionManager.CollisionType.Static].GetItems( new Point3(MathFunctions.FloorInt(voxel.Position.X), MathFunctions.FloorInt(voxel.Position.Y), MathFunctions.FloorInt(voxel.Position.Z))); if (bodiesInside != null) { bool hasLadder = bodiesInside.OfType <GameComponent>() .Any(component => component.Tags.Contains("Climbable")); if (hasLadder) { ; } { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 2, 1), MoveType = Creature.MoveType.Climb }); if (!standingOnGround) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 0, 1), MoveType = Creature.MoveType.Climb }); } standingOnGround = true; } } if (standingOnGround || inWater) { Creature.MoveType moveType = inWater ? Creature.MoveType.Swim : Creature.MoveType.Walk; if (IsEmpty(neighborHood[0, 1, 1])) { // +- x successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 1), MoveType = moveType }); } if (IsEmpty(neighborHood[2, 1, 1])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 1), MoveType = moveType }); } if (IsEmpty(neighborHood[1, 1, 0])) { // +- z successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 1, 0), MoveType = moveType }); } if (IsEmpty(neighborHood[1, 1, 2])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 1, 2), MoveType = moveType }); } if (!hasNeighbors) { if (IsEmpty(neighborHood[2, 1, 2])) { // +x + z successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 2), MoveType = moveType }); } if (IsEmpty(neighborHood[2, 1, 0])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 0), MoveType = moveType }); } if (IsEmpty(neighborHood[0, 1, 2])) { // -x -z successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 2), MoveType = moveType }); } if (IsEmpty(neighborHood[0, 1, 0])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 0), MoveType = moveType }); } } } if (!topCovered && (standingOnGround || inWater)) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { if (dx == 1 && dz == 1) { continue; } if (!IsEmpty(neighborHood[dx, 1, dz])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(dx, 2, dz), MoveType = Creature.MoveType.Jump }); } } } } // Falling if (!inWater && !standingOnGround) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 0, 1), MoveType = Creature.MoveType.Fall }); } foreach (Creature.MoveAction v in successors) { Voxel n = neighborHood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z]; if (n != null && (n.IsEmpty || n.WaterLevel > 0)) { Creature.MoveAction newAction = v; newAction.Voxel = n; toReturn.Add(newAction); } } return(toReturn); }
public Point3(Vector3 vect) { X = MathFunctions.FloorInt(vect.X); Y = MathFunctions.FloorInt(vect.Y); Z = MathFunctions.FloorInt(vect.Z); }
public Point3 GetChunkID(Vector3 origin) { origin = RoundToChunkCoords(origin); return(new Point3(MathFunctions.FloorInt(origin.X), MathFunctions.FloorInt(origin.Y), MathFunctions.FloorInt(origin.Z))); }
public List<Creature.MoveAction> GetMoveActions(Voxel voxel) { List<Creature.MoveAction> toReturn = new List<Creature.MoveAction>(); CollisionManager objectHash = PlayState.ComponentManager.CollisionManager; Voxel[,,] neighborHood = GetNeighborhood(voxel); int x = (int)voxel.GridPosition.X; int y = (int)voxel.GridPosition.Y; int z = (int)voxel.GridPosition.Z; bool inWater = (neighborHood[1, 1, 1] != null && neighborHood[1, 1, 1].WaterLevel > 5); bool standingOnGround = (neighborHood[1, 0, 1] != null && !neighborHood[1, 0, 1].IsEmpty); bool topCovered = (neighborHood[1, 2, 1] != null && !neighborHood[1, 2, 1].IsEmpty); bool hasNeighbors = HasNeighbors(neighborHood); List<Creature.MoveAction> successors = new List<Creature.MoveAction>(); //Climbing ladders IEnumerable<IBoundedObject> objectsInside = objectHash.Hashes[CollisionManager.CollisionType.Static].GetItems( new Point3(MathFunctions.FloorInt(voxel.Position.X), MathFunctions.FloorInt(voxel.Position.Y), MathFunctions.FloorInt(voxel.Position.Z))); bool blockedByObject = false; if (objectsInside != null) { var bodies = objectsInside.OfType<GameComponent>(); var enumerable = bodies as IList<GameComponent> ?? bodies.ToList(); // TODO: This is supposed to be done when the door is a NEIGHBOR of this voxel only!! foreach (GameComponent body in enumerable) { Door door = body.GetRootComponent().GetChildrenOfType<Door>(true).FirstOrDefault(); if (door != null) { if ( PlayState.Diplomacy.GetPolitics(door.TeamFaction, Creature.Faction).GetCurrentRelationship() == Relationship.Hateful) { if (IsEmpty(neighborHood[0, 1, 1])) // +- x successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 1), MoveType = Creature.MoveType.DestroyObject, InteractObject = door, Voxel = neighborHood[0, 1, 1] }); if (IsEmpty(neighborHood[2, 1, 1])) successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 1), MoveType = Creature.MoveType.DestroyObject, InteractObject = door, Voxel = neighborHood[2, 1, 1] }); if (IsEmpty(neighborHood[1, 1, 0])) // +- z successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 1, 0), MoveType = Creature.MoveType.DestroyObject, InteractObject = door, Voxel = neighborHood[1, 1, 0] }); if (IsEmpty(neighborHood[1, 1, 2])) successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 1, 2), MoveType = Creature.MoveType.DestroyObject, InteractObject = door, Voxel = neighborHood[1, 1, 2] }); blockedByObject = true; } } } if (blockedByObject) { return successors; } if (CanClimb) { bool hasLadder = enumerable.Any(component => component.Tags.Contains("Climbable")); if (hasLadder) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 2, 1), MoveType = Creature.MoveType.Climb }); if (!standingOnGround) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 0, 1), MoveType = Creature.MoveType.Climb }); } standingOnGround = true; } } } if (standingOnGround || (CanSwim && inWater)) { Creature.MoveType moveType = inWater ? Creature.MoveType.Swim : Creature.MoveType.Walk; if (IsEmpty(neighborHood[0, 1, 1])) // +- x successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 1), MoveType = moveType }); if (IsEmpty(neighborHood[2, 1, 1])) successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 1), MoveType = moveType }); if (IsEmpty(neighborHood[1, 1, 0])) // +- z successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 1, 0), MoveType = moveType }); if (IsEmpty(neighborHood[1, 1, 2])) successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 1, 2), MoveType = moveType }); if (!hasNeighbors) { if (IsEmpty(neighborHood[2, 1, 2])) // +x + z successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 2), MoveType = moveType }); if (IsEmpty(neighborHood[2, 1, 0])) successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 0), MoveType = moveType }); if (IsEmpty(neighborHood[0, 1, 2])) // -x -z successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 2), MoveType = moveType }); if (IsEmpty(neighborHood[0, 1, 0])) successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 0), MoveType = moveType }); } } if (!topCovered && (standingOnGround || (CanSwim && inWater))) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { if (dx == 1 && dz == 1) continue; if (!IsEmpty(neighborHood[dx, 1, dz])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(dx, 2, dz), MoveType = Creature.MoveType.Jump }); } } } } // Falling if (!inWater && !standingOnGround) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 0, 1), MoveType = Creature.MoveType.Fall }); } if (CanFly) { 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 (IsEmpty(neighborHood[dx, 1, dz])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(dx, dy, dz), MoveType = Creature.MoveType.Fly }); } } } } } foreach (Creature.MoveAction v in successors) { Voxel n = neighborHood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z]; if (n != null && (n.IsEmpty || n.WaterLevel > 0)) { Creature.MoveAction newAction = v; newAction.Voxel = n; toReturn.Add(newAction); } } return toReturn; }