/// <summary> /// Performs a raycast with the current terrain data. /// Raycasts are performed very simple, this function will move along your ray by adding direction*stepWidth every step. /// In every step it will check if it hit a block and if true it will stop and return the data. /// /// TODO: Implement a better way (more precise!) for raycasting /// </summary> /// <returns><c>true</c>, if the raycast hit a block, <c>false</c> otherwise.</returns> /// <param name="worldspaceStartpoint">Worldspace startpoint.</param> /// <param name="direction">Direction.</param> /// <param name="stepWidth">The step width you want to use for raycasting. the lower this is the more precise the result and slower the calculation will be.</param> /// <param name="length">The length of the ray.</param> /// <param name="hitInfo">The raycast hit info.</param> /// <param name="calculateHitFace">hitFace will only get set if this is true.</param> public static bool TerrainRaycast(Vector3 worldspaceStartpoint, Vector3 direction, float stepWidth, float length, out CubicRaycastHitInfo hitInfo, bool calculateHitFace) { // Initialize bool blockHit = false; float distanceTraveled = 0; Vector3 currentPos = worldspaceStartpoint; hitInfo = new CubicRaycastHitInfo(); Vector3 blockPos = Vector3.zero; CubicTerrain terrain = CubicTerrain.GetInstance(); // Search for blocks on the ray while (!blockHit && distanceTraveled < length) { // Calculate current step data currentPos += direction * stepWidth; distanceTraveled += stepWidth; blockPos = terrain.GetBlockPosition(currentPos); // Check if there is a block at this position if (terrain.HasBlock(blockPos)) { blockHit = true; hitInfo.blockHit = blockPos; hitInfo.hitPoint = currentPos; if (calculateHitFace) { // Get hit face /*LEFT = 0, * RIGHT = 1, * TOP = 2, * BOTTOM = 3, * FRONT = 4, * BACK = 5*/ // Back and forward flipped Vector3[] faceNormals = new Vector3[] { Vector3.left, Vector3.right, Vector3.up, Vector3.down, Vector3.forward, Vector3.back }; // Get block center position Vector3 blockCenterPosition = blockPos + new Vector3(0.5f, 0.5f, 0.5f); // Get shortest distance face. float shortestDistance = stepWidth + 10; int shortestFace = -1; for (int i = 0; i < faceNormals.Length; i++) { // Get distance from hit point to the current normal + blockcenter Vector3 blockNormalPosition = blockCenterPosition + faceNormals[i]; float distance = Vector3.Distance(currentPos, blockNormalPosition); if (shortestDistance > distance) { shortestDistance = distance; shortestFace = i; } } // Get face hitInfo.faceHit = (BlockFace)shortestFace; } } } return(blockHit); }
public void FixedUpdate() { CubicTerrain terrainInstance = CubicTerrain.GetInstance(); // Initialize Vector3 currentPosition = this.transform.position; Vector3 newPosition = this.transform.position; // Add gravity to current velocity this.velocity += this.gravity * Time.deltaTime; // Move based on velocity newPosition += this.velocity * Time.deltaTime; Vector3 realNewPosition = newPosition; Vector3 blockSpaceNewPosition = terrainInstance.GetBlockPosition(newPosition); bool newPositionValid = true; blockSpaceNewPosition.y -= (float)this.characterHeight / 2.0f; newPosition.y = blockSpaceNewPosition.y; // New position valid? for (int i = 0; i < this.characterHeight && newPositionValid; i++) { if (terrainInstance.HasBlock(blockSpaceNewPosition)) { newPositionValid = false; } // Check left, right, front and back Vector3[] checkPositions = new Vector3[] { Vector3.left * 0.5f, Vector3.right * 0.5f, Vector3.forward * 0.5f, Vector3.back * 0.5f }; // Check all directions foreach (Vector3 checkPosition in checkPositions) { Vector3 checkPos = checkPosition + newPosition; if (terrainInstance.HasBlock(terrainInstance.GetBlockPosition(checkPos))) { newPositionValid = false; } } blockSpaceNewPosition.y++; newPosition.y = blockSpaceNewPosition.y; } if (newPositionValid) { this.transform.position = realNewPosition; this.velocity -= this.velocity / 2; } else { this.velocity = Vector3.zero; } }