This is my first post, so sorry if it isn’t good. I’m making a Minecraft-like game in Unity, and I’m happy with everything except that I can’t save any worlds. The worlds go on forever and the terrain is random too. I heard about arrays and each blocks being a byte. I’m very new to Unity, so I don’t really know what these mean or how to save them.
Here is my whole Chunk Script used in the game:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public enum TerrainType {
Lowlands,
Highlands,
Mountains
}
public enum BiomeType {
Grasslands,
Forest,
Desert,
Ice
}
[RequireComponent (typeof(MeshFilter))]
[RequireComponent (typeof(MeshCollider))]
public class Chunk : MonoBehaviour {
public int height = 40;
public int groundHeight = 8;
public byte[,,] map;
protected Mesh mesh;
protected List<Vector3> verts = new List<Vector3>();
protected List<int> tris = new List<int>();
protected List<Vector2> uv = new List<Vector2>();
protected MeshCollider meshCollider;
public List<GameObject> targets = new List<GameObject>();
protected bool initialized = false;
protected int width;
// Use this for initialization
void Start () {
width = Terrain.activeTerrain.chunkSize;
map = new byte[width, height, width];
TerrainType terrainType = GetTerrainFor(transform.position.x, transform.position.z);
BiomeType biomeType = GetBiomeFor(transform.position.x, transform.position.z);
float myHeight = GetHeightOf(terrainType);
byte dirt = Terrain.blocks.GetBlockByte("Dirt");
byte grassydirt = Terrain.blocks.GetBlockByte("GrassyDirt");
byte ice = Terrain.blocks.GetBlockByte("Ice");
byte sand = Terrain.blocks.GetBlockByte("Sand");
for (int x = 0; x < width; x++)
{
float percent = (float)x / (float)(width - 1);
float xBalance = CurvePoint(
percent,
(GetHeightOf(transform.position.x - width, transform.position.z) + myHeight) / 2,
myHeight,
(GetHeightOf(transform.position.x + width, transform.position.z) + myHeight) / 2);
for (int z = 0; z < width; z++)
{
percent = (float)z / (float)(width - 1);
float zBalance = CurvePoint(
percent,
(GetHeightOf(transform.position.x, transform.position.z - width) + myHeight) / 2,
myHeight,
(GetHeightOf(transform.position.x, transform.position.z + width) + myHeight) / 2);
float finalHeight = (xBalance + zBalance) / 2;
for (int y = 0; y < finalHeight; y++)
{
switch (biomeType)
{
default:
if (y >= finalHeight - 1)
map[x, y, z] = grassydirt;
else
map[x, y, z] = dirt;
break;
case BiomeType.Ice:
if (y >= finalHeight - 2)
map[x, y, z] = ice;
else
map[x, y, z] = dirt;
break;
case BiomeType.Desert:
if (y >= finalHeight - 7)
map[x, y, z] = sand;
else
map[x, y, z] = dirt;
break;
}
}
}
}
for (int dx = -1; dx <= 1; dx++)
{
for (int dz = -1; dz <= 1; dz++)
{
float myX = transform.position.x + dx * width;
float myZ = transform.position.z + dz * width;
List<LandBrush> brushes = GetBrushesFor(myX, myZ);
for (int a = 0; a < brushes.Count; a++)
{
brushes[a].ApplyBrush(this);
}
}
}
initialized = true;
Regenerate();
}
// Update is called once per frame
void Update () {
}
public void CloseMeshTarget() {
mesh.vertices = verts.ToArray();
mesh.triangles = tris.ToArray();
mesh.uv = uv.ToArray();
mesh.RecalculateNormals();
meshCollider.sharedMesh = mesh;
}
public void CreateMeshTarget(bool reset=false) {
meshCollider = GetComponent<MeshCollider>();
mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
verts.Clear();
tris.Clear();
uv.Clear ();
}
public void DrawBrick(int x, int y, int z, byte block) {
Vector3 start = new Vector3(x, y, z);
Vector3 offset1, offset2;
if (IsTransparent(x, y - 1, z))
{
offset1 = Vector3.left;
offset2 = Vector3.back;
DrawFace(start + Vector3.right, offset1, offset2, block);
}
if (IsTransparent(x, y + 1, z))
{
offset1 = Vector3.right;
offset2 = Vector3.back;
DrawFace(start + Vector3.up, offset1, offset2, block);
}
if (IsTransparent(x - 1, y, z))
{
offset1 = Vector3.back;
offset2 = Vector3.down;
DrawFace(start + Vector3.up, offset1, offset2, block);
}
if (IsTransparent(x + 1, y, z))
{
offset1 = Vector3.forward;
offset2 = Vector3.down;
DrawFace(start + Vector3.right + Vector3.up + Vector3.back, offset1, offset2, block);
}
if (IsTransparent(x, y, z - 1))
{
offset1 = Vector3.right;
offset2 = Vector3.down;
DrawFace(start + Vector3.back + Vector3.up, offset1, offset2, block);
}
if (IsTransparent(x, y, z + 1))
{
offset1 = Vector3.left;
offset2 = Vector3.down;
DrawFace(start + Vector3.up + Vector3.right, offset1, offset2, block);
}
}
public void DrawFace(Vector3 start, Vector3 offset1, Vector3 offset2, byte block)
{
int index = verts.Count;
verts.Add (start);
verts.Add (start + offset1);
verts.Add (start + offset2);
verts.Add (start + offset1 + offset2);
BlockType blockType = Terrain.blocks.GetBlock(block);
Vector2 uvBase = blockType.UVCoord();
float uvOff = 64f / 1024f;
if ((offset1 == Vector3.right) && (offset2 == Vector3.back))
{
uv.Add (uvBase);
uv.Add (uvBase + new Vector2(uvOff, 0));
uv.Add (uvBase + new Vector2(0, -uvOff));
uv.Add (uvBase + new Vector2(uvOff, -uvOff));
}
else
{
uv.Add (uvBase + new Vector2(0, -uvOff));
uv.Add (uvBase + new Vector2(uvOff, -uvOff));
uv.Add (uvBase + new Vector2(0, -uvOff * 2));
uv.Add (uvBase + new Vector2(uvOff, -uvOff * 2));
}
tris.Add (index + 0);
tris.Add (index + 1);
tris.Add (index + 2);
tris.Add (index + 3);
tris.Add (index + 2);
tris.Add (index + 1);
}
public bool IsTransparent(int x, int y, int z)
{
if ((x< 0) || (y < 0) || (z < 0) || (x >= width) || (y >= height) || (z >= width)) return true;
return map[x,y,z] == 0;
}
public void Regenerate() {
if (! initialized) return;
CreateMeshTarget(true);
mesh.triangles = tris.ToArray();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
for (int z = 0; z < width; z++)
{
byte block = map[x,y,z];
if (block == 0) continue;
DrawBrick(x, y, z, block);
}
}
}
CloseMeshTarget();
}
public void SetBrick(int x, int y , int z, byte block)
{
if (y == 0) return;
x -= Mathf.RoundToInt(transform.position.x);
y -= Mathf.RoundToInt(transform.position.y);
z -= Mathf.RoundToInt(transform.position.z);
if ((x< 0) || (y < 0) || (z < 0) || (x >= width) || (y >= height) || (z >= width)) return;
if (map[x,y,z] != block)
{
map[x,y,z] = block;
Regenerate();
}
}
public static List<LandBrush> GetBrushesFor(float x, float z) {
List<LandBrush> brushes = new List<LandBrush>();
Terrain terrain = Terrain.activeTerrain;
TerrainType terrainType = GetTerrainFor(x, z);
BiomeType biomeType = GetBiomeFor (x, z);
Random.seed = terrain.seed + Mathf.FloorToInt(x * 7 + z * 13);
float numBrushes = 8;
if (terrainType == TerrainType.Mountains)
numBrushes = 18;
while (numBrushes > 0)
{
numBrushes--;
brushes.Add (new LandBrush(x, z, terrain.chunkSize, terrainType, biomeType));
}
return brushes;
}
public static TerrainType GetTerrainFor(float x, float z) {
Random.seed = Terrain.activeTerrain.seed + Mathf.FloorToInt(x * 7 + z * 13);
return (TerrainType)Mathf.FloorToInt(Random.value * 3);
}
public static BiomeType GetBiomeFor (float x, float z) {
x = Mathf.FloorToInt(x / 160);
z = Mathf.FloorToInt(x / 160);
Random.seed = Terrain.activeTerrain.seed + Mathf.FloorToInt(x * 7 + z * 13);
return (BiomeType)Mathf.FloorToInt(Random.value * 4);
}
public static float GetHeightOf(float x, float z) {
return GetHeightOf (GetTerrainFor(x, z));
}
public static float GetHeightOf(TerrainType terrainType) {
switch (terrainType)
{
default: return 8;
case TerrainType.Highlands:
return 13;
case TerrainType.Mountains:
return 30;
}
}
public static float CurvePoint(float percent, float val1, float val2, float val3)
{
float p1 = (1 - percent) * val1 + percent * val2;
float p2 = (1 - percent) * val2 + percent * val3;
return (1 - percent) * p1 + percent * p2;
}
}