Friday, May 06, 2011

Screenshots + Video

Nothing besides that really.. just some screenshots and a video :]


Tuesday, May 03, 2011

More Optimization and Mod Support

I know I was supposed to move onto the next version, but I just wasn't happy so I went back to the drawing board.

Long story short, cubes used to be ~16-26 bytes each (depending on how many faces are visible.  Then (thanks to the help, again, of the guys at SA and reddit) I realized that I don't even need to store the cube position.  Everytime I reference a cube I'm going through some kind of dictionary that has the position stored as a key.  I pulled that Vector3 out.

Next on my list of attack was the type.  I don't have more than 256 texture types (and if I do eventually, it's easy to change it) so I switched that from an Int16 to a byte.

Next was the visible faces.  That's normally in a List<Int16>.  I was able to fit all the data into a byte.  I did that by splitting up the byte into 3 parts:  the first digit, the second and the third.  If the first digit is 1, the front is visible.  If it's 2, the back is visible.  If it's 0, neither are visible.  If the second digit is 1, the top is visible.  2, bottom.  0, neither.  3, both top and bottom.  The last digit is a special case.  If it's 1, the left side is visible.  2, right side.  0, neither side.  If the third digit is > 5, we subtract 5 from the value to get the official size and set the first digit to 3 (both front and back are visible).  The reason I did it this way is since I wanted to fit it all into a byte, the value couldn't be more than 255.  That means the first digit has to always be 2 or less.  The third digit can be any value since the highest the first and second digits can be is 2 and 3 respectively, so I used that as the key.  Sounds complicated, but here are some examples:

1:  front face visible
2:  bottom face visible
3:  both left and right faces are visible

2:  back face visible
0:  neither top nor bottom are visible
1:  left face visible

Due to the 5 in the third digit, we subract 5 from it and the value changes to what would be 300.
3:  both front and back faces visible.
0:  neither top nor bottom visible
0:  neither right nor left are visible

I hope those examples fully explain it.  Thanks to these changes, each cube now takes 2 bytes total.  Coming from 16-26, that's a huge memory saver.

I'm going to keep working on some performance mods but while I'm doing that, I'm also thinking of .02a.  After I am happy with this optimization stuff, I'm going to start adding plants and creatures.  I was thinking about how I want to do creatures when I realized something.  I'm going to be spending lots of time creating different plant types and creatures to put into the game.  If there's one thing I've learned from Minecraft, it's that the community can come up with things a lot faster than a single dev team can.  Based off that, I've decided that instead of writing plants/animals into the game, I'm going to write an API to add plants and animals.  Once I have that API, I'll create a base set of creatures that I'll bundle with the game (all plugged in through the API).  That way the second people get the game, they will have a way to add their own creatures.  If the game takes off, maybe someone can create some kind of creature 'library' so people can download different plants/animals into their game.

That way forward makes a lot more sense than relying on solely me to create things.

So next thing on my list is investigating Triangle Strips.  I currently use a Triangle List to create everything on the screen.  After investigating my memory, I realized that my vertex buffers take ~half of the RAM that my game uses.  Triangle Strips have less objects stored in memory due to the way they are built, so theoretically they should lower my RAM usage.

Theoretically.  I don't know if that's how it really is but I'm about to find out!

So.. a build and push to the testers tonight and Triangle Strips for the rest of the week.

Sunday, May 01, 2011

Time to move onto the next version.

With this latest optimization, I think I can safely say that it's time to move onto Version .02a.

Thanks to the help from reddit and the SomethingAwful forums I was able to greatly reduce my memory footprint.  I am now implementing a Dictionary<Int16,bool> which should technically be the smallest possible Dictionary combination for me.  I did this by changing it so instead of storing the cubes global position to the world, I'm storing it's relative position to the chunk.  When I need its global position I just take its local position and add it to the chunk position.

The formula I'm using to convert from Vector3 to Int16 is:

location.X + (location.Y * 256) + (location.Z * 16)

To convert back, I do the following:

            int y = index / 256;
            index -= (short)(y * 256);
            int z = index / 16;
            index -= (short)(z * 16);
            int x = index;

            return new Vector3(x, y, z);

This won't give me any collisions as long as I stay within 16x128x16. With the memory I save, this is the best possible combination that I can think of between the memory saved from not storing any visible cubes and always doing an algorithm check to the speed from storing all visible cubes and only doing the algorithm check once.

With this, I'm going to force myself to go onto .02a and do more fun programming stuff.  I'll push it out to the testers and have them test it to make sure I didn't make any obvious mistakes.

Here are some more cool screenshots with a drawOut of 30 (61x61 chunk world).

Love this mountain range.