From the start I've wanted give Patreon's a little extra whereever possible. I've tried that with bonus videos but keeping those videos exclusive has proved to be a bit trickier than expected. But I thought I'd share this.
Below is the text I write for myself when making a video (I always put the video together before hand to try and minimise cut-worthy moments). It's gotten to the point where the text I write is pretty self-explanatory, and could stand as a good supplement to the video itself, so I thought I'd share with you guys. This is the text I wrote for the most recent video, part 2 of the How to Make 7 Days to Die in Unity series.
/////////////////////////////////////////////////////////////////////////////
// REMEMBER TO RESIZE YOUR CODE TEXT SO PEOPLE CAN READ IT IN THE VIDEO!!! //
/////////////////////////////////////////////////////////////////////////////
// Change sky colour to make terrain more visible.
// Change "0.5f" in PopulateTerrainMap to use the terrainsurface variable.
// While in PopulateTerrainMap, get rid of all that if bollocks and have terrainMap be set to;
// Set the value of this point in the terrainMap.
terrainMap[x, y, z] = (float)y - thisHeight;
// Replace EdgeTable with a 2D table of ints that represent indexes in the corner table, update the code in MarchCube to use the new table.
int[,] EdgeIndexes = new int[12, 2] {
{0, 1}, {1, 2}, {3, 2}, {0, 3}, {4, 5}, {5, 6}, {7, 6}, {4, 7}, {0, 4}, {1, 5}, {2, 6}, {3, 7}
};
// Get the vertices for the start and end of this edge.
Vector3 vert1 = position + CornerTable[EdgeIndexes[indice, 0]];
Vector3 vert2 = position + CornerTable[EdgeIndexes[indice, 1]];
// Create a function for returning terrain value.
float SampleTerrain (Vector3Int point) {
return terrainMap[point.x, point.y, point.z];
}
// Replace the one call to terrainMap (in CreateMeshData) with a call to this function.
cube[i] = SampleTerrain(corner);
// Move the cube float array setup into MarchCube and use the new SampleTerrain funcion. Remove the cube setup from our CreateMeshData function.
void MarchCube (Vector3Int position) {
// Sample terrain values at each corner of cube.
float[] cube = new float[8];
for (int i = 0; i < 8; i++) {
cube[i] = SampleTerrain(position + CornerTable[i]);
}
// Get the configuration index of this cube.
int configIndex = GetCubeConfiguration(cube);
// Add bool to choose between smooth and isometric style terrain.
public bool smoothTerrain;
// And add new code for smooth interpolation, wrapped in an if statement conditional on that smoothterrain value.
Vector3 vertPosition;
if (smoothTerrain) {
// Get the terrain values at either of our current edge from the cube array we created above.
float vert1Sample = cube[EdgeIndexes[indice, 0]];
float vert2Sample = cube[EdgeIndexes[indice, 1]];
// Calculate the difference between the two terrain values.
float difference = vert2Sample - vert1Sample;
// If the difference is 0, the terrain passes through the middle of the edge.
if (difference == 0f)
difference = terrainSurface;
else
difference = (terrainSurface - vert1Sample) / difference;
// Calculate the point along the edge that the terrain passes through.
vertPosition = vert1 + ((vert2 - vert1) * difference);
} else {
// Get the midpoint of this edge.
vertPosition = (vert1 + vert2) / 2f;
}
// Add new bool for flatshading.
public bool flatShadedTerrain;
// Create a function for returning the index of a vert (or adding it if it's not there)
int VertForIndice (Vector3 vert) {
// Loop through all the verts currently in the vertices list.
for (int i = 0; i < vertices.Count; i++) {
// If we find one that matches the vert we have, return the index of that vert.
if (vertices[i] == vert)
return i;
}
// If we didn't find a match, add our vert to the list and return that latest index instead.
vertices.Add(vert);
return vertices.Count - 1;
}
// Wrap the end of MarchCube in an if statement to use that function (or not) based on the flatShaded bool.
// Add to our vertices and triangles list and incremement the edgeIndex.
if (flatShadedTerrain) {
vertices.Add(vertPosition);
triangles.Add(vertices.Count - 1);
} else
triangles.Add(VertForIndice(vertPosition));
// Add a mesh collider component, get the component, and set the mesh in BuildMesh. Give the object a tag of "Terrain". Make sure to create the tag in the tags menu.
MeshCollider meshCollider;
meshCollider = GetComponent();
transform.tag = "Terrain";
// Child camera to a second gameobject and basic movement script using the following code.
public Camera cam;
void Update() {
transform.position = Vector3.MoveTowards(transform.position, transform.position + (cam.transform.forward * Input.GetAxis("Vertical")) + (transform.right * Input.GetAxis("Horizontal")), Time.deltaTime * 10f);
cam.transform.Rotate(new Vector3(-Input.GetAxis("Mouse Y"), 0, 0));
transform.Rotate(new Vector3(0, Input.GetAxis("Mouse X"), 0));
}
// Create a crosshair type thing to signify middle of screen.
// Add code to camera script update to raycast on mouseclick.
if (Input.GetMouseButtonDown(0)) {
Ray ray = cam.ViewportPointToRay(new Vector3(0.5f, 0.5f, 1f));
RaycastHit hit;
if (Physics.Raycast(ray, out hit)) {
if (hit.transform.tag == "Terrain")
Debug.Log("Left Clicked on Terrain");
}
}
if (Input.GetMouseButtonDown(1)) {
Ray ray = cam.ViewportPointToRay(new Vector3(0.5f, 0.5f, 1f));
RaycastHit hit;
if (Physics.Raycast(ray, out hit)) {
if (hit.transform.tag == "Terrain")
Debug.Log("Right Clicked on Terrain");
}
}
// Finally, create two new public functions in marching to deform terrain;
public void PlaceTerrain (Vector3 pos) {
Vector3Int v3Int = new Vector3Int(Mathf.CeilToInt(pos.x), Mathf.CeilToInt(pos.y), Mathf.CeilToInt(pos.z));
terrainMap[v3Int.x, v3Int.y, v3Int.z] = 0f;
CreateMeshData();
}
public void RemoveTerrain (Vector3 pos) {
Vector3Int v3Int = new Vector3Int(Mathf.FloorToInt(pos.x), Mathf.FloorToInt(pos.y), Mathf.FloorToInt(pos.z));
terrainMap[v3Int.x, v3Int.y, v3Int.z] = 1f;
CreateMeshData();
}
// And replace those Debug lines in the camera script with;
hit.transform.GetComponent().RemoveTerrain(hit.point);
hit.transform.GetComponent().PlaceTerrain(hit.point);
// Done!