public bool RayIntersectsWithCuboid(Cuboidf selectionBox, double posX, double posY, double posZ) { if (selectionBox == null) { return(false); } tmpCuboidd.Set(selectionBox).Translate(posX, posY, posZ); return(RayIntersectsWithCuboid(tmpCuboidd, ref hitOnBlockFace, ref hitPosition)); }
/// <summary> /// Sets the minimum and maximum values of the cuboid /// </summary> public Cuboidd Set(Cuboidf selectionBox) { this.X1 = selectionBox.X1; this.Y1 = selectionBox.Y1; this.Z1 = selectionBox.Z1; this.X2 = selectionBox.X2; this.Y2 = selectionBox.Y2; this.Z2 = selectionBox.Z2; return(this); }
/// <summary> /// Sets the cuboid to the selectionBox, translated by vec /// </summary> public Cuboidd SetAndTranslate(Cuboidf selectionBox, Vec3d vec) { this.X1 = selectionBox.X1 + vec.X; this.Y1 = selectionBox.Y1 + vec.Y; this.Z1 = selectionBox.Z1 + vec.Z; this.X2 = selectionBox.X2 + vec.X; this.Y2 = selectionBox.Y2 + vec.Y; this.Z2 = selectionBox.Z2 + vec.Z; return(this); }
/// <summary> /// Returns the shortest horizontal distance to any point between this and given cuboid /// </summary> public double ShortestHorizontalDistanceFrom(Cuboidf cuboid, BlockPos offset) { double cx = offset.X + cuboid.X1 - GameMath.Clamp(offset.X + cuboid.X1, X1, X2); double cz = offset.Z + cuboid.Z1 - GameMath.Clamp(offset.Z + cuboid.Z1, Z1, Z2); double dx = offset.X + cuboid.X2 - GameMath.Clamp(offset.X + cuboid.X2, X1, X2); double dz = offset.Z + cuboid.Z2 - GameMath.Clamp(offset.Z + cuboid.Z2, Z1, Z2); return(Math.Sqrt( Math.Min(cx * cx, dx * dx) + Math.Min(cz * cz, dz * dz) )); }
/// <summary> /// If the given cuboid intersects with this cuboid /// </summary> public bool IntersectsOrTouches(Cuboidf other, double offsetX, double offsetY, double offsetZ) { bool isOutSide = X2 <other.X1 + offsetX || X1> other.X2 + offsetX || Y2 <other.Y1 + offsetY || Y1> other.Y2 + offsetY || Z2 <other.Z1 + offsetZ || Z1> other.Z2 + offsetZ ; return(!isOutSide); }
/// <summary> /// If the given cuboid intersects with this cuboid /// </summary> public bool IntersectsOrTouches(Cuboidf other, Vec3d offset) { bool isOutSide = X2 <other.X1 + offset.X || X1> other.X2 + offset.X || Y2 <other.Y1 + offset.Y || Y1> other.Y2 + offset.Y || Z2 <other.Z1 + offset.Z || Z1> other.Z2 + offset.Z ; return(!isOutSide); }
public static bool AabbIntersect(Cuboidf aabb, double x, double y, double z, Cuboidf aabb2, Vec3d pos) { if (aabb2 == null) { return(true); } return (x + aabb.X1 < aabb2.X2 + pos.X && y + aabb.Y1 < aabb2.Y2 + pos.Y && z + aabb.Z1 < aabb2.Z2 + pos.Z && x + aabb.X2 > aabb2.X1 + pos.X && y + aabb.Y2 > aabb2.Y1 + pos.Y && z + aabb.Z2 > aabb2.Z1 + pos.Z ); }
/// <summary> /// If the given cuboid intersects with this cuboid /// </summary> public bool IntersectsOrTouches(Cuboidf other, Vec3d offset) { // For performance, this is a conditional statement with && conjunction: the conditional will fail early if any is false if (X2 >= other.X1 + offset.X && X1 <= other.X2 + offset.X && Z2 >= other.Z1 + offset.Z && Z1 <= other.Z2 + offset.Z && Y2 >= other.Y1 + offset.Y && Y1 <= Math.Round(other.Y2 + offset.Y, 5) // Fix float/double rounding errors. Only need to fix the vertical because gravity. Thankfully we don't have horizontal gravity. ) { return(true); } return(false); }
/// <summary> /// Tests given cuboidf collides with the terrain. By default also checks if the cuboid is merely touching the terrain, set alsoCheckTouch to disable that. /// </summary> /// <param name="blockAccessor"></param> /// <param name="entityBoxRel"></param> /// <param name="pos"></param> /// <param name="alsoCheckTouch"></param> /// <returns></returns> public Cuboidd GetCollidingCollisionBox(IBlockAccessor blockAccessor, Cuboidf entityBoxRel, Vec3d pos, bool alsoCheckTouch = true) { BlockPos blockPos = new BlockPos(); Vec3d blockPosVec = new Vec3d(); Cuboidd entityBox = entityBoxRel.ToDouble().Translate(pos); entityBox.Y1 = Math.Round(entityBox.Y1, 5); // Fix float/double rounding errors. Only need to fix the vertical because gravity. int minX = (int)(entityBoxRel.X1 + pos.X); int minY = (int)(entityBoxRel.Y1 + pos.Y - 1); // -1 for the extra high collision box of fences int minZ = (int)(entityBoxRel.Z1 + pos.Z); int maxX = (int)Math.Ceiling(entityBoxRel.X2 + pos.X); int maxY = (int)Math.Ceiling(entityBoxRel.Y2 + pos.Y); int maxZ = (int)Math.Ceiling(entityBoxRel.Z2 + pos.Z); for (int y = minY; y <= maxY; y++) { for (int x = minX; x <= maxX; x++) { for (int z = minZ; z <= maxZ; z++) { Block block = blockAccessor.GetBlock(x, y, z); blockPos.Set(x, y, z); blockPosVec.Set(x, y, z); Cuboidf[] collisionBoxes = block.GetCollisionBoxes(blockAccessor, blockPos); for (int i = 0; collisionBoxes != null && i < collisionBoxes.Length; i++) { Cuboidf collBox = collisionBoxes[i]; if (collBox == null) { continue; } bool colliding = alsoCheckTouch ? entityBox.IntersectsOrTouches(collBox, blockPosVec) : entityBox.Intersects(collBox, blockPosVec); if (colliding) { return(collBox.ToDouble().Translate(blockPos)); } } } } } return(null); }
public Block GetCollidingBlock(IBlockAccessor blockAccessor, Cuboidf entityBoxRel, Vec3d pos, bool alsoCheckTouch = true) { Cuboidd entityBox = tmpBox.SetAndTranslate(entityBoxRel, pos); int minX = (int)(entityBox.X1); int minY = (int)(entityBox.Y1) - 1; // -1 for the extra high collision box of fences int minZ = (int)(entityBox.Z1); int maxX = (int)(entityBox.X2); int maxY = (int)(entityBox.Y2); int maxZ = (int)(entityBox.Z2); for (int y = minY; y <= maxY; y++) { for (int x = minX; x <= maxX; x++) { for (int z = minZ; z <= maxZ; z++) { Block block = blockAccessor.GetBlock(x, y, z); blockPos.Set(x, y, z); Cuboidf[] collisionBoxes = block.GetCollisionBoxes(blockAccessor, blockPos); if (collisionBoxes == null || collisionBoxes.Length == 0) { continue; } blockPosVec.Set(x, y, z); for (int i = 0; i < collisionBoxes.Length; i++) { Cuboidf collBox = collisionBoxes[i]; if (collBox == null) { continue; } if (alsoCheckTouch ? entityBox.IntersectsOrTouches(collBox, blockPosVec) : entityBox.Intersects(collBox, blockPosVec)) { return(block); } } } } } return(null); }
/// <summary> /// Tests given cuboidf collides with the terrain. By default also checks if the cuboid is merely touching the terrain, set alsoCheckTouch to disable that. /// </summary> /// <param name="blockAccessor"></param> /// <param name="entityBoxRel"></param> /// <param name="pos"></param> /// <param name="alsoCheckTouch"></param> /// <returns></returns> public bool GetCollidingCollisionBox(IBlockAccessor blockAccessor, Cuboidf entityBoxRel, Vec3d pos, ref Cuboidd intoCubuid, bool alsoCheckTouch = true) { BlockPos blockPos = new BlockPos(); Vec3d blockPosVec = new Vec3d(); Cuboidd entityBox = entityBoxRel.ToDouble().Translate(pos); int minX = (int)(entityBoxRel.X1 + pos.X); int minY = (int)(entityBoxRel.Y1 + pos.Y - 1); // -1 for the extra high collision box of fences int minZ = (int)(entityBoxRel.Z1 + pos.Z); int maxX = (int)Math.Ceiling(entityBoxRel.X2 + pos.X); int maxY = (int)Math.Ceiling(entityBoxRel.Y2 + pos.Y); int maxZ = (int)Math.Ceiling(entityBoxRel.Z2 + pos.Z); for (int y = minY; y <= maxY; y++) { for (int x = minX; x <= maxX; x++) { for (int z = minZ; z <= maxZ; z++) { Block block = blockAccessor.GetBlock(x, y, z); blockPos.Set(x, y, z); blockPosVec.Set(x, y, z); Cuboidf[] collisionBoxes = block.GetCollisionBoxes(blockAccessor, blockPos); for (int i = 0; collisionBoxes != null && i < collisionBoxes.Length; i++) { Cuboidf collBox = collisionBoxes[i]; if (collBox == null) { continue; } bool colliding = alsoCheckTouch ? entityBox.IntersectsOrTouches(collBox, blockPosVec) : entityBox.Intersects(collBox, blockPosVec); if (colliding) { intoCubuid.Set(collBox).Translate(blockPos); return(true); } } } } } return(false); }
/// <summary> /// Returns the shortest distance to any point between this and given cuboid /// </summary> public double ShortestVerticalDistanceFrom(Cuboidf cuboid, EntityPos offset) { double oY1 = offset.Y + cuboid.Y1; double oY2 = offset.Y + cuboid.Y2; double cy = oY1 - GameMath.Clamp(oY1, Y1, Y2); // Test if inside if (oY1 <= Y1 && oY2 >= Y2) { cy = 0; } double dy = oY2 - GameMath.Clamp(oY2, Y1, Y2); return(Math.Min(cy, dy)); }
/// <summary> /// Returns the shortest distance to any point between this and given cuboid /// </summary> public double ShortestDistanceFrom(Cuboidf cuboid, BlockPos offset) { double oX1 = offset.X + cuboid.X1; double oY1 = offset.Y + cuboid.Y1; double oZ1 = offset.Z + cuboid.Z1; double oX2 = offset.X + cuboid.X2; double oY2 = offset.Y + cuboid.Y2; double oZ2 = offset.Z + cuboid.Z2; double cx = oX1 - GameMath.Clamp(oX1, X1, X2); double cy = oY1 - GameMath.Clamp(oY1, Y1, Y2); double cz = oZ1 - GameMath.Clamp(oZ1, Z1, Z2); // Test if inside if (oX1 <= X1 && oX2 >= X2) { cx = 0; } if (oY1 <= Y1 && oY2 >= Y2) { cy = 0; } if (oZ1 <= Z1 && oZ2 >= Z2) { cz = 0; } double dx = oX2 - GameMath.Clamp(oX2, X1, X2); double dy = oY2 - GameMath.Clamp(oY2, Y1, Y2); double dz = oZ2 - GameMath.Clamp(oZ2, Z1, Z2); return(Math.Sqrt( Math.Min(cx * cx, dx * dx) + Math.Min(cy * cy, dy * dy) + Math.Min(cz * cz, dz * dz) )); }
/// <summary> /// Tests given cuboidf collides with the terrain. By default also checks if the cuboid is merely touching the terrain, set alsoCheckTouch to disable that. /// </summary> /// <param name="blockAccessor"></param> /// <param name="entityBoxRel"></param> /// <param name="pos"></param> /// <param name="alsoCheckTouch"></param> /// <returns></returns> public bool IsColliding(IBlockAccessor blockAccessor, Cuboidf entityBoxRel, Vec3d pos, bool alsoCheckTouch = true) { return(GetCollidingBlock(blockAccessor, entityBoxRel, pos, alsoCheckTouch) != null); }
private BlockFacing(string code, byte flag, int index, int oppositeIndex, int horizontalAngleIndex, Vec3i facingVector, Vec3f planeCenter, EnumAxis axis, Cuboidf plane) { this.index = index; this.meshDataIndex = (byte)(index + 1); this.horizontalAngleIndex = horizontalAngleIndex; this.flag = flag; this.code = code; this.oppositeIndex = oppositeIndex; this.normali = facingVector; this.normalf = new Vec3f(facingVector.X, facingVector.Y, facingVector.Z); this.normald = new Vec3d((double)facingVector.X, (double)facingVector.Y, (double)facingVector.Z); this.plane = plane; normalPacked = NormalUtil.PackNormal(normalf.X, normalf.Y, normalf.Z); normalb = (byte)( (axis == EnumAxis.Z ? 1 : 0) << 0 | (facingVector.Z < 0 ? 1 : 0) << 1 | (axis == EnumAxis.Y ? 1 : 0) << 2 | (facingVector.Y < 0 ? 1 : 0) << 3 | (axis == EnumAxis.X ? 1 : 0) << 4 | (facingVector.X < 0 ? 1 : 0) << 5 ); normalPackedFlags = VertexFlags.PackNormal(normalf); this.planeCenter = planeCenter; this.axis = axis; }