In this part of the tutorial you will make a ground, a tree, a moving camera, and a Tree Brush tool similar to the tool in Cities: Skylines.
Start by making a plane with the scale 100 positioned at the center. Give it a nice color and rename it to "Ground." Then create an empty gameobject and rename it "_Controller." Make sure it is at the center. This controller will hold all scripts we create.
Then create an empty gameobject and rename it to "Tree." As a child to that gameobject, create a cylinder, and rename it to "Wood." It should have position (0, 1, 0) and scale (0.2, 1, 0.2). Give it a material called "Wood." Then add a sphere, and rename the sphere to "Leaf," and give it a material called "Leaf." The sphere should have position (0, 2, 0) and scale (2, 2.54, 2). If you have done everything correctly you should now have what looks like a tree, where the coordinate system of the tree begins at the bottom of the tree. This will make it easier to add trees and we don't need to care about the tree's height. Also make the tree a prefab.
Now we need a script that can move the camera. This is not a tutorial on how to move a camera, so I will just give you my script. The basic idea is that we move the camera with WASD and zoom it with the mouse wheel or keys I or O. Drag the script to the camera.
using UnityEngine; using System.Collections; public class CameraController : MonoBehaviour { float height = 40f; float distanceBack = 40f; float camMoveSpeed = 30f; float zoomSpeed = 3f; void Start() { transform.position = Vector3.zero; //Move up transform.position += new Vector3(0f, height, 0f); //Move back transform.position -= new Vector3(0f, 0f, distanceBack); //Look at the center to get an angle transform.LookAt(Vector3.zero); } void LateUpdate() { //Move camera with keys //Move left/right if (Input.GetKey(KeyCode.A)) { transform.position -= new Vector3(camMoveSpeed * Time.deltaTime, 0f, 0f); } else if (Input.GetKey(KeyCode.D)) { transform.position += new Vector3(camMoveSpeed * Time.deltaTime, 0f, 0f); } //Move forward/back if (Input.GetKey(KeyCode.S)) { transform.position -= new Vector3(0f, 0f, camMoveSpeed * Time.deltaTime); } else if (Input.GetKey(KeyCode.W)) { transform.position += new Vector3(0f, 0f, camMoveSpeed * Time.deltaTime); } //Zoom float currentHeight = transform.position.y; float zoomDistance = 0f; if (currentHeight > 20f && currentHeight < 200f) { if (Input.GetAxis("Mouse ScrollWheel") > 0f || Input.GetKeyDown(KeyCode.I)) { zoomDistance += zoomSpeed; } else if (Input.GetAxis("Mouse ScrollWheel") < 0f || Input.GetKeyDown(KeyCode.O)) { zoomDistance -= zoomSpeed; } } //Can only zoom in else if (currentHeight > 200f) { if (Input.GetAxis("Mouse ScrollWheel") > 0f || Input.GetKeyDown(KeyCode.I)) { zoomDistance += zoomSpeed; } } //Can only zoom out else if (currentHeight < 20f) { if (Input.GetAxis("Mouse ScrollWheel") < 0f || Input.GetKeyDown(KeyCode.O)) { zoomDistance -= zoomSpeed; } } transform.Translate(Vector3.forward * zoomDistance); } }
Now we will create a Tree Brush tool similar to the tool Cities: Skylines is using to place trees. If you haven't seen it, it is basically a filled circle that you can resize to place (or remove) trees over a larger or smaller area.
Out Tree Brush tool consists of a projector, so import Unity's standard projectors. Go to Assets → Import package → Effects → Projectors. We are here going to use the BlobLightProjector. But first you have to create an empty gameobject and rename it "Circle." Then make the projector a child of that gameobject. Position the projector at (0, 0.38, 0) and make sure the rotation is (90, 0, 0). Also check the projector's "Ortographic" checkbox, and that the projector should ignore layer "Tree." So make sure the Tree you created is at a layer called "Tree."
But the projector's circle doesn't look good, so we need a new one. Open the projector's material and give it a new circle by importing a circle image to Unity and then drag it to the material slot called "Cookie." I'm using this circle:
Now we need to make the circle move around with the mouse. Create a new script called "TutorialMouseMarker," and add the following to it:
using UnityEngine; using System.Collections; //Creates a cities skylines style round circle that //will move around with the mouse and is resizable public class TutorialMouseMarker : MonoBehaviour { public static TutorialMouseMarker current; //Drags //The gameobject holding the projector public GameObject circleObj; //The projector that will display the circle public Projector projector; //Projector settings float projectorMax = 15f; float projectorMin = 3f; void Awake() { current = this; } void Update() { UpdateProjector(); } //Move the circle and change its size void UpdateProjector() { //Find the position of the mouse Vector3 mouseScreenPosition = Input.mousePosition; RaycastHit hit; //Fire ray and make sure we hit ground which is layer 10 if (Physics.Raycast(Camera.main.ScreenPointToRay(mouseScreenPosition), out hit, 1000f, 1 << 10)) { //Change the position of the circle to the position //where the ray hit the ground circleObj.transform.position = hit.point; } //Change size of projector radius float projectorSize = projector.orthographicSize; //Increase/decrease with p and m keys if (Input.GetKey(KeyCode.P)) { projectorSize += 0.5f; } else if (Input.GetKey(KeyCode.M)) { projectorSize -= 0.5f; } //Make sure it can't grow too big nor too small projector.orthographicSize = Mathf.Clamp(projectorSize, projectorMin, projectorMax); } }
Add the script to "_Controller" gameobject and add both the "Circle" gameobject and the projector to the script. The basic idea of the script is to fire a ray from wherever the mouse is towards the ground and then position the circle where the ray hit the ground. To make this work the ray has to ignore everything else except the ground. So click on the "Ground" gameobject and make sure it is at layer 10 (We check that when we fire a ray by using the parameter "1 << 10") and give the layer a cool name like Ground.
The last part of the script above takes care of resizing the circle so we can remove trees over a larger area and add trees over a smaller area. If you now click play you should see something that looks like this (ignore the "Tree parent" and the "Tree combined" gameobjects because we will soon add them):
Now let's learn how to combine meshes with different colors into one mesh!