Now that our level editor will be able to load in this data, we now want to have a way to actually modify what we see onscreen. To do this, we'll need to create a GUI interface and functionality for our level editor.
// The object we are currently looking to spawn private Transform toCreate;
Start
function:toCreate = tiles[0];
Update
function and then explain how it's working, as follows:void Update() { // Left click - Create object if (Input.GetMouseButton(0) && GUIUtility.hotControl == 0) { Vector3 mousePos = Input.mousePosition; /* Set the position in the z axis to the opposite of the camera's so that the position is on the world so ScreenToWorldPoint will give us valid values. */ mousePos.z = Camera.main.transform.position.z * -1; Vector3 pos = Camera.main.ScreenToWorldPoint(mousePos); // Deal with the mouse being not exactly on a // block int posX = Mathf.FloorToInt(pos.x + .5f); int posY = Mathf.FloorToInt(pos.y + .5f); Collider[] hitColliders = Physics.OverlapSphere(pos, 0.45f); int i = 0; while (i < hitColliders.Length) { if (toCreate.name != hitColliders[i].gameObject.name) { DestroyImmediate(hitColliders[i].gameObject); } else { // Already exists, no need to create // another return; } i++; } CreateBlock(tiles.IndexOf(toCreate) + 1, posX, posY); } // Right clicking - Delete object if (Input.GetMouseButton(1) && GUIUtility.hotControl == 0) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit = new RaycastHit(); Physics.Raycast(ray, out hit, 100); // If we hit something other than the player // we want to destroy it! if ((hit.collider != null) && (hit.collider.name != "Player")) { Destroy(hit.collider.gameObject); } } }
You'll note that we used something named hotControl
when we were checking for input. The reason we did this was that whenever a player holds down a mouse button, it becomes "hot." No other controls are allowed to respond to mouse events while some control is "hot."
Once the user releases their mouse, hotControl
gets set to 0
to indicate that other controls can respond to user input, which will be useful when we implement our GUI system, as we don't want to draw something when we're clicking on our mouse button.
For more information on
GUIUtility.hotControl
, check out http://docs.unity3d.com/ScriptReference/GUIUtility-hotControl.html.
A lot of the stuff contained in this code is from reusing a lot of the aspects you learned earlier in the book, back when we did our platformer game. Yet, now we are using the same functions to work with the mouse position in the world and converting it to world space.
We use the ScreenToWorldPoint
function to convert our mouse position from screenspace into world space with the Z position of the point being the units away from the camera we want the position to be. Because our world is at 0, we want the Z to be negative whatever the camera's Z position is.
For more information on
ScreenToWorldPoint
check out http://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html.
We use this information to get the position we want to place the block at. Once we have this, we can just call Instantiate
and create something, but we also need to make sure that we only have one object per tile, so we will use a raycast to determine if that area already has a block, and if it does, we will destroy it:
Start
function. We will enable it again in code later, but just for demonstration purposes, click on the checkbox to activate it once again. Then, in the Game tab, click on the screen and right-click on areas in the level. Take a look at the following screenshot:You'll note that now we can draw walls anywhere within our scene and delete anything aside from our player!