/// <summary> /// Initializes a new instance of the <see cref="CubicPathfinding"/> class. /// </summary> /// <param name="terrain">Terrain.</param> private CubicPathfinding(CubicTerrain terrain) { this.terrain = terrain; this.workerThread = new Thread(this.WorkerThread); this.workerThread.Start(); this.pathQueue = new Queue <CubicPath> (); }
/// <summary> /// Initializes a new instance of the <see cref="CubicPathfinding"/> class. /// </summary> /// <param name="terrain">Terrain.</param> private CubicPathfinding(CubicTerrain terrain) { this.terrain = terrain; this.workerThread = new Thread (this.WorkerThread); this.workerThread.Start (); this.pathQueue = new Queue<CubicPath> (); }
public static CubicPathfinding GetInstance() { if (instance == null) { instance = new CubicPathfinding(CubicTerrain.GetInstance()); } return(instance); }
public void Update() { // Right mouse button. if (Input.GetMouseButtonDown(1)) { // The unity physics way if (CubicTerrain.GetInstance().useMeshColliders) { // Get ready to perform the raycast. RaycastHit hitInfo = new RaycastHit(); Ray cameraRay = this.playerCamera.GetComponent <Camera>().ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2)); Debug.DrawRay(cameraRay.origin, cameraRay.direction, Color.red, 100.0f); // Perform the raycast if (Physics.Raycast(cameraRay, out hitInfo, 50, this.detectionMask.value)) { if (hitInfo.collider == null) { return; } // get collider parent Transform chunkTransform = hitInfo.collider.transform.parent; if (chunkTransform != null) { // Chunk hit? CubicTerrainChunk chunk = chunkTransform.GetComponent <CubicTerrainChunk>(); if (chunk != null && !chunk.isDirty) { // Yes, chunk hit! // Delete the clicked block Vector3 block = chunk.GetBlockPosition(hitInfo, -0.5f); chunk.chunkData.SetVoxel((int)block.x, (int)block.y, (int)block.z, -1); } } } } else { // Cubic World Physics way CubicRaycastHitInfo hitInfo = new CubicRaycastHitInfo(); if (CubicPhysics.TerrainRaycastUnprecise(this.playerCamera.GetComponent <Camera>().ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2)), 5.0f, out hitInfo)) { // Debug.Log ("Hit: " + hitInfo.hitPoint + ", Block: " + hitInfo.blockHit + ", Face: " + hitInfo.faceHit); // Hit block CubicTerrain.GetInstance().SetBlock((int)hitInfo.blockHit.x, (int)hitInfo.blockHit.y, (int)hitInfo.blockHit.z, -1); } } } }
/// <summary> /// Gets the chunk data. /// </summary> /// <returns>The chunk data.</returns> /// <param name="x">The x coordinate.</param> /// <param name="z">The z coordinate.</param> /// <param name="width">Width.</param> /// <param name="height">Height.</param> /// <param name="depth">Depth.</param> /// <param name="chunkOwner">The owner of the chunk you intend to load</param> public CubicTerrainData GetChunkData(CubicTerrain chunkOwner, int x, int y, int z, int width, int height, int depth) { BufferedStream chunkDataStream = new BufferedStream(File.Open(this.chunkDataFile, FileMode.Open)); CubicTerrainData terrainData = new CubicTerrainData(chunkOwner, width, height, depth); // Get chunk starting position chunkDataStream.Position = this.chunkLookupTable [new ListIndex <int>(x, y, z)]; terrainData.DeserializeChunk(chunkDataStream); chunkDataStream.Close(); return(terrainData); }
/// <summary> /// Gets the chunk data. /// </summary> /// <returns>The chunk data.</returns> /// <param name="x">The x coordinate.</param> /// <param name="z">The z coordinate.</param> /// <param name="width">Width.</param> /// <param name="height">Height.</param> /// <param name="depth">Depth.</param> /// <param name="chunkOwner">The owner of the chunk you intend to load</param> public CubicTerrainData GetChunkData(CubicTerrain chunkOwner, int x, int y, int z, int width, int height, int depth) { BufferedStream chunkDataStream = new BufferedStream (File.Open (this.chunkDataFile, FileMode.Open)); CubicTerrainData terrainData = new CubicTerrainData (chunkOwner, width, height, depth); // Get chunk starting position chunkDataStream.Position = this.chunkLookupTable [new ListIndex<int>(x,y,z)]; terrainData.DeserializeChunk (chunkDataStream); chunkDataStream.Close (); return terrainData; }
/// <summary> /// Initializes the chunk file, chunk generation thread and initializes all needed variables. /// </summary> public void Start() { // Make sure we are at 0|0|0 this.transform.position = new Vector3(0, 0, 0); // Singleton if (instance != null) { Debug.LogError("Multiple CubicTerrain Script GameObject detected! Error! Disabling this instance."); this.enabled = false; return; } instance = this; // Terrain stream? if (this.serializeTerrain) { this.terrainFile = new CubicTerrainFile(this.chunkFilesPath + "table.clt", this.chunkFilesPath + "data.cfd"); } // Initialize lists this.chunkObjects = new List3D <GameObject> (); this.chunkData = new List3D <CubicTerrainData> (); this.generationJobs = new List3D <ChunkGenerationJob> (); this.terrainGenerator = this.GetComponent <ATerrainGenerator> (); this.chunkGenerationThread = new Thread(this.ChunkGenerationThread); this.chunkGenerationThread.Start(); // Init this.terrainMaterial.SetTexture("_MainTex", Blocks.textureAtlas); this.transparentTerrainMaterial.SetTexture("_MainTex", Blocks.textureAtlas); if (!this.loadPlayerChunkFirst) { return; } Vector3 chunkPosition = this.GetChunkPosition(this.playerTransform.position); this.GenerateChunk((int)chunkPosition.x, (int)chunkPosition.z); this.transformPosition = this.transform.position; }
/// <summary> /// Initializes a new instance of the <see cref="CubicTerrainData"/> class. /// </summary> /// <param name="width">Width.</param> /// <param name="height">Height.</param> /// <param name="depth">Depth.</param> public CubicTerrainData(CubicTerrain owner, int width, int height, int depth) { // Set owner reference this.owner = owner; // Save dimensions this._width = width; this._height = height; this._depth = depth; // Initialize voxel data array this._voxelData = new VoxelData[width][][]; for (int i = 0; i < width; i++) { this._voxelData[i] = new VoxelData[height][]; for (int j = 0; j < height; j++) { this._voxelData[i][j] = new VoxelData[depth]; } } }
/// <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 Update() { // Right mouse button. if (Input.GetMouseButtonDown(0)) { // Unity physics if (CubicTerrain.GetInstance().useMeshColliders) { // Get ready to perform the raycast. RaycastHit hitInfo = new RaycastHit(); Ray cameraRay = this.playerCamera.GetComponent <Camera>().ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2)); Debug.DrawRay(cameraRay.origin, cameraRay.direction, Color.red, 100.0f); // Perform the raycast if (Physics.Raycast(cameraRay, out hitInfo, 5, this.detectionMask.value)) { if (hitInfo.collider == null) { return; } // get collider parent Transform chunkTransform = hitInfo.collider.transform.parent; if (chunkTransform != null) { // Chunk hit? CubicTerrainChunk chunk = chunkTransform.GetComponent <CubicTerrainChunk>(); if (chunk != null && !chunk.isDirty) { // Yes, chunk hit! BlockHitInfo blockHitInfo = chunk.GetBlockHitInfo(hitInfo); int x = (int)blockHitInfo.hitBlock.x; int y = (int)blockHitInfo.hitBlock.y; int z = (int)blockHitInfo.hitBlock.z; // Which face was hit? calculate target position for the new block switch (blockHitInfo.hitFace) { case BlockFace.LEFT: x -= 1; break; case BlockFace.RIGHT: x += 1; break; case BlockFace.TOP: y += 1; break; case BlockFace.BOTTOM: y -= 1; break; case BlockFace.FRONT: z += 1; break; case BlockFace.BACK: z -= 1; break; } Vector3 chunkPos = chunk.chunkPosition; // Get chunk we want to place the block on if (x < 0) { chunkPos.x -= 1; x = chunk.master.chunkWidth - 1; } if (x >= chunk.master.chunkWidth) { chunkPos.x += 1; x = 0; } if (y < 0) { chunkPos.y -= 1; y = chunk.master.chunkDepth - 1; } if (z >= chunk.master.chunkHeight) { chunkPos.y += 1; y = 0; } if (z < 0) { chunkPos.z -= 1; z = chunk.master.chunkDepth - 1; } if (z >= chunk.master.chunkDepth) { chunkPos.z += 1; z = 0; } // Finally place the object GameObject chunkObject = chunk.master.GetChunkObject((int)chunkPos.x, (int)chunkPos.y, (int)chunkPos.z); chunkObject.GetComponent <CubicTerrainChunk>().chunkData.SetVoxel(x, y, z, (short)this.blockId); } } } } else { // Cubic physics CubicRaycastHitInfo hitInfo = new CubicRaycastHitInfo(); if (CubicPhysics.TerrainRaycastPrecise(this.playerCamera.GetComponent <Camera>().ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2)), 5.0f, out hitInfo)) { Debug.Log("Hit: " + hitInfo.hitPoint + ", Block: " + hitInfo.blockHit + ", Face: " + hitInfo.faceHit); // Get block to place position int x = (int)hitInfo.blockHit.x; int y = (int)hitInfo.blockHit.y; int z = (int)hitInfo.blockHit.z; // Which face was hit? calculate target position for the new block switch (hitInfo.faceHit) { case BlockFace.LEFT: x -= 1; break; case BlockFace.RIGHT: x += 1; break; case BlockFace.TOP: y += 1; break; case BlockFace.BOTTOM: y -= 1; break; case BlockFace.FRONT: z += 1; break; case BlockFace.BACK: z -= 1; break; } CubicTerrain.GetInstance().SetBlock(x, y, z, (short)this.blockId); } } } }
/// <summary> /// Initializes the chunk file, chunk generation thread and initializes all needed variables. /// </summary> public void Start() { // Make sure we are at 0|0|0 this.transform.position = new Vector3 (0, 0, 0); // Singleton if (instance != null) { Debug.LogError ("Multiple CubicTerrain Script GameObject detected! Error! Disabling this instance."); this.enabled = false; return; } instance = this; // Terrain stream? if (this.serializeTerrain) this.terrainFile = new CubicTerrainFile(this.chunkFilesPath+"table.clt", this.chunkFilesPath+"data.cfd"); // Initialize lists this.chunkObjects = new List3D<GameObject> (); this.chunkData = new List3D<CubicTerrainData> (); this.generationJobs = new List3D<ChunkGenerationJob> (); this.terrainGenerator = this.GetComponent<ATerrainGenerator> (); this.chunkGenerationThread = new Thread (this.ChunkGenerationThread); this.chunkGenerationThread.Start (); // Init this.terrainMaterial.SetTexture ("_MainTex", Blocks.textureAtlas); this.transparentTerrainMaterial.SetTexture ("_MainTex", Blocks.textureAtlas); if (!this.loadPlayerChunkFirst) return; Vector3 chunkPosition = this.GetChunkPosition(this.playerTransform.position); this.GenerateChunk((int)chunkPosition.x,(int)chunkPosition.z); this.transformPosition = this.transform.position; }
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; } }
public void Update() { bool firstPoint = Input.GetKeyDown(KeyCode.P); bool lastPoint = Input.GetKeyDown(KeyCode.L); bool definePoint = firstPoint || lastPoint; if (this.path != null) { if (this.path.isReady) { Debug.Log("Path found in " + path.runtime + " milliseconds!"); foreach (Vector3 blockPos in this.path.pathData) { CubicTerrain.GetInstance().SetBlock((int)blockPos.x, (int)blockPos.y - 1, (int)blockPos.z, -1); } this.path = null; } else if (!this.path.foundPath) { Debug.Log("Path not found :-( after search for " + path.runtime + " milliseconds!"); } } // Right mouse button. if (definePoint) { if (CubicTerrain.GetInstance().useMeshColliders) { // Get ready to perform the raycast. RaycastHit hitInfo = new RaycastHit(); Ray cameraRay = this.playerCamera.GetComponent <Camera>().ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2)); Debug.DrawRay(cameraRay.origin, cameraRay.direction, Color.red, 100.0f); // Perform the raycast if (Physics.Raycast(cameraRay, out hitInfo, 5, this.detectionMask.value)) { if (hitInfo.collider == null) { return; } // get collider parent Transform chunkTransform = hitInfo.collider.transform.parent; if (chunkTransform != null) { // Chunk hit? CubicTerrainChunk chunk = chunkTransform.GetComponent <CubicTerrainChunk>(); if (chunk != null && !chunk.isDirty) { // Yes, chunk hit! BlockHitInfo blockHitInfo = chunk.GetBlockHitInfo(hitInfo); int x = (int)blockHitInfo.hitBlock.x; int y = (int)blockHitInfo.hitBlock.y; int z = (int)blockHitInfo.hitBlock.z; // Which face was hit? calculate target position for the new block switch (blockHitInfo.hitFace) { case BlockFace.LEFT: x -= 1; break; case BlockFace.RIGHT: x += 1; break; case BlockFace.TOP: y += 1; break; case BlockFace.BOTTOM: y -= 1; break; case BlockFace.FRONT: z += 1; break; case BlockFace.BACK: z -= 1; break; } Vector3 chunkPos = chunk.chunkPosition; // Get chunk we want to place the block on if (x < 0) { chunkPos.x -= 1; x = chunk.master.chunkWidth - 1; } if (x >= chunk.master.chunkWidth) { chunkPos.x += 1; x = 0; } if (z < 0) { chunkPos.z -= 1; z = chunk.master.chunkDepth - 1; } if (z >= chunk.master.chunkDepth) { chunkPos.z += 1; z = 0; } // Finally place the object GameObject chunkObject = chunk.master.GetChunkObject((int)chunkPos.x, (int)chunkPos.y, (int)chunkPos.z); chunk = chunkObject.GetComponent <CubicTerrainChunk>(); // Get absolute position Vector3 absoluteVoxelspace = chunk.GetAbsolutePosition(new Vector3(x, y, z)); Debug.Log("Point: " + absoluteVoxelspace); if (firstPoint) { startPoint = absoluteVoxelspace; } else if (lastPoint) { goalPoint = absoluteVoxelspace; } } } } } else { // Cubic World Physics way CubicRaycastHitInfo hitInfo = new CubicRaycastHitInfo(); if (CubicPhysics.TerrainRaycastUnprecise(this.playerCamera.GetComponent <Camera>().ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2)), 5.0f, out hitInfo)) { // Debug.Log ("Hit: " + hitInfo.hitPoint + ", Block: " + hitInfo.blockHit + ", Face: " + hitInfo.faceHit); // Hit block Vector3 topBlock = hitInfo.blockHit + Vector3.up; Debug.Log("Top Block: " + topBlock); if (firstPoint) { startPoint = topBlock; } else if (lastPoint) { goalPoint = topBlock; } } } } if (startPoint != Vector3.zero && goalPoint != Vector3.zero) { Debug.Log("Starting A* path finding. Distance: " + Vector3.Distance(startPoint, goalPoint)); // Start pathfinding CubicPathfinding pathfinder = CubicPathfinding.GetInstance(); this.path = pathfinder.GetPath(startPoint, goalPoint, true); startPoint = Vector3.zero; goalPoint = Vector3.zero; } }