private static Vector3?GetNearestGridIntersectionPoint(Ray ray, Vector3 gridMinCoord, float gridWidth, float gridHeight, float gridBreadth) { List <CollisionFace> faces = new List <CollisionFace>(); //Bottom faces.Add(new CollisionFace(gridMinCoord, gridMinCoord + new Vector3(gridWidth, 0, 0), gridMinCoord + new Vector3(gridWidth, 0, gridBreadth), gridMinCoord + new Vector3(0, 0, gridBreadth), new Vector3(0, 1, 0))); //Top faces.Add(new CollisionFace(gridMinCoord + new Vector3(0, gridHeight, 0), gridMinCoord + new Vector3(gridWidth, gridHeight, 0), gridMinCoord + new Vector3(gridWidth, gridHeight, gridBreadth), gridMinCoord + new Vector3(0, gridHeight, gridBreadth), new Vector3(0, 1, 0))); faces.Add(new CollisionFace(gridMinCoord, gridMinCoord + new Vector3(gridWidth, 0, 0), gridMinCoord + new Vector3(gridWidth, gridHeight, 0), gridMinCoord + new Vector3(0, gridHeight, 0), new Vector3(0, 0, 0))); faces.Add(new CollisionFace(gridMinCoord, gridMinCoord + new Vector3(0, 0, gridBreadth), gridMinCoord + new Vector3(0, gridHeight, gridBreadth), gridMinCoord + new Vector3(0, gridHeight, 0), new Vector3(0, 0, 0))); faces.Add(new CollisionFace(gridMinCoord + new Vector3(gridWidth, 0, 0), gridMinCoord + new Vector3(gridWidth, 0, gridBreadth), gridMinCoord + new Vector3(gridWidth, gridHeight, gridBreadth), gridMinCoord + new Vector3(gridWidth, gridHeight, 0), new Vector3(0, 1, 0))); faces.Add(new CollisionFace(gridMinCoord + new Vector3(0, 0, gridBreadth), gridMinCoord + new Vector3(gridWidth, 0, gridBreadth), gridMinCoord + new Vector3(gridWidth, gridHeight, gridBreadth), gridMinCoord + new Vector3(0, gridHeight, gridBreadth), new Vector3(0, 1, 0))); CollisionFace nearestFace = GetNearestCollisionFace(faces, ray); Vector3?nearestPoint = null; if (nearestFace != null) { nearestPoint = nearestFace.GetRayFaceIntersectionPoint(ray); } return(nearestPoint); }
/// <summary> /// Gets the nearest world object bounded by the voxel box centred at the input coordinates /// </summary> /// <param name="globalCoordinates"></param> /// <returns></returns> public AbstractWorldObject GetNearestWorldObjectAt(Vector3 globalCoordinates, Ray ray) { AbstractWorldObject result = null; AbstractBlock block = GetBlockAt(globalCoordinates); float?nearestDist = float.MaxValue; if (block != null) { CollisionFace face = VoxelRaycastUtility.GetNearestCollisionFace(block.GetCollisionFaces(), ray); if (face != null) { nearestDist = face.Intersects(ray); result = block; } } List <Wall> wallsInBlock = new List <Wall>(); Vector3 blockLowerLeft = globalCoordinates + new Vector3(-0.5f, -0.5f, -0.5f); Vector3 blockUpperLeft = globalCoordinates + new Vector3(0.5f, -0.5f, -0.5f); Vector3 blockLowerRight = globalCoordinates + new Vector3(-0.5f, -0.5f, 0.5f); Vector3 blockUpperRight = globalCoordinates + new Vector3(0.5f, -0.5f, 0.5f); //Get walls wallsInBlock.Add(GetWallAt(blockLowerLeft, blockUpperLeft)); wallsInBlock.Add(GetWallAt(blockLowerLeft, blockLowerRight)); wallsInBlock.Add(GetWallAt(blockLowerLeft, blockUpperRight)); wallsInBlock.Add(GetWallAt(blockUpperLeft, blockLowerRight)); foreach (Wall w in wallsInBlock) { if (w != null) { //Check if ray crosses wall and get nearest point CollisionFace face = VoxelRaycastUtility.GetNearestCollisionFace(w.GetCollisionFaces(), ray); if (face != null) { float?dist = face.Intersects(ray); if (dist != null && nearestDist != null && ((float)dist) < ((float)nearestDist)) { nearestDist = dist; result = w; } } } } return(result); }
public static Vector3?GetNearestWallAnchor(CollisionFace face, Ray ray) { Vector3?result = null; Vector3?pointOnFace = face.GetRayFaceIntersectionPoint((Ray)ray); if (pointOnFace != null) { Vector3 point = (Vector3)pointOnFace; //Get nearest wall anchor (i.e val.5) float xDecimal; float yDecimal; float zDecimal; if (point.X >= 0) { xDecimal = (int)point.X + 0.5f; } else { xDecimal = (int)point.X - 0.5f; } if (point.Y >= 0) { yDecimal = (int)point.Y + 0.5f; } else { yDecimal = (int)point.Y - 0.5f; } if (point.Z >= 0) { zDecimal = (int)point.Z + 0.5f; } else { zDecimal = (int)point.Z - 0.5f; } result = new Vector3(xDecimal, yDecimal, zDecimal); } return(result); }
public static bool AddBlock(Ray selectionRay, AbstractBlock selectedBlock) { bool result = false; Direction nearestFaceDirection = Direction.NULL; CollisionFace face = VoxelRaycastUtility.GetNearestCollisionFace(selectedBlock.GetCollisionFaces(), selectionRay); if (face is BlockCollisionFace) { nearestFaceDirection = (face as BlockCollisionFace).Facing; } if (nearestFaceDirection != Direction.NULL) { result = selectedBlock.OnAddBlock(nearestFaceDirection, new DirtBlock(BlockShape.Cube, Direction.North)); } return(result); }
public static CollisionFace GetNearestCollisionFace(List <CollisionFace> faces, Ray ray) { float nearestBlockFaceDist = float.MaxValue; CollisionFace nearestFace = null; foreach (CollisionFace face in faces) { if (ray != null) { float?dist = face.Intersects((Ray)ray); //((Ray)mouseRay).Intersects(face.Value.Plane); if (dist != null && ((float)dist) < nearestBlockFaceDist) { nearestBlockFaceDist = (float)dist; nearestFace = face; } } } return(nearestFace); }
/// <summary> /// Detects and resolves all collisions between the player and his neighboring /// tiles. When a collision is detected, the player is pushed away along one /// axis to prevent overlapping. There is some special logic for the Y axis to /// handle platforms which behave differently depending on direction of movement. /// </summary> private void HandleCollisions(List <Sprite> level) { Rectangle bounds = BoundingBox(); //Reset flag to search for ground collision. isOnGround = false; foreach (CollisionSurface tile in level) { // If this tile is collidable, if (this.BoundingBox().Intersects(tile.BoundingBox())) { Rectangle tileBounds = tile.BoundingBox(); CurrentCollisionSurface = tile; //Sets the colour to a dark blue when you are colliding with the surface if (tile.Colour != Color.Transparent) { tile.Colour = Color.DarkBlue; } if (tile.CollisionType != TileCollision.Slope && tile.CollisionType != TileCollision.Slide) { // Determine collision depth (with direction) and magnitude. Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds); if (depth != Vector2.Zero) { float absDepthX = Math.Abs(depth.X); float absDepthY = Math.Abs(depth.Y); //Resolve the collision along the shallow axis. if (absDepthY < absDepthX || tile.CollisionType == TileCollision.Platform) { //If we crossed the top of a tile, we are on the ground. if (previousBottom <= tileBounds.Top) { isOnGround = true; isJumping = false; isGliding = false; //BEGIN BOUNCE if (tile.CollisionType == TileCollision.Bounce) { CollisionBounce bounceTile = (CollisionBounce)tile; isBouncing = true; BounceLaunchVelocityX = bounceTile.BounceVelocityX; BounceLaunchVelocityY = bounceTile.BounceVelocityY; } //SLIDE PLAYER if (tile.CollisionType == TileCollision.Conveyor) { if (movement != 0) { SlideDirection = movement; } CollisionConveyor conveyorTile = (CollisionConveyor)tile; SlideMoveFactor = conveyorTile.SlideBoost; } } //Ignore platforms, unless we are on the ground. if (IsOnGround) { // Resolve the collision along the Y axis. Position = new Vector2(Position.X, Position.Y + depth.Y); Rotation = 0.0f; if (tile.CollisionType == TileCollision.Conveyor) { isSliding = true; } if (tile.CollisionType == TileCollision.Moving) { CollisionMoving movingTile = (CollisionMoving)tile; if (!movingTile.IsAtWaypoint) { if (movingTile.PlatformSpeed.Y > 0) { Position.X += movingTile.PlatformSpeed.X; } else { Position += movingTile.PlatformSpeed; } } } //Perform further collisions with the new bounds. bounds = BoundingBox(); } } else if (tile.CollisionType != TileCollision.Platform) { // Resolve the collision along the X axis Position = new Vector2(Position.X + depth.X, Position.Y); if (tile.CollisionType == TileCollision.Walljump) { IsOnWall = true; if (tile.Position.X < Position.X) { CollisionOnFace = CollisionFace.Left; } else { CollisionOnFace = CollisionFace.Right; } } //Perform further collisions with the new bounds. bounds = BoundingBox(); } } } else if (tile.CollisionType == TileCollision.Slope || tile.CollisionType == TileCollision.Slide) { CollisionSlope slopeTile = (CollisionSlope)tile; float displacement = RectangleExtensions.GetSlopePosition(bounds, tileBounds, slopeTile.BottomSlopePoint); //If we crossed the top of a tile, we are on the ground. if (previousBottom > displacement - this.BoundingBox().Height / 2) { isOnGround = true; isJumping = false; isGliding = false; if (tile.CollisionType == TileCollision.Slide) { CollisionSlide slideTile = (CollisionSlide)tile; SlideDirection = slideTile.SlideDirection; SlideMoveFactor = slideTile.SlideBoost; } } //Ignore platforms, unless we are on the ground. if ((IsOnGround & !wantsToJump) | (IsOnGround & isJumping) | (IsOnGround & isGliding)) { // Resolve the collision along the Y axis. Position = new Vector2(Position.X, displacement - this.BoundingBox().Height / 2); Rotation = RectangleExtensions.GetSlopeAngle(tileBounds, slopeTile.BottomSlopePoint) / 2; if (tile.CollisionType == TileCollision.Slide) { isSliding = true; } //Perform further collisions with the new bounds. bounds = BoundingBox(); } } } } //Save the new bounds bottom. previousBottom = bounds.Bottom; }