After playing minecraft...

First, I thoroughly enjoyed the game. It’s amazing how something so simple on the surface can be so much fun :slight_smile:

But, in playing it, I found myself wondering about terrain engine of sorts he used. Does he just draw a 3 dimensional array of cubes, say around 1000x1000x128? Or do you think he uses some sort of raycasting to only draw the visible ones?

I find the idea of a terrain that isn’t just a heightmap to be neat, even a fairly “low resolution” on built up of cubes. Any thoughts how this could be implemented in Unity?

4 Likes

When using a parralel aligned cubes you only ever need to render 3 faces at a time. it is the 3 faces who’s Dot(player.forward, face.normal) < 0.

From what I hear he has an array of faces in the 6 cardinal directions, and then calls render on the 3 required faces for that frame at any particular frame. I’m unsure of anything more technical within to handle culling and stacked cubes, but I’ve heard the 3 face rule for at least the basic first pass culling.

is minecraft in any way optimized? It doesn’t run as fast as you’d expect… considering the graphics

4 Likes

The game also only draws cubes visible to the player. You can notice this clearly when you accidentally clip the camera through a block; it looks like a huge void behind it, with only caves being rendered in the distance below. So I guess one thing he does is to only render blocks that are directly adjacent to air or water, where the player has the potential to see it. This test is probably done in a single pass for initial terrain generation, and then incrementally for blocks around a block that experiences a state change.

Does that help?

Yes, it sure does. I think your guess about only rendering blocks that are directly adjacent to air or water is a HUGE tip to me. And it makes perfect sense…I only wish I’d though to of that myself :slight_smile:
+1 to Awesomeness for you there

Now…about storage…think it’s just a huge 3 dimensional array of blocks?

I thought I recalled hearing it’s a huge array of references to block types. So each type of block is numbered or indexed, and then it only stores the texture and block parameters once in the static index list. Although I’m unsure of how that works for Blocks like Water. An array of shorts is much smaller than an array of block structs.

I really want to play minecraft - buuuut - from what I’ve heard about it, it would kill any productivity I have with my current project :slight_smile:

1 Like

its interesting how he gets the file that small cause technically a 1024x1024 block file eats 1mb per layer, even if its only using 1 byte per block
but the inf format should be documented on its wiki I think

As I saw in a video the landscape is practically infinite, isn’t it? I guess the map around the player is generated in realtime and only changed blocks / chunks are applied and stored. This concept works over network too.

I haven’t seen the file format, but with run-length-encoding (like you do with characters in a text file) alone I think you can compress it down a whole lot. The distribution of block types is not noisy, instead you get blocks of the same type clustering together because of the procedural algorithms. Just consider the earth block, there’s huge continuous stretches of that type everywhere. In your fileformat you do something like: “from here, repeat the earth block 34 times”. One byte for the block type, another for the amount of repeats. :slight_smile:

For water I think he probably stores the level of water in a block next to the block type. It seems to act pretty discreet, with water per block only having 8 or 16 different levels of height. I would guess flow direction and such do not have to be stored, they can be logically derived from the current state of the waterblocks.

1 Like

I lub this game… so much time wasted.

AFAIK the map goes 128 blocks down.

the amount of torches you need for that haha …
already digging around at 20 below ground means you have cut down a forest and ripped appart a whole store of coal :wink:

I played around with it a bit in unity, and the way I did it was 10x10x10 chunks of blocks, rendering only the faces exposed to empty space. Random, stable noise let the terrain go infinitely in all directions (including down). Performance was pretty good for a 4-5 chunk view distance (so 1,000,000+ possible cubes in memory, but only a fraction of those actually adding polygons to the world). I was using a single byte to store the block type, but you could still reduce that significantly. Regardless, with that view distance and storage size, it’s still only 1mb of data for a decent size area. If you stored the random seed, the actual data file could be pretty minimal - just save the cubes that have changed and use the noise algorithm to determine the others.

2 Likes

I’ve tried something like this in Unity too.
NOTE: SophieH was so kind to give me her voxel script, that made this happen!

I modified her script to only use byte arrays and added some other changes. But my world can only be 2048x2048x128 right now, if it goes bigger, you would get an memory exception error so this is something i want to work on.

I’ve got the idea to only store chunks (16x16x16 blocks in a group) that got changed, instead of saving each block into that array. But it got too slow finding the right chunk among millions in one frame. So i dunno how to solve this to create a much bigger world. I would welcome any suggestion.

So what the script does is to render only faces if it is on the surface. It groups every 16x16x16 block into one chunk to save drawcalls as well and i use a big atlas map for the textures (the texture i use is from Doku’s RPG Texture package for minecraft).

You can try an older version. I have a newer one with much better controls, only one cube to place/destroy, and better block detection. But i haven’t uploaded it cause im still working on increasing the world, somehow.

Unity Minecraft

NOTE: It will be laggy at the beginning to generate the level, later on i will do that in a loading screen. So when you try placing cubes at the beginning, it takes a few seconds to display them, cause ive limited my current version so it can only update < 10 chunks at a time.

The physic and collision is crappy too, just added something simple so i can play around with it.

Controls:

  • WASD: Movement
  • Left click: Place current block type
  • Right click: remove block
  • R: toggle between blocks (no visual indicator yet)
  • F: Create a big sphere of the current block type
  • B: Bomb away some blocks (this is fun 8D)

The red transparent cube shows the field you would remove.
The blue transparent cube shows the field where you place a new block.

@Kiyaku
Quite a lot of fun to play around with! I start to understand the MineCraft addiction, note to myself: stay away from minecraft.

Kiyaku,
I wasn’t sure what visual range Minecraft uses…but I put a sphere at one corner of your map, and back up to the middle of the map. I felt like that was a good view distance…so maybe minecraft uses something more along the lines of 1024x1024x128, instead? Not sure, I guess I could hop on and try to estimate it.

I then measured how many blocks I could cross in Minecraft, in 5 seconds…roughtly 25. I then found a flat piece of terrain (or as close as I could, without digging one out) and picked a tree that was JUST on the edge of visibility. I then measured how much time it took to reach that tree.
It took right about 45 seconds. So 45/5 = 9, 9*25 = 225.
So, this means the the viewing distance is roughly 225 blocks forward. This is so small, I’m thinking about double checking my timing or something.
But, if this is the case, I could easily go ahead and say…maybe it is really 28 blocks for every 5 seconds of walking, easily giving you the nice round number of 255.
Meaning that the total drawing distance around the player is 512x512x128.

That’s a LOT smaller than 2048x2048x128 :slight_smile: 33mb instead of 536mb!!
I’m assuming one byte per block.

(I ran a second test, and got a forward distance of 336…but that was a bad test, I had some hilly terrain. I’m just too lazy to dig a straight path right now. But even then, that would put a map of 672x672x128.)

As far as chunks, I think that is definitely a great idea.
I noticed that when new terrain moves into view, it appears in chunks. All i had to do was find a tree that was on the edge of visibility, then move forward until the next “chunk” came into view with another landmark that was on the edge of visibility, and measure the blocks between them.
Roughly 16…so I’m going to say that as the player moves forward, new terrain is added in 16x16x16 chunks. So with 33mb of blocks to draw in total (33, 554, 432) divided into chunks of 16x16x16…that comes to only having to manage 8192 chunks of blocks in memory.

So your chunk array definition would be something like
byte[,] chunk = new byte[16,16,16]; (4096 blocks or bytes)

your “world” or display array definition would be
Chunk[,] world = new Chunk[32,32,8];

A bit more manageable, I think.
Entire chunks could be marked as drawable or not, simply based on whether or not they only contain air or have no blocks adjacent to air or water (not possible to be seen). This would be a huge time saver. It would a simple thing to calculate this whenever a new chunk becomes visible.

I’m still working on how lighting is calculated for the blocks.

So, I have some questions for you:
You mentioned only drawing faces if the face was on the surface…meaning its next to an empty block, I assume. If this is so, what is a “Cube”? Is it just a prefab with 6 planes that you can hide or show?

After looking at your screenshot, it appears that you generate a cube for each visible square on the map, possibly only drawing certain sides which are visible, but still using a cube collider.

Ok, a little more and I’m done…for now :slight_smile:
Some thoughts on the types of blocks:
That array of bytes, for storing blocks…can hold 256 values. That’s a LOT of different block types. From looking at the wiki, Minecraft has about 64. That leaves a LOT more room in that byte for extra data.
Let’s say the remaining 64 values are for future block types. Great, that leaves half the byte for other things, like the precalculated lighting for each block.
So values 0-127 determine block type.
You could use the rest to determine the lighting amounts for the 6 block sides.

I’m not saying this is the best approach…but it might be a good way to save memory. Personally, I don’t care for this approach unless I have to, as it is somewhat inflexible for new ideas or such. Other the other hand, having 33 million “Block” classes instead of bytes, each with its own storage baggage (bloat if you will), could be pretty rough.

Maybe what is best is a hybrid approach…empty blocks get 1 byte of storage…the block type. Visible blocks get the full gamut.

1 Like

Well the viewing distant might be that long. But then what, how do you generate the next blocks when you keep on walking, moving the fields in that array? But then where do you store the changed tiles so you can save them?

I actually tried the saving-the-chunks approach before. Instead of saving “blocks”, i saved each chunk and i gave the chunk a script that hold the 4096 byte array to store its own blocks. So with this approach i can create worlds that are so much bigger.

But the problem i encountered is speed. When you change a block in the world, you first have to check what chunk it belongs to. So the only thing that came into my mind, is going through every created chunk and see if the block belongs to that chunk. But this process takes too long, you will feel “lags” if you created too many chunks.

Also loading a new chunk, and this will answer your next question about “what is a block?”, is lagging when the field is too big.
A “block” is just a virtual position in my array. I don’t create cubes, i only create the faces. And when i create a chunk, i check i there would be a block above, left, behind, right, infront or under me. If yes, dont render my faces on this position. So i only render faces that are visible.
This is really fast using the big byte array to store the block types.

But when you use the chunk system, i would have to call the “check what chunk has this block” function 16x16x16x6 times for each chunk when recreating the chunk (block got added or removed). 16x16x16 is the number of blocks in that chunk, and then 6 times for each direction. So you would loop 24576 times the “check what chunk has this block” function to create a chunk. This causes a 1-2 second lag (hope i did the math right, its 4am right now lol).

So this is where my current problem is, trying to create a system that is fast enough to create a huge number of chunks + blocks, and to find a way how to create a “infinite” world like in minecraft. I think the “only save whats changed” approach is the way to go. But dunno how yet.

But yes i’ve also changed the block type to a byte array cause i wont need more than 256 different blocks so this is enough lol. However i planned a second array for different purposes like “time”, so you can change blocks over time (regrowing, changing skin, etc). You can store that in the same byte array, depending on how many objects you want to create in your world.

For collision detection i just create a 3x3 grid out of invisible box colliders around the player, and the boxes will only activate its collider if the fields around me are visible (blocktype != 0). Works pretty good so far.

I found some more info here, on the level format:
http://www.minecraftwiki.net/wiki/Alpha_Level_Format
His “chunks” of blocks are 16x16x128.
I like how he stores the chunks of data into a breakdown of folders, based on the chunk coordinates. This allows for quick and easy access of the data, no matter where in the world you are loading the chunk from.

This answers a big question I had…how do you quickly and effeciently
save and load data for a chunk of data, which might not necessarily be part of a square map, without having to search through the file or load the whole level?

As far as knowing which chunk a block belongs to…could you just have each block have a reference to its chunk? That way, when you collide or remove a block, you know which chunk it is a part of by looking at its reference to the chunk. Adding a block is simply replacing an existing block of air with some other material.

Seems like you could do that. It also might be a good idea to have an index of the block within the chunk. I guess it depends on how much it increases memory storage.

Some thoughts about how to add/remove chunks, as you move around the map.
You could do a linked list type thing, where each chunk has a reference to the chunks to the north/south/east/west of it.

Or, you could just have an array of chunks for your world (32x32) which would give you a 512x512x128 block world.
The array [0…31, 0…31) would reference the chunk at those chunk coordinates.
If the player moves ‘east’ and you need to “shift” the world west…you could easily load in the east border of chunks from disk (or create them, whatever), shift the array to the left one chunk, and set the eastmost column to the new east chunks. Code could be able to shift these pretty quick…a 32x32 array is nothing. And you are only updating the references.

I’m throwing together a quick code spike to declare the chunk, block, and world classes, and see what effect different options have on memory usage.
If you wanted, each chunk could have a column/row value which is updated.

This is just all in my head. there are probably optimizations that could be made, shortcuts, and so forth.

If anyone wants a codebase to play around with, here’s mine. Also a webplayer to just mess around with it. Feel free to use it in a free project… on the off chance that you become the next notch, please throw a small chunk of that cash at me. :wink:

Web Player

Sometimes you start in a deep hole if the random terrain just happened to dig one under the starting point.

You have to click on the screen to capture the mouse, but it’ll respond to all your movements regardless. I just used very slightly modified player scripts from the default stuff. You can left-click to dig, but I never got around to right-click-to-add (it would technically be pretty simple). Camera and all that is default, so it doesn’t show from the right height and blocks look bigger than they otherwise would. Code is messy, mostly uncommented, and I take no responsibility for any inappropriate remarks you may come across. It was just for fun. Infinite world in all directions, I’ve broken the loader a couple times but it usually works just fine. Lighting isn’t enabled, fog hides the chunks popping in. Have fun!

Unity Package Download