Introduction
In the third article in the series, we will continue on expanding our knowledge of the environment in general. We would also take a look at how to process user input from the keyboard. We need to be able to somehow handle user input and internally convert these inputs to desired actions or outputs. If you have not already done so, please take a moment and read:
-
Unity 3D – Game Programming – Part 1
-
Unity 3D – Game Programming – Part 2
-
Unity 3D – Game Programming – Part 3
-
Unity 3D – Game Programming – Part 4
-
Unity 3D – Game Programming – Part 5
-
Unity 3D – Game Programming – Part 6
-
Unity 3D – Game Programming – Part 7
-
Unity 3D – Game Programming – Part 8
-
Unity 3D – Game Programming – Part 9
-
Unity 3D – Game Programming – Part 10
Unity 3D Networking Article(s):
- Unity 3D - Network Game Programming
Unity 3D Leap Motion and Oculus Rift Article(s):
- 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 Part 3 of the series we will look at how to process user input and based on the input take particular actions. At this point we will only concentrate on the keyboard input from the user. Future articles will cover other types of input.
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.
|
|
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 |
| |
eBook (ePUB)
ISBN: 9780997148428
Edition: First Edition
Publisher: Noorcon Inc.
Language: English
Size: 9.98 MB |
|
|
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
Code Project Articles Sample Mobile App
Live Preview of Article Code and Visuals:
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.
Input Processing in Unity 3D - Input Manager
Each program you write, whether the program is a phone application, a web application, a game or an embedded system, needs some sort of an input. In general every program needs some sort of an input and some sort of an output. The output is what the users sees, and the input is what the user enters or gives to the program to generate the output based on some algorithm.
Unity 3D is no different. The game engine needs to be able to process inputs from different sources:
-
Keyboard
-
Mouse
-
Joystick(s)
Unity 3D manages its inputs through the Input Manager. The Input Manage is accessible by selecting Edit->Project Settings->Input from the main menu bar.
Figure 1-Input Manager
|
Figure 2-Horizonal Configuration
|
Figure 3-Vertical Configuration
|
Figure 1 lists all of the out of the box Input configurations defined in the game engine. Let’s go ahead and expand the first Input Definition called Horizontal. Looking at Figure 2, you will notice the attributes that are defined under the Horizontal Axis input configuration. The following are the properties of the input configuration that are important to take a note of:
-
Name: the name of the axis as defines in the Input Manager. This is the name that you can refer to in your C# code for to detect and perform an operation as desired.
-
Positive Button: defines the primary button that will provide the positive direction / force.
-
Negative Button: defines the primary button that will provide the negative direction / force.
-
Alt. Positive Button: same as the positive button, but defines a secondary input intake.
-
Alt. Negative Button: same as the negative button, but defines a secondary input intake.
-
Type: defines where the input source is coming from; (Keyboard/Mouse/Joystick).
-
Axis: which axis in the world should the force be applied to.
At this point we are not going to modify any of the configurations. I just wanted to show you how the Input Manager looked like and give you a brief overview of the properties.
Input Processing in Unity 3D - Keyboard Input
Recall from Part 2, we wanted to dynamically create our cube primitives and place them relative to the design time cubes. In order to achieve this, we had to create a new script and attach it to any active Game Object in the scene. We attached our script to the camera object.
NOTE: It was safe to do so because our script does not interact with the object it is attached to.
The result was that when we run the program, the primitives would be immediately created and displayed in the scene.
Now let’s consider the following scenario, what if we wanted to create the primitives only after a specific key was pressed on the keyboard, let’s say the Space Bar.
using UnityEngine;
using System.Collections;
public class createPrimitivesFromInput : MonoBehaviour {
private GameObject cube1;
private GameObject cube2;
private GameObject cube3;
private bool PRIMITIVES_CREATED;
void Start () {
this.PRIMITIVES_CREATED = false;
}
void Update () {
if (Input.GetKey (KeyCode.Space)) {
this.CreateMyPrimitives();
}
if (PRIMITIVES_CREATED) {
this.cube1.transform.Rotate(new Vector3(0,1,0), 1);
this.cube2.transform.Rotate(new Vector3(1,0,0), 1);
this.cube3.transform.Rotate(new Vector3(0,0,1), 1);
}
}
void CreateMyPrimitives(){
if (this.cube1 == null) {
this.cube1 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube1.transform.localPosition = new Vector3 (0, 2, 0);
}
if (this.cube2 == null) {
this.cube2 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube2.transform.localPosition = new Vector3 (3, 2, 0);
}
if (this.cube3 == null) {
this.cube3 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube3.transform.localPosition = new Vector3 (-3, 2, 0);
}
this.PRIMITIVES_CREATED = true;
}
}
The listing above is a modification of the script we created in Part 2 of the series. Let’s breakdown the script:
-
We need to detect if the Space Bar is pressed by the user. This is done in the Update() function using the Input object and the GetKey() function, i.e., Input.GetKey (KeyCode.Space). The parameter that we pass into the function is an enum representation of the Space Bar, KeyCode.Space.
-
Then we need to detect if the key is pressed by checking the value passed back by the GetKey() function. If true, then we will call a new function that we have defined called CreateMyPrimitives().
-
In the CreateMyPrimitive() function, we will check to see if the primitives are null, and if so, then we will instantiate them.
-
In the Update() function, we check to see if the primitives have been initialized, and if so, we then apply the rotation to each primitive accordingly.
Don’t forget that the Update() function is continuously executed while the program is running. Therefore, if the Space Bar is pressed several time, we are going to run into a problem. We will be instantiating the primitives as many times as the Space Bar is being pressed, resulting in chaos.
In order to prevent this from happening, we will introduce a new boolean variable called PRIMITIVES_CREATED which will be used to control if we need to instantiate the primitives or not. The initial value of the PRIMITIVES_CREATED is set to false, and this is done in the Start() function.
NOTE: Remember that the Start() function gets executed only once at the start!
So when the Space Bar is pressed, the CreateMyPrimitives() function is called, and the primitives are instantiated. Again, notice, that we are checking to see if the primitive variables are null before we instantiate them. Finally we set the PRIMITIVES_CREATED variable to true.
Now, in the Update() function, we have to check and see if the primitives are initialized before we can apply our rotation to the Transform.
Figure 4-Screenshot of Running New Script
Can we improve this code? Sure we can. Here is another listing that will do exactly what we want.
using UnityEngine;
using System.Collections;
public class createPrimitivesFromInput : MonoBehaviour {
private GameObject cube1;
private GameObject cube2;
private GameObject cube3;
private bool PRIMITIVES_CREATED;
void Start () {
this.PRIMITIVES_CREATED = false;
}
void Update () {
if (!this.PRIMITIVES_CREATED) {
if (Input.GetKey (KeyCode.Space)) {
this.CreateMyPrimitives();
}
}else{
this.cube1.transform.Rotate(new Vector3(0,1,0), 1);
this.cube2.transform.Rotate(new Vector3(1,0,0), 1);
this.cube3.transform.Rotate(new Vector3(0,0,1), 1);
}
}
void CreateMyPrimitives(){
if (!this.PRIMITIVES_CREATED) {
this.cube1 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube1.transform.localPosition = new Vector3 (0, 2, 0);
this.cube2 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube2.transform.localPosition = new Vector3 (3, 2, 0);
this.cube3 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube3.transform.localPosition = new Vector3 (-3, 2, 0);
this.PRIMITIVES_CREATED = true;
}
}
}
As you can see, the new listing is improved as we are using one variable to detect if the primitives are created or not and based on that perform our operations.
Using Keyboard Input to Apply Rotation
Now, let’s go a step further. Let’s go ahead and define some input key values to handle the rotation for the dynamically created primitives in the following order:
-
Key A will be responsible to rotate Cube1’ on the Y-Axis.
-
Key B will be responsible to rotate Cube2’ on the X-Axis.
-
Key C will be responsible to rotate Cube3’ on the Z-Axis.
We would need to modify our code to handle the three new input types as follows:
using UnityEngine;
using System.Collections;
public class createPrimitivesFromInput : MonoBehaviour {
private GameObject cube1;
private GameObject cube2;
private GameObject cube3;
private bool PRIMITIVES_CREATED;
void Start () {
this.PRIMITIVES_CREATED = false;
}
void Update () {
if (!this.PRIMITIVES_CREATED) {
if (Input.GetKey (KeyCode.Space)) {
this.CreateMyPrimitives();
}
}else{
if(Input.GetKey(KeyCode.A)){
this.cube1.transform.Rotate(new Vector3(0,1,0), 1);
}
if(Input.GetKey(KeyCode.B)){
this.cube2.transform.Rotate(new Vector3(1,0,0), 1);
}
if(Input.GetKey(KeyCode.C)){
this.cube3.transform.Rotate(new Vector3(0,0,1), 1);
}
}
}
void CreateMyPrimitives(){
if (!this.PRIMITIVES_CREATED) {
this.cube1 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube1.transform.localPosition = new Vector3 (0, 2, 0);
this.cube2 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube2.transform.localPosition = new Vector3 (3, 2, 0);
this.cube3 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube3.transform.localPosition = new Vector3 (-3, 2, 0);
this.PRIMITIVES_CREATED = true;
}
}
}
Notice, that the Update() function is where you place the logic to perform your Input and Output. In the listing above, the code checks to see if the primitives have been initialized, and if true, then it will check for input from the user. Based on the key value it will apply the appropriate rotation to the Game Object.
Something to think about: in the new code, the primitives will not rotate continuously as they did in Part 2. They also will not rotate in-synch at the same time!
Each primitive will rotate independently only when the specific key associated to its rotation is pressed. For instance, if you press the A key, Cube1’ will continuously rotate until you stop pressing it. It will stop at the last rotation angle where you lifted your finger from the key!
Figure 5-Screenshot Capturing New Input for Rotation
Using Keyboard Input to Apply Translation
Continuing on our script improvement, let’s now use the following keys to move Cube1’ forward, backward, and to either side:
-
Up Arrow Key will be responsible to move Cube1’ on the Z-Axis.
-
Down Arrow Key will be responsible to move Cube1’ backward on the Z-Axis.
-
Left Arrow Key will be responsible to move Cube1’ to the left on the X-Axis.
-
Right Arrow Key will be responsible to move Cube1’ to the right on the X-Axis.
In order to achieve this, we will need to modify our Update() function as follows:
using UnityEngine;
using System.Collections;
public class createPrimitivesFromInput : MonoBehaviour {
private GameObject cube1;
private GameObject cube2;
private GameObject cube3;
private bool PRIMITIVES_CREATED;
void Start () {
this.PRIMITIVES_CREATED = false;
}
void Update () {
if (!this.PRIMITIVES_CREATED) {
if (Input.GetKey (KeyCode.Space)) {
this.CreateMyPrimitives();
}
}else{
if(Input.GetKey(KeyCode.A)){
this.cube1.transform.Rotate(new Vector3(0,1,0), 1);
}
if(Input.GetKey(KeyCode.B)){
this.cube2.transform.Rotate(new Vector3(1,0,0), 1);
}
if(Input.GetKey(KeyCode.C)){
this.cube3.transform.Rotate(new Vector3(0,0,1), 1);
}
if(Input.GetKey(KeyCode.UpArrow)){
this.cube1.transform.Translate(Vector3.forward * Time.deltaTime);
}
if(Input.GetKey(KeyCode.DownArrow)){
this.cube1.transform.Translate(Vector3.back * Time.deltaTime);
}
if(Input.GetKey(KeyCode.LeftArrow)){
this.cube1.transform.Translate(Vector3.left * Time.deltaTime);
}
if(Input.GetKey(KeyCode.RightArrow)){
this.cube1.transform.Translate(Vector3.right * Time.deltaTime);
}
}
}
void CreateMyPrimitives(){
if (!this.PRIMITIVES_CREATED) {
this.cube1 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube1.transform.localPosition = new Vector3 (0, 2, 0);
this.cube2 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube2.transform.localPosition = new Vector3 (3, 2, 0);
this.cube3 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube3.transform.localPosition = new Vector3 (-3, 2, 0);
this.PRIMITIVES_CREATED = true;
}
}
}
Figure 6-Screenshot of Translation of Object
So now you have seen how to handle keyboard input in Unity 3D, and based on the input perform an action.
Points of Interest
Using the new skills you have, try to think about the different aspects of user inputs your game or simulation is going to need. How will one manage more actions and handle multiple inputs? Do some reading on the subject and download the source code in this article to practice more. Next we will demonstrate how to create some simple User Interface elements.
History
This is the third article of a series which I would slowly contribute to the Code Project community.
-
Unity 3D – Game Programming – Part 1
-
Unity 3D – Game Programming – Part 2
-
Unity 3D – Game Programming – Part 3
-
Unity 3D – Game Programming – Part 4
-
Unity 3D – Game Programming – Part 5
-
Unity 3D – Game Programming – Part 6
-
Unity 3D – Game Programming – Part 7
-
Unity 3D – Game Programming – Part 8
-
Unity 3D – Game Programming – Part 9
-
Unity 3D – Game Programming – Part 10
Unity 3D Networking Article(s):
- Unity 3D - Network Game Programming
Unity 3D Leap Motion and Oculus Rift Article(s):
- Unity 3D - Leap Motion Integration