public Chunk(Game1 game, Vector3 offset, Block[] blocks) { _game = game; _offset = offset; _boundingBox = new BoundingBox( new Vector3(_offset.X * WIDTH, _offset.Y * HEIGHT, _offset.Z * DEPTH), new Vector3((_offset.X + 1) * WIDTH, (_offset.Y + 1) * HEIGHT, (_offset.Z + 1) * DEPTH)); _solidVertexList = new List<VertexPositionNormalTexture>(); _solidIndexList = new List<int>(); _solidIndicesDict = new Dictionary<int,List<int>>(); _solidBlocksOffsetsList = new List<int>(); _liquidVertexList = new List<VertexPositionNormalTexture>(); _liquidIndexList = new List<int>(); _liquidIndicesDict = new Dictionary<int, List<int>>(); _liquidBlocksOffsetsList = new List<int>(); _blocks = blocks; _blockAccessor = new BlockAccessor(_game.Map); _effect = new BasicEffect(_game.GraphicsDevice); }
private int BuildVertices(Block block, float x, float y, float z) { if (block.Type == BlockType.None) return 0; x += 0.5f; y += 0.5f; z += 0.5f; bool isLiquid = BlockHelper.IsLiquid(block); float scaleX = 0.5f, scaleY = 0.5f, scaleZ = 0.5f; var faces = new List<VertexPositionNormalTexture[]>(); // Front if (DrawFace(block, _blockAccessor.MoveTo((int)x, (int)y, (int)z).Backward.Block)) { var face = new VertexPositionNormalTexture[4]; face[0].Position = new Vector3(1 * scaleX + x, 1 * scaleY + y, -1 * scaleZ + z); face[1].Position = new Vector3(1 * scaleX + x, -1 * scaleY + y, -1 * scaleZ + z); face[2].Position = new Vector3(-1 * scaleX + x, -1 * scaleY + y, -1 * scaleZ + z); face[3].Position = new Vector3(-1 * scaleX + x, 1 * scaleY + y, -1 * scaleZ + z); faces.Add(face); } //Back if (DrawFace(block, _blockAccessor.MoveTo((int)x, (int)y, (int)z).Forward.Block)) { var face = new VertexPositionNormalTexture[4]; face[0].Position = new Vector3(1 * scaleX + x, 1 * scaleY + y, 1 * scaleZ + z); face[1].Position = new Vector3(-1 * scaleX + x, 1 * scaleY + y, 1 * scaleZ + z); face[2].Position = new Vector3(-1 * scaleX + x, -1 * scaleY + y, 1 * scaleZ + z); face[3].Position = new Vector3(1 * scaleX + x, -1 * scaleY + y, 1 * scaleZ + z); faces.Add(face); } //Right if (DrawFace(block, _blockAccessor.MoveTo((int)x, (int)y, (int)z).Right.Block)) { var face = new VertexPositionNormalTexture[4]; face[0].Position = new Vector3(1 * scaleX + x, 1 * scaleY + y, -1 * scaleZ + z); face[1].Position = new Vector3(1 * scaleX + x, 1 * scaleY + y, 1 * scaleZ + z); face[2].Position = new Vector3(1 * scaleX + x, -1 * scaleY + y, 1 * scaleZ + z); face[3].Position = new Vector3(1 * scaleX + x, -1 * scaleY + y, -1 * scaleZ + z); faces.Add(face); } //Bottom if (DrawFace(block, _blockAccessor.MoveTo((int)x, (int)y, (int)z).Down.Block)) { var face = new VertexPositionNormalTexture[4]; face[0].Position = new Vector3(1 * scaleX + x, -1 * scaleY + y, -1 * scaleZ + z); face[1].Position = new Vector3(1 * scaleX + x, -1 * scaleY + y, 1 * scaleZ + z); face[2].Position = new Vector3(-1 * scaleX + x, -1 * scaleY + y, 1 * scaleZ + z); face[3].Position = new Vector3(-1 * scaleX + x, -1 * scaleY + y, -1 * scaleZ + z); faces.Add(face); } //Left if (DrawFace(block, _blockAccessor.MoveTo((int)x, (int)y, (int)z).Left.Block)) { var face = new VertexPositionNormalTexture[4]; face[0].Position = new Vector3(-1 * scaleX + x, -1 * scaleY + y, -1 * scaleZ + z); face[1].Position = new Vector3(-1 * scaleX + x, -1 * scaleY + y, 1 * scaleZ + z); face[2].Position = new Vector3(-1 * scaleX + x, 1 * scaleY + y, 1 * scaleZ + z); face[3].Position = new Vector3(-1 * scaleX + x, 1 * scaleY + y, -1 * scaleZ + z); faces.Add(face); } //Top if (DrawFace(block, _blockAccessor.MoveTo((int)x, (int)y, (int)z).Up.Block)) { var face = new VertexPositionNormalTexture[4]; face[0].Position = new Vector3(1 * scaleX + x, 1 * scaleY + y, 1 * scaleZ + z); face[1].Position = new Vector3(1 * scaleX + x, 1 * scaleY + y, -1 * scaleZ + z); face[2].Position = new Vector3(-1 * scaleX + x, 1 * scaleY + y, -1 * scaleZ + z); face[3].Position = new Vector3(-1 * scaleX + x, 1 * scaleY + y, 1 * scaleZ + z); faces.Add(face); } if (faces.Count > 0) { for (var i = 0; i < faces.Count; i++) { var face = faces.ElementAt(i); float[] uv = BlockHelper.GetUVMapping(block); float left = uv[0] + 0.1f; float right = uv[0] + uv[2] * 0.90f; float top = uv[1] + 0.1f; float bottom = uv[1] + uv[3] * 0.90f; face[0].TextureCoordinate = new Vector2(right, top); face[1].TextureCoordinate = new Vector2(right, bottom); face[2].TextureCoordinate = new Vector2(left, bottom); face[3].TextureCoordinate = new Vector2(left, top); } var indices = new int[faces.Count * 6]; int j = 0; for (int i = 0; i < faces.Count; i++) { var offset = i * 4; indices[j++] = 0 + offset; indices[j++] = 3 + offset; indices[j++] = 2 + offset; indices[j++] = 0 + offset; indices[j++] = 2 + offset; indices[j++] = 1 + offset; } for (int i = 0; i < indices.Length / 3; i++) { var face = faces.ElementAt((int)(float)i / 2); // i = 0 => face[3] - face[0], face[0] - face[2] // i = 1 => face[2] - face[0], face[0] - face[1] Vector3 firstvec = face[indices[i * 3 + 1] % 4].Position - face[indices[i * 3] % 4].Position; Vector3 secondvec = face[indices[i * 3] % 4].Position - face[indices[i * 3 + 2] % 4].Position; Vector3 normal = Vector3.Cross(firstvec, secondvec); normal.Normalize(); face[indices[i * 3] % 4].Normal += normal; face[indices[i * 3 + 1] % 4].Normal += normal; face[indices[i * 3 + 2] % 4].Normal += normal; face[indices[i * 3] % 4].Normal.Normalize(); face[indices[i * 3 + 1] % 4].Normal.Normalize(); face[indices[i * 3 + 2] % 4].Normal.Normalize(); } var currentVertexOffset = isLiquid ? _liquidVertexList.Count : _solidVertexList.Count; var indicesDict = isLiquid ? _liquidIndicesDict : _solidIndicesDict; var vertexList = isLiquid ? _liquidVertexList : _solidVertexList; var indexList = isLiquid ? _liquidIndexList : _solidIndexList; var blocksOffsetsList = isLiquid ? _liquidBlocksOffsetsList : _solidBlocksOffsetsList; foreach (var face in faces) foreach (var vertex in face) vertexList.Add(vertex); var blockOffset = GetBlockOffset((int)x, (int)y, (int)z); indicesDict.Add(blockOffset, new List<int>()); blocksOffsetsList.Add(blockOffset); foreach (var index in indices) { indexList.Add(index + currentVertexOffset); indicesDict[blockOffset].Add(index + currentVertexOffset); } } return faces.Count * 4; }
private bool DrawFace(Block block1, Block block2) { if (BlockHelper.IsTransparent(block1) && BlockHelper.IsSolid(block2)) return true; if (BlockHelper.IsSolid(block1) && BlockHelper.IsTransparent(block2)) return true; else if (BlockHelper.IsSolid(block1) && BlockHelper.IsSolid(block2)) return false; else if (BlockHelper.IsTransparent(block1) && BlockHelper.IsTransparent(block2) && !BlockHelper.IsNone(block1) && !BlockHelper.IsNone(block2)) return false; else return true; }
private Chunk Generate3DNoiseChunk(Vector3 chunkOffset) { int noiseWidth = Map.NUM_CHUNKS_WIDTH * Chunk.WIDTH; int noiseDepth = Map.NUM_CHUNKS_DEPTH * Chunk.DEPTH; int noiseHeight = Map.NUM_CHUNKS_HEIGHT * Chunk.HEIGHT; Block[] blocks = new Block[Chunk.WIDTH * Chunk.HEIGHT * Chunk.DEPTH]; for (int x = 0; x < Chunk.WIDTH; x++) for (int z = 0; z < Chunk.DEPTH; z++) { int offset = x * Chunk.DEPTH * Chunk.HEIGHT + z * Chunk.HEIGHT; for (int y = 0; y < Chunk.HEIGHT; y++) { int mapX = (int)chunkOffset.X * Chunk.WIDTH + x; int mapY = (int)chunkOffset.Y * Chunk.HEIGHT + y; int mapZ = (int)chunkOffset.Z * Chunk.DEPTH + z; float octave1 = (SimplexNoise.noise(2.0f * mapX * 1 / noiseWidth, 2.0f * mapY * 1 / noiseHeight, 2.0f * mapZ * 1 / noiseDepth) + 1) / 2 * 0.7f; float octave2 = (SimplexNoise.noise(4.0f * mapX * 1 / noiseWidth, 4.0f * mapY * 1 / noiseHeight, 4.0f * mapZ * 1 / noiseDepth) + 1) / 2 * 0.2f; float octave3 = (SimplexNoise.noise(8.0f * mapX * 1 / noiseWidth, 8.0f * mapY * 1 / noiseHeight, 8.0f * mapZ * 1 / noiseDepth) + 1) / 2 * 0.1f; float rnd = octave1 + octave2 + octave3; if (rnd < 0.5) blocks[offset + y] = new Block(BlockType.Rock); else if(y < Map.WATER_HEIGHT * NUM_CHUNKS_HEIGHT * Chunk.HEIGHT) blocks[offset + y] = new Block(BlockType.Water); else blocks[offset + y] = new Block(BlockType.None); } } return new Chunk(_game, chunkOffset, blocks); }
public void SetBlockAt(int mapX, int mapY, int mapZ, Block block) { var offset = GetBlockOffset(mapX, mapY, mapZ); var oldBlock = _blocks[offset]; _blocks[offset] = block; if (BlockHelper.IsNone(oldBlock) && !BlockHelper.IsNone(block)) { // Replace none block with plain block => We must create new block vertices and destroy neighbours ones } else if (!BlockHelper.IsNone(oldBlock) && BlockHelper.IsNone(block)) { // Replace plain block with none block => We must destroy vertices and build neighbours ones NumVertices -= DestroyBlockVertices(mapX, mapY, mapZ); var directions = _blockAccessor.AllDirections; foreach (var dir in directions) { if (!_blockAccessor.MoveTo(mapX, mapY, mapZ).MoveTo(dir).IsNone) NumVertices += RebuildBlockVertices(_blockAccessor.X, _blockAccessor.Y, _blockAccessor.Z); } } else if(block.Type != oldBlock.Type) { // Block type changed, need redraw } UpdateBuffers(); }
public BlockAccessor(Map map) { _map = map; _outOfMapBlock = new Block(BlockType.None); }
private Chunk Generate2DNoiseChunk(Vector3 chunkOffset) { PerlinNoise perlinNoise = new PerlinNoise(_game.Map.Seed); int noiseWidth = Map.NUM_CHUNKS_WIDTH * Chunk.WIDTH; int noiseDepth = Map.NUM_CHUNKS_DEPTH * Chunk.DEPTH; int mapHeight = Map.NUM_CHUNKS_HEIGHT * Chunk.HEIGHT; Block[] blocks = new Block[Chunk.WIDTH * Chunk.HEIGHT * Chunk.DEPTH]; for (int x = 0; x < Chunk.WIDTH; x++) for (int z = 0; z < Chunk.DEPTH; z++) { int offset = x * Chunk.DEPTH * Chunk.HEIGHT + z * Chunk.HEIGHT; int mapX = (int)chunkOffset.X * Chunk.WIDTH + x; int mapY = (int)chunkOffset.Y * Chunk.HEIGHT; int mapZ = (int)chunkOffset.Z * Chunk.DEPTH + z; float octave1 = (perlinNoise.Noise(2.0f * mapX * 1 / noiseWidth, 2.0f * mapZ * 1 / noiseDepth) + 1) / 2 * 0.7f; float octave2 = (perlinNoise.Noise(4.0f * mapX * 1 / noiseWidth, 4.0f * mapZ * 1 / noiseDepth) + 1) / 2 * 0.2f; float octave3 = (perlinNoise.Noise(8.0f * mapX * 1 / noiseWidth, 8.0f * mapZ * 1 / noiseDepth) + 1) / 2 * 0.1f; float rnd = octave1 + octave2 + octave3; int grassHeight = (int)Math.Floor(rnd * mapHeight) - mapY; int dirtHeight = grassHeight - 4; int curY = 0; for (; curY < (dirtHeight) && curY < Chunk.HEIGHT; curY++) blocks[offset + curY] = new Block(BlockType.Rock); for (; curY < grassHeight && curY < Chunk.HEIGHT; curY++) blocks[offset + curY] = new Block(BlockType.Dirt); if (curY == grassHeight && curY < Chunk.HEIGHT) { blocks[offset + curY] = new Block(BlockType.Grass); curY++; } for (; curY < Map.WATER_HEIGHT * NUM_CHUNKS_HEIGHT * Chunk.HEIGHT; curY++) { blocks[offset + curY] = new Block(BlockType.Water); } for (; curY < Chunk.HEIGHT; curY++) { blocks[offset + curY] = new Block(BlockType.None); } } return new Chunk(_game, chunkOffset, blocks); }
public static bool IsSolid(Block block) { return !IsNone(block) && !IsLiquid(block); }
public static bool IsTransparent(Block block) { return IsNone(block) || IsLiquid(block); }
public static bool IsSelectable(Block block) { return block.Type != BlockType.None; }
public static bool IsNone(Block block) { return block.Type == BlockType.None; }
public static bool IsLiquid(Block block) { return block.Type == BlockType.Water; }
public static float[] GetUVMapping(Block block) { int numTexturesPerRow = 2; int numTexturesPerCol = 2; float width = 1.0f / numTexturesPerRow; float height = 1.0f / numTexturesPerCol; float x = ((float)(((int)block.Type - 1) % numTexturesPerRow)) / numTexturesPerRow; float y = ((float)(int)(((int)block.Type - 1) / numTexturesPerRow)) / numTexturesPerCol; return new float[] { x, y, width, height }; }
public void ReplaceWithBlock(Block block) { var chunk = _map.GetChunkAt(X, Y, Z); chunk.SetBlockAt(X, Y, Z, block); }