Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Windows-Phone-7

UNITY 3D – Game Programming – Part 4

4.97/5 (27 votes)
8 May 2015CPOL20 min read 78K   370  
The fourth article in a series to discuss Unity 3D and how to get started with your own 3D projects.

Introduction

In part four of the series, we will look at creating user interface elements using the new UI architecture in Unity 3D. Building on our code base, we will create a simple interface to perform some of the functions that we have been programming through the keyboard input in Part 2 and Part 3 of the series. If you have not already done so, please take a moment and read:

  1. Unity 3D – Game Programming – Part 1

  2. Unity 3D – Game Programming – Part 2

  3. Unity 3D – Game Programming – Part 3

  4. Unity 3D – Game Programming – Part 4

  5. Unity 3D – Game Programming – Part 5

  6. Unity 3D – Game Programming – Part 6

  7. Unity 3D – Game Programming – Part 7

  8. Unity 3D – Game Programming – Part 8

  9. Unity 3D – Game Programming – Part 9

  10. Unity 3D – Game Programming – Part 10

Unity 3D Networking Article(s):

  1. Unity 3D - Network Game Programming

Unity 3D Leap Motion and Oculus Rift Article(s):

  1. Unity 3D - Leap Motion Integration

In the first part of the series we started by the very basics of the Unity 3D environment. Getting a feel of the IDE and the different sections which you will be working with throughout your project. We also covered how to use the tools in the designer to apply different transformation to a selected Game Object: positioning, rotation and scaling. We finally looked at how to create our first script and using the script apply a rotation transform on the Y-Axis of our cube.

In the second part of the series, we looked at more of the transformation of a given object through coding. We also looked at how to create light sources that are crucial for the rendering of your objects in the scene.

In the third part of the series we looked at how to process user input through the keyboard and based on the key code take particular actions.

In Part 4 of the series, we will look at creating a simple user interface. The user interface that we will develop will provide us a means to feedback to the user, and also another method for the user to input to our game or simulation.

Introduction to Game Programing: Using C# and Unity 3D (Paperback) or (eBook) is designed and developed to help individuals that are interested in the field of computer science and game programming. It is intended to illustrate the concepts and fundamentals of computer programming. It uses the design and development of simple games to illustrate and apply the concepts.
Image 1
Paperback
ISBN: 9780997148404
Edition: First Edition
Publisher: Noorcon Inc.
Language: English
Pages: 274
Binding: Perfect-bound Paperback (Full Color)
Dimensions (inches): 6 wide x 9 tall
Support independent publishing: Buy this book on Lulu.
Image 3
eBook (ePUB)
ISBN: 9780997148428
Edition: First Edition
Publisher: Noorcon Inc.
Language: English
Size: 9.98 MB
Support independent publishing: Buy this e-book on Lulu.
Available From:

Windows Phone 8.x Demo:

I have provided a free phone application that you can download and preview the demos on your Windows Phone. To download the mobile application, follow the link: CodeProjectArticleSample

Image 9
Code Project Articles Sample Mobile App

Live Preview of Article Code and Visuals:

Image 10

Link to live preview: http://www.noorcon.com/CodeProject/CodeProjectArticlePreview.html

Background

It is assumed that the reader of this article is familiar with programming concepts in general. It is also assumed that the reader has an understanding and experience of the C# language. It is also recommended that the reader of the article is familiar with Object-Oriented Programming and Design Concepts as well. We will be covering them briefly throughout the article as needed, but we will not get into the details as they are separate topics altogether. We also assume that you have a passion to learn 3D programming and have the basic theoretical concepts for 3D Graphics and Vector Math.

Lastly, the article uses Unity 3D version 4.6.1 which is the latest public release as of the initial publication date. Most of the topics discussed in the series will be compatible with older versions of the game engine, and perhaps also the new version which is supposed to be release sometime this year. There is however, one topics which is significantly different in the current 4.6.1 version compared to the older version of the game engine, and that is the UI (User Interface) pipeline. This is due to the new UI architecture in the engine which is far superior to what we had prior to this release. I for one, am very happy with the new UI architecture.

Using the code

Downloading the project/source code for article series: Download source.

With each consecutive article that is submitted, the project/source code will be also expanding. The new project files and source files will be inclusive of older parts in the series.

NOTE: To get the latest code, go to the most recent published part in the series and download the code.

User Interface Design in Unity 3D

As you are aware of, every program is composed of some input and some output. In Part 3 of the series we looked at how to get input from the user through the computer keyboard. Now, we are going to look at how to display feedback to our user based so that he/she has a better idea of what is going on in the program, and also continue by creating another means for the user to input to the program.

NOTE: The User Interface that we are going to build will only be applicable to Unity 3D version 4.6.1 and above.

Prior to the latest release on Unity 3D, a game programmer and designer had to spend a significant amount of time for the proper development of their user interface for the game. And they had to do most of the design through coding and programming. With the latest release, we have a better engine to handle the UI portion and hence will significantly improve the efficiency of the UI development.

Assuming you have followed all of the parts in the series, let’s open our Unity 3D project. You will have a scene looking like the one below:

Image 11
Figure 1-Screenshot of Code From Part 3

Let’s go ahead and create a HUD (Heads Up Display) that will display the position and rotation for each of the primitives that we have in the scene.

If you recall from the previous articles, we have three design time primitives (cubes) that have been placed in the scene using the designer, as shown in the figure above. And we have a script which will create three more additional primitives (cubes) at runtime when we press the Space Bar on the keyboard.

To draw the UI elements, we would need to create a UI Canvas. This is important, every single UI element needs to be a child of a Canvas to be drawn on the screen.

To create a UI Canvas, Right-Click your mouse within the Hierarchy window in Unity 3D and you will get a context menu up:

Image 12
Figure 2-Context Menu After Right-Click in Hierarchy Window

Notice, under the UI Menu within the Context Menu, the UI Items that are available to you. These are:

  • Panel

  • Button

  • Text

  • Image

  • RawImage

  • Slider

  • Scrollbar

  • Toggle

  • InputField

  • Canvas

  • EventSystem

As you can see, you are limited to the types of UI elements available to you, but nevertheless, you have everything you need to implement the necessary functions for your game or simulation. With a little bit of creativity, these UI elements will go a long way!

Go ahead and select the Canvas object from the menu. When you do so, you will notice that two new GameObjects have been automatically placed in your scene, Canvas and EventSystem:

Image 13
Figure 3-Notice Two New Objects Got Placed in Your Scene

We will be adding our UI elements using the same method. Each time we want to add a UI element we will Right-Click to get the Context Menu and then select the proper UI component under the UI menu.

So let’s say we want to create our UI based on the following sketch:

Image 14
Figure 4-Sketch of Our User Interface

Creating the User Interface - Panel 1

We can start creating our user interface as sketched in Figure 4. Let’s start by first doing Panel 1. Within the Hierarchy window, select the Canvas GameObject and right-click to get the context menu up. Select UI->Panel to insert a Panel GameObject in the scene. Double click the Panel GameObject to have it focused on the Scene View as show in the following figure:

Image 15
Figure 5-Screenshot Showing Panel Drawn on Canvas

There are a lot of things going on here. First, notice that when you double click an item listed in the Hierarchy window, the Scene View focuses on the specified object in the scene. So, just on a side note, if you want to focus on a given object in a more complex scene, just double click on it.

Second and more importantly, take a look at the Inspector Window, marked as number 1 in Figure 5. Let’s take a moment and discuss a few important concepts here.

Image 16
Figure 6-Inspector Window for Panel

You should be familiar with the Inspector Window by now. This window lists all of the attached components to a given object, and based on the Object Type, it will list different components.

Looking at Figure 6, you notice three areas that I have highlighted:

  1. Rect Transform
  2. Image
  3. Panel

The Rect Transform component is the most important one that you should become familiar with. It is going to be used for the positioning and anchoring of your UI Objects in respect to one another!

We will be using the Rect Transform extensively to place and position our UI elements. More on this later.

The Image components is going to be the background texture for a given UI element. Given that the UI element supports such an attribute. Out of the box, each UI element uses the default textures and Transforms for each UI element as designed by the engine.

Finally, the Panel component, show the look and feel of the panel’s background image. More on this later as well!

Let’s go ahead and use the transform tool to adjust the position and size of the panel. We would want to anchor our panel to the TOP LEFT CORNER of the screen. Using the pre-existing anchor settings, we can simply use the desires Anchor Preset as shown in Figure 7.

To bring up the Anchor Preset configuration window, click in the region marked as 1 (one) in Figure 7. You will get a new window, marked as 2 (two) in Figure 7, listing all of the presets. From the existing presets, select the one that represent the top left corner of the screen.

Image 17
Figure 7-Display Pre-Configured Anchors

When you change the anchor settings, you will notice, that the Rect Transform properties have also been updated to reflect the new anchoring of the Panel GameObject. By defaults it fills the whole Canvas GameObject surface area.

Go ahead and width and height properties to the Rect Transform to 200 x 100 respectively. You should have a view like the following in your view:

Image 18
Figure 8-Panel Look After Anchoring and Size Settings

Now, we would like to move the Panel GameObject close to the Top Left Corner through positioning. Using the positioning tool, you can move it to the region you prefer as a designer. You can also use the Rect Transform to apply specific numeric numbers for the Pos X and Pos Y component. In this case Pos Z will always be 0.

Image 19
Figure 9-Panel after Positioning to Top Left Corner

Several things to note in Figure 9. First, notice that in the Scene View, at design, time the actual location of the Panel seems to be on the right hand side. This is because we are looking at the Canvas Object from the back. What does that mean?

Well, take a look at the three colored arrows red, green and blue. These arrows represent the positive direction of each axis in the 3D environment. If you have not figured this out by now, the red arrow represents the X-Axis, and the arrow is always directed towards the positive. The green arrow represents the Y-Axis, and the arrow is always directed towards the positive. The blue arrow represents the Z-Axis, and the arrow is always directed towards the positive direction.

In Figure 9, look at the region numbered 2 (two) and 3 (three). You will notice that the Rect Transform has been modified to have Pos X set to 110 and Pos Y set to -60. This is the displacement from the anchor point, which is the Top Left Corner.

There is no magic here, you just need to play with the positioning and the scaling to get the right feel for your UI design.

Now that we have added our Panel, let’s go ahead and add the labels which will display the position and the rotation of our primitives.

In the Hierarchy Window, Right-Click the Panel GameObject and select UI->Text.

Image 20
Figure 10-First Text UI Element

Just like our Panel UI element, let’s go ahead and change the anchoring of our Text UI element, to Top Left Corner, then using the Rect Transform or the design time positioning tool to adjust it and place it properly on the Top Left Corner of our Panel. Also change the name of the Text UI element to lblCube1Position.

Image 21
Figure 11-Position of Cube1 Primitives Label after Configuration

Go ahead and place two more Text UI elements as we did and position them according to our sketch in Figure 4. If you have done everything correctly, you will have something like the following figure:

Image 22
Figure 12-Final Panel Look for Design Time Primitives

Ok, so now we have one of our panels designed to display the position and rotation of the primitives created at design time from Part 1. Now we need to write some code to actual update our labels. We would need to update our previous scripts that handled the primitive rotation from Part 2 of our series.

If you recall, we created three separate scripts for each cube primitive and applied the rotation to the primitive in the Update() of that script. Now, we will need to update these scripts to be able to update our labels for each primitive. Let’s go ahead and modify the script for Cube1.

We will modify our cube1Rotate.cs script to the following listing:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class cube1Rotate : MonoBehaviour {

 // variable to store Text UI Element
 public Text lblCube1Position;

 private string position = "";

 // Use this for initialization
 void Start () {
 
 }
 
 // Update is called once per frame
 void Update () {
  // Rotate our game object around it's y-axis
  this.transform.Rotate (new Vector3 (0, 1, 0), 1);

  if (this.lblCube1Position != null) {
   position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
                                   this.transform.localPosition.x,
                                   this.transform.localPosition.y,
                                   this.transform.localPosition.z,
                                   this.transform.localEulerAngles.x,
                                   this.transform.localEulerAngles.y,
                                   this.transform.localEulerAngles.z);
   this.lblCube1Position.text = position;
  }
 }
}

When you review the listing above, you will notice that we have created a public variable of type Text. Also notice that we had to import the UnityEngine.UI namespace to be able to use the UI Objects in our code.

Then in our Update() function we have added a few lines of code to check to see if the lblCube1Position variable is initialized, and if it is, then we go ahead and construct a string that will represent the position and the rotation of the given object, and finally we assign the newly constructed string to the text field of the lblCube1Position UI element.

The first step was to update out script to be able to handle the updating and displaying of the information desired. The second step would be to make sure that our newly created script gets properly configured in the designer.

Image 23
Figure 13-Design Time Assignment of lblCube1Position Text Variable

As shown in Figure 13, you will need to assign the Text UI element to the Text variable defined in our script. One way to do this, is to select the GameObject in the scene that has the cube1Rotate.cs and drag-n-drop the lblCube1Position Text UI element from the Hierarchy Window (1) onto the Text variable defined in the script file (2) and (3) as shown in the Inspector Window.

When you run this program update, you will see that the top Text UI element will now display the position and the rotation.

NOTE: I had to adjust my Panel UI element and the Text UI element(s) due to the length of the text. This will happen throughout your UI design, as it is expected. You will need to adjust the Rect Transform accordingly to take into consideration the amount of data it is being displayed on the screen.

I have updated my UI elements as follows:

  • Panel UI element to have the following configuration: PosX=130; PosY=-40; Width=250; Height=75.

  • Text UI for lblCube1Position: PosX=125; PosY=-20; Width=230; Height=20; Font Size=12.

  • Text UI for lblCube2Position: PosX=125; PosY=-40; Width=230; Height=20; Font Size=12.

  • Text UI for lblCube3Position: PosX=125; PosY=-60; Width=230; Height=20; Font Size=12.

Image 24
Figure 14-Display Showing Label for Cube1

Go ahead and perform the same concept we performed for Cube1, and apply them to Cube2 and Cube3. You will need to update the scripts first, and then in the design view, assign the appropriate Text UI element to the variable supporting the Text Object in the script.

Updated listing for cube2Rotate.cs:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class cube2Rotate : MonoBehaviour {

 // variable to store Text UI Element
 public Text lblCube1Position;
 
 private string position = "";

 // Use this for initialization
 void Start () {
 
 }
 
 // Update is called once per frame
 void Update () {
  // Rotate our game object around it's x-axis
  this.transform.Rotate (new Vector3 (1, 0, 0), 1);

  if (this.lblCube1Position != null) {
   position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
                            this.transform.localPosition.x,
                            this.transform.localPosition.y,
                            this.transform.localPosition.z,
                            this.transform.localEulerAngles.x,
                            this.transform.localEulerAngles.y,
                            this.transform.localEulerAngles.z);
   this.lblCube1Position.text = position;
  }
 }
}

Updated listing for cube3Rotate.cs:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class cube3Rotate : MonoBehaviour {
 
 // variable to store Text UI Element
 public Text lblCube1Position;
 
 private string position = "";

 // Use this for initialization
 void Start () {
 
 }
 
 // Update is called once per frame
 void Update () {
  // Rotate our game object around it's z-axis
  this.transform.Rotate (new Vector3 (0, 0, 1), 1);

  if (this.lblCube1Position != null) {
   position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
                            this.transform.localPosition.x,
                            this.transform.localPosition.y,
                            this.transform.localPosition.z,
                            this.transform.localEulerAngles.x,
                            this.transform.localEulerAngles.y,
                            this.transform.localEulerAngles.z);
   this.lblCube1Position.text = position;
  }
 }
}

Image 25
Figure 15-The Final Panel Look for Position and Rotation of Design Time Primitives

As you can see, it does take time to design and position your UI properly on the screen. There is much more to it then it is shown in this article, but I believe this is a good start for anyone who has an interest to delve deeper. Also, don’t forget, that as mentioned earlier, in prior versions of the engine, you would have to do everything we just did through scripting!

Creating the User Interface - Panel 2

Let’s go ahead and create our second panel that will do the same thing, but for the dynamically created primitives. I will not repeat the steps here, because it is pretty much the same, but the position will be different.

Your environment should look something like the following:

Image 26
Figure 16-Screen View with Panel 2 Configured

We would also need to modify our script that handles the dynamic primitives createPrimitivesFromInput.cs as follows:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class createPrimitivesFromInput : MonoBehaviour {

 private GameObject cube1; // represents our Cube1'
 private GameObject cube2; // represents our Cube2'
 private GameObject cube3; // represents our Cube3'

 private bool PRIMITIVES_CREATED;

 public Text lblCube1Position;
 public Text lblCube2Position;
 public Text lblCube3Position;

 private string cube1position = "";
 private string cube2position = "";
 private string cube3position = "";

 // Use this for initialization
 void Start () {  
  this.PRIMITIVES_CREATED = false;

  // update position information for each primitive
  if(this.lblCube1Position != null){
   this.lblCube1Position.text = this.cube1position;
  }
  if(this.lblCube2Position != null){
   this.lblCube2Position.text = this.cube2position;
  }
  if(this.lblCube3Position != null){
   this.lblCube3Position.text = this.cube3position;
  }
 }

 // Update is called once per frame
 void Update () {

  if (!this.PRIMITIVES_CREATED) {
   if (Input.GetKey (KeyCode.Space)) {
    this.CreateMyPrimitives();
   }
  }else{
   // apply the y-axis transform to Cube1'
   if(Input.GetKey(KeyCode.A)){
    this.cube1.transform.Rotate(new Vector3(0,1,0), 1);
   }
   
   // apply the x-axis transform to Cube2'
   if(Input.GetKey(KeyCode.B)){
    this.cube2.transform.Rotate(new Vector3(1,0,0), 1);
   }

   // apply the z-axis transform to Cube3'
   if(Input.GetKey(KeyCode.C)){
    this.cube3.transform.Rotate(new Vector3(0,0,1), 1);
   }

   // code for the movement of Cube1' forward
   if(Input.GetKey(KeyCode.UpArrow)){
    this.cube1.transform.Translate(Vector3.forward * Time.deltaTime);
   }
   // code for the movement of Cube1' backward
   if(Input.GetKey(KeyCode.DownArrow)){
    this.cube1.transform.Translate(Vector3.back * Time.deltaTime);
   }
   // code for the movement of Cube1' left
   if(Input.GetKey(KeyCode.LeftArrow)){
    this.cube1.transform.Translate(Vector3.left * Time.deltaTime);
   }
   // code for the movement of Cube1' right
   if(Input.GetKey(KeyCode.RightArrow)){
    this.cube1.transform.Translate(Vector3.right * Time.deltaTime);
   }

   // update position information for each primitive
   if(this.lblCube1Position != null){
    this.cube1position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
                                  this.cube1.transform.localPosition.x,
                                  this.cube1.transform.localPosition.y,
                                       this.cube1.transform.localPosition.z,
                                       this.cube1.transform.localEulerAngles.x,
                                       this.cube1.transform.localEulerAngles.y,
                                       this.cube1.transform.localEulerAngles.z);
    this.lblCube1Position.text = this.cube1position;
   }
   if(this.lblCube2Position != null){
    this.cube2position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
                                       this.cube2.transform.localPosition.x,
                                       this.cube2.transform.localPosition.y,
                                       this.cube2.transform.localPosition.z,
                                       this.cube2.transform.localEulerAngles.x,
                                       this.cube2.transform.localEulerAngles.y,
                                       this.cube2.transform.localEulerAngles.z);
    this.lblCube2Position.text = this.cube2position;
   }
   if(this.lblCube3Position != null){
    this.cube3position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
                                       this.cube3.transform.localPosition.x,
                                       this.cube3.transform.localPosition.y,
                                       this.cube3.transform.localPosition.z,
                                       this.cube3.transform.localEulerAngles.x,
                                       this.cube3.transform.localEulerAngles.y,
                                       this.cube3.transform.localEulerAngles.z);
    this.lblCube3Position.text = this.cube3position;
   }
  }
 }

 // This function will be called when the Space Bar on the keyboard is pressed
 void CreateMyPrimitives(){

  if (!this.PRIMITIVES_CREATED) {

   // initialize our Cube1 primitive and place it at location (0,2,0)
   this.cube1 = GameObject.CreatePrimitive (PrimitiveType.Cube);
   this.cube1.transform.localPosition = new Vector3 (0, 2, 0);

   // initialize our Cube2 primitive and place it at location (3,2,0)
   this.cube2 = GameObject.CreatePrimitive (PrimitiveType.Cube);
   this.cube2.transform.localPosition = new Vector3 (3, 2, 0);

   // initialize our Cube3 primitive and place it at location (-3,2,0)
   this.cube3 = GameObject.CreatePrimitive (PrimitiveType.Cube);
   this.cube3.transform.localPosition = new Vector3 (-3, 2, 0);

   this.PRIMITIVES_CREATED = true;

  }
 }
}

After you update the script and in the designer assign the proper Text UI elements to the appropriate variables and run the program, you will see the following:

Image 27
Figure 17-Running Program with New Update

If you recall from Part 3 of the series, we implemented to receive an input from the program. The input to generate the dynamic primitives was the Space Bar on the keyboard. When you press the Space Bar, you will get the following screen:

Image 28
Figure 18-When Dynamic Primitives Are Created

Notice that the newly created primitives are not rotating, and that is because we made them rotate based on some keyboard input in Part 3. We assigned the A-Key to rotate Cube1’, the B-Key to rotate Cube2’ and the C-Key to rotate Cube3’. When you do so, you will get the updates as follows:

Image 29
Figure 19-Displaying All Position and Rotation Information

Creating the User Interface - Creating a Button and Event Handling

So far, we have looked at how to place Panels and Text (Label) UI elements on the scene. Let’s go ahead and now see how we can introduce Buttons. A Button in general is used for the user to click on and after the click, some particular event or action gets raised in your program.

The concept is pretty much the same here. The placement, positioning and scaling of the Button UI element is going to be exactly the same as the Panel and Text UI elements we have discussed so far.

In order for us to place a Button, we would select the Canvas GameObject in our Hierarchy Window, and Right-Click to get the context menu up. From there select UI->Button to place a Button UI element into the scene:

Image 30
Figure 20-Button Created in Scene

Notice in Figure 20, that the Button object itself has a child Text object. That is the label for the button! Also notice that the Button object has similar properties for the anchoring and positioning of the UI element on the scene. Let’s go ahead and modify the anchoring and positioning of our Button based on Figure 4.

The Button will be anchored to the Right Top Corner of our screen:

Image 31
Figure 21-Final Placement of Our Button

Image 32
Figure 22-Button Event Properties

Looking at the Inspector Window, once you select the Button UI element in the scene. You will notice several properties special to the Button Object.

NOTE: I have collapsed the components which we are not going to discuss at this time, and which you are already familiar with, namely the Rect Transform, so that we have enough screen real estate to display the Button (script) component.

In Unity 3D, you will need to create each function that will handle a particular event in the system. This at first is a little uncomfortable if you are used to double-clicking your UI object in a Windows or Web environment and have it automatically create a function with the appropriate parameters for you.

Looking at Figure 22, you notice the On Click() event that is defined already as a placeholder, it is not associated with anything yet! You will need to associate it with a function! To do so, you will need to click on the (+) icon indicated by a (1) in the Figure. When you do so, you will get the following:

Image 33
Figure 22-On Click() Event Created, but Not Assigned

 

Notice, there is nothing assigned to the OnClick() placeholder. This is where we would assign our GameObject that will be responsible handling the OnClick event of our Button in the scene.

We will use our createPrimitiveFromInput.cs script to handle our button click event. So let’s go ahead and modify the source code to the following:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class createPrimitivesFromInput : MonoBehaviour {

 private GameObject cube1; // represents our Cube1'
 private GameObject cube2; // represents our Cube2'
 private GameObject cube3; // represents our Cube3'

 private bool PRIMITIVES_CREATED;

 public Text lblCube1Position;
 public Text lblCube2Position;
 public Text lblCube3Position;

 private string cube1position = "";
 private string cube2position = "";
 private string cube3position = "";

 // Use this for initialization
 void Start () {  
  this.PRIMITIVES_CREATED = false;

  // update position information for each primitive
  if(this.lblCube1Position != null){
   this.lblCube1Position.text = this.cube1position;
  }
  if(this.lblCube2Position != null){
   this.lblCube2Position.text = this.cube2position;
  }
  if(this.lblCube3Position != null){
   this.lblCube3Position.text = this.cube3position;
  }
 }

 // Update is called once per frame
 void Update () {

  if (!this.PRIMITIVES_CREATED) {
   if (Input.GetKey (KeyCode.Space)) {
    this.CreateMyPrimitives();
   }
  }else{
   // apply the y-axis transform to Cube1'
   if(Input.GetKey(KeyCode.A)){
    this.cube1.transform.Rotate(new Vector3(0,1,0), 1);
   }
   
   // apply the x-axis transform to Cube2'
   if(Input.GetKey(KeyCode.B)){
    this.cube2.transform.Rotate(new Vector3(1,0,0), 1);
   }

   // apply the z-axis transform to Cube3'
   if(Input.GetKey(KeyCode.C)){
    this.cube3.transform.Rotate(new Vector3(0,0,1), 1);
   }

   // code for the movement of Cube1' forward
   if(Input.GetKey(KeyCode.UpArrow)){
    this.cube1.transform.Translate(Vector3.forward * Time.deltaTime);
   }
   // code for the movement of Cube1' backward
   if(Input.GetKey(KeyCode.DownArrow)){
    this.cube1.transform.Translate(Vector3.back * Time.deltaTime);
   }
   // code for the movement of Cube1' left
   if(Input.GetKey(KeyCode.LeftArrow)){
    this.cube1.transform.Translate(Vector3.left * Time.deltaTime);
   }
   // code for the movement of Cube1' right
   if(Input.GetKey(KeyCode.RightArrow)){
    this.cube1.transform.Translate(Vector3.right * Time.deltaTime);
   }

   // update position information for each primitive
   if(this.lblCube1Position != null){
    this.cube1position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
                                  this.cube1.transform.localPosition.x,
                                  this.cube1.transform.localPosition.y,
                                       this.cube1.transform.localPosition.z,
                                       this.cube1.transform.localEulerAngles.x,
                                       this.cube1.transform.localEulerAngles.y,
                                       this.cube1.transform.localEulerAngles.z);
    this.lblCube1Position.text = this.cube1position;
   }
   if(this.lblCube2Position != null){
    this.cube2position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
                                       this.cube2.transform.localPosition.x,
                                       this.cube2.transform.localPosition.y,
                                       this.cube2.transform.localPosition.z,
                                       this.cube2.transform.localEulerAngles.x,
                                       this.cube2.transform.localEulerAngles.y,
                                       this.cube2.transform.localEulerAngles.z);
    this.lblCube2Position.text = this.cube2position;
   }
   if(this.lblCube3Position != null){
    this.cube3position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
                                       this.cube3.transform.localPosition.x,
                                       this.cube3.transform.localPosition.y,
                                       this.cube3.transform.localPosition.z,
                                       this.cube3.transform.localEulerAngles.x,
                                       this.cube3.transform.localEulerAngles.y,
                                       this.cube3.transform.localEulerAngles.z);
    this.lblCube3Position.text = this.cube3position;
   }
  }
 }

 // This function will be called when the Space Bar on the keyboard is pressed
 public void CreateMyPrimitives(){

  if (!this.PRIMITIVES_CREATED) {

   // initialize our Cube1 primitive and place it at location (0,2,0)
   this.cube1 = GameObject.CreatePrimitive (PrimitiveType.Cube);
   this.cube1.transform.localPosition = new Vector3 (0, 2, 0);

   // initialize our Cube2 primitive and place it at location (3,2,0)
   this.cube2 = GameObject.CreatePrimitive (PrimitiveType.Cube);
   this.cube2.transform.localPosition = new Vector3 (3, 2, 0);

   // initialize our Cube3 primitive and place it at location (-3,2,0)
   this.cube3 = GameObject.CreatePrimitive (PrimitiveType.Cube);
   this.cube3.transform.localPosition = new Vector3 (-3, 2, 0);

   this.PRIMITIVES_CREATED = true;

  }
 }
}

All we have to do in this case it to modify our void CreateMyPrimitives() function to make it a public function, like public void CreateMyPrimitives().

NOTE: All event functions have to be void and public!

This would be step one. Creating the script to handle the event for us. Step two will be to assign the object that the script is assigned to, to the event handler of the Button element listed in Figure 23.

In our case, the createPrimitivesFromInput.cs is attached to our Main Camera GameObject. So you would select the Button GameObject to bring up the Inspector Window, and then you will drag and drop the Main Camera GameObject into the OnClick() placeholder. The result would be the following:

Image 34
Figure 24-Main Camera Object Assigned to OnClick() Button Event

The next step would be to get the function from the Drop-Down list pointed by the arrow in Figure 24. You will get a bunch of option. We are interested in the function we have defined in our Class. So select our Class and from within the Class select the function that represents our function that will handle the event.

Image 35
Figure 25-Displays Selection of Class and Function for Button Event

You have now created your first Interactive UI in Unity 3D! Congratulations! When you run the program now, you can instantiate the dynamic primitives either with your keyboard using the Space Bar, or the Button we just created on the screen!

Points of Interest

User interface design and development in itself is a large topic and one that will take time to master. In this article we saw some of the very basics to get you started in Unity 3D. The idea is to introduce you to the concepts and for you to take your own path and improve upon it on your own.

History

This is the fourth article of a series which I would slowly contribute to the Code Project community.

  1. Unity 3D – Game Programming – Part 1

  2. Unity 3D – Game Programming – Part 2

  3. Unity 3D – Game Programming – Part 3

  4. Unity 3D – Game Programming – Part 4

  5. Unity 3D – Game Programming – Part 5

  6. Unity 3D – Game Programming – Part 6

  7. Unity 3D – Game Programming – Part 7

  8. Unity 3D – Game Programming – Part 8

  9. Unity 3D – Game Programming – Part 9

  10. Unity 3D – Game Programming – Part 10

Unity 3D Networking Article(s):

  1. Unity 3D - Network Game Programming

Unity 3D Leap Motion and Oculus Rift Article(s):

  1. Unity 3D - Leap Motion Integration

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)