Summary
In this tutorial we will create simple UI for user login and registration. From this tutorial you will learn how to:
- create Unity project;
- import assets from asset store into project;
- create UI using model-view-controller (MVC) approach with javascript;
- interact with http server.
Try demo for this tutorial here http://unity-test-server.appspot.com/demo.
Download source code here https://docs.google.com/file/d/0B0HipNssJJD-bEh0Wi1XeV9PSlE/edit.
Creating of project
Start unity and create an empty project: File menu -> New project. In dialog (fig. 1) enter location where you want save this project and press Create button. Left import checkboxes unselected.
Fig. 1. Dialog of new project creation
Unity will restart. In File menu select Save Scene and save it as StartMenu scene (fig. 2).
Fig. 2. Saving scene
Adding some dynamic: selecting of skybox material and camera rotation
Now lets see what we got. Press Play button on top middle of Unity (rounded with red ellipse on fig. 3). You will see a blue empty screen.
Fig. 3. Play button
Just to add some dynamic lets add skybox material and camera rotation effect. This will show that something is happening on our scene.
For this example I use free Skybox Volume 2 material you can download in Unity asset store https://www.assetstore.unity3d.com (fig. 4).
Fig. 4. Skybox Volume 2
To import this texture in Unity press Open in Unity button. New window will be opened in Unity with almost same context you see on web page of asset store. Press download and import button. After download will be completed select all checkboxes in import dialog (fig. 5) and press Import button.
Fig. 5. Skybox import from Unity asset store
To add skybox texture to scene in Edit menu select Render Settings. In Inspector (right side) you will see setting for rendering (fig. 6).
Fig. 6. Render Settings
Press small circle for Skybox Material and select skybox you like. Now press Play button and enjoy beautiful sci-fi style skybox.
Now it is time to add some dynamic: camera rotation effect. From now we will add several javascript files and we will need some folders structure. Right click on Assets in Project tab (left bottom) and select in context menu Create -> Folder. Name this folder Scripts. Select this folder and create three sub folders (fig. 7):
Right click on Effects folder and in context menu select Create -> Javascript. Change name of the script to CameraRotationEffect. Double click this file will open Assembly-UnityScript program that allow you to edit script content. Enter listing 1 content and press save icon on tool bar of the script editing program.
- Effects
- MVC
- StartMenu
Fig. 7. Scripts folders structure
Right click on Effects folder and in context menu select Create -> Javascript. Change name of the script to CameraRotationEffect. Double click this file will open Assembly-UnityScript program that allow you to edit script content. Enter listing 1 content and press save icon on tool bar of the script editing program.
public var time: Time;
public var mainCamera : GameObject;
// This function will be called when scene loaded
function Start () {
// Fixed update will be performed 20 time per second:
time.fixedDeltaTime = 0.05f;
// Getting MainCamera gameobject:
mainCamera = GameObject.Find("Main Camera");
}
// This function will be called every time.fixedDeltaTime
// seconds:
function FixedUpdate () {
// Camera rotation with step 2 * time.deltaTime:
mainCamera.transform.Rotate(0, 2 * time.deltaTime, 0);
}
public var mainCamera : GameObject;
// This function will be called when scene loaded
function Start () {
// Fixed update will be performed 20 time per second:
time.fixedDeltaTime = 0.05f;
// Getting MainCamera gameobject:
mainCamera = GameObject.Find("Main Camera");
}
// This function will be called every time.fixedDeltaTime
// seconds:
function FixedUpdate () {
// Camera rotation with step 2 * time.deltaTime:
mainCamera.transform.Rotate(0, 2 * time.deltaTime, 0);
}
List. 1. Camera rotation effect script
Creating menu UI components
First of all to create a UI components we need create empty GameObject. In menu GameObject select Create Empty. In Hierarchy new GameObject appears. Right click on it and rename to StartMenu. Create javascript file StartMenuController in folder StartMenu, replace it contents with listing 2 and attach this javascript to StartMenu GameObject.
This script currently contains two functions:
// This function called when scene loaded:
function Start () {
// We will put here all initialisation code
}
// This function will draw UI components
function OnGUI () {
// Rendering code
}
function Start () {
// We will put here all initialisation code
}
// This function will draw UI components
function OnGUI () {
// Rendering code
}
List. 2. StartMenuController
This script currently contains two functions:
- Start - called once on scene load
- OnGUI - called every time when UI redraw happends
We can put all rendering stuff in OnGUI function, but we will do in other way. For every screen rendering code will be in separate view class. This makes our code clean. We need an interface all views will implements. To create this interface create new javascript file ViewInterface in MVC folder and put in this file code from listing 3.
// Common view interface:
interface View {
// Rendering UI function:
function render();
// Enable/disable UI components:
function setBlockUI(blockUI);
}
interface View {
// Rendering UI function:
function render();
// Enable/disable UI components:
function setBlockUI(blockUI);
}
Listing 3. View interface
Also we need class that will store login data. Create new javascript file LoginData in folder StartMenu and add listing 4 content to it.
class LoginData {
public var login : String = "";
public var password : String = "";
public function clear() {
login = "";
password = "";
}
}
public var login : String = "";
public var password : String = "";
public function clear() {
login = "";
password = "";
}
}
Listing 4. LoginData class
Now we can add login view that will render GUI components. Create new javascript file in folder StartMenu with name LoginView and replace it's content with code from listing 5.
class LoginView implements View {
public final static var NAME : String = "Login";
public var guiSkin : GUISkin;
public var header1Style : GUIStyle;
public var header2Style : GUIStyle;
public var header2ErrorStyle : GUIStyle;
public var formFieldStyle : GUIStyle;
public var data : LoginData = new LoginData();
public var error = false;
public var errorMessage : String = "";
public var enterGameHandler;
public var openRegistrationHandler;
private var blockUI = false;
function render() {
var screenWidth = Screen.width;
var screenHeight = Screen.height;
var xShift = (screenWidth - 260)/2;
var yShift = (screenHeight - 260)/2;
GUI.skin = guiSkin;
// Disabling UI if blockUI is true:
GUI.enabled = !blockUI;
// Main label:
GUI.Label(Rect(0, yShift, screenWidth, 30), "Welcome to the Game", header1Style);
// Message label:
if(error) {
GUI.Label(Rect(0, yShift + 70, screenWidth, 30), errorMessage, header2ErrorStyle);
} else {
GUI.Label(Rect(0, yShift + 70, screenWidth, 30), "Enter your Login and Password", header2Style);
}
// Login label and login text field:
GUI.Label(Rect(xShift, yShift + 120, 100, 30), "Login:", formFieldStyle);
data.login = GUI.TextField(Rect(xShift + 110, yShift + 120, 150, 30), data.login, 16);
// Password label and password text field:
GUI.Label(Rect(xShift, yShift + 170, 100, 30), "Password:", formFieldStyle);
data.password = GUI.PasswordField(Rect(xShift + 110, yShift + 170, 150, 30), data.password, "*"[0], 16);
// Login button:
if(GUI.Button(Rect(xShift, yShift + 220, 120, 30), "Enter Game")) {
enterGameHandler();
}
// Switch to registration view button:
if(GUI.Button(Rect(xShift + 140, yShift + 220, 120, 30), "Registration")) {
openRegistrationHandler();
}
// Enabling UI:
GUI.enabled = true;
}
public function setBlockUI(blockUI) {
this.blockUI = blockUI;
}
}
public final static var NAME : String = "Login";
public var guiSkin : GUISkin;
public var header1Style : GUIStyle;
public var header2Style : GUIStyle;
public var header2ErrorStyle : GUIStyle;
public var formFieldStyle : GUIStyle;
public var data : LoginData = new LoginData();
public var error = false;
public var errorMessage : String = "";
public var enterGameHandler;
public var openRegistrationHandler;
private var blockUI = false;
function render() {
var screenWidth = Screen.width;
var screenHeight = Screen.height;
var xShift = (screenWidth - 260)/2;
var yShift = (screenHeight - 260)/2;
GUI.skin = guiSkin;
// Disabling UI if blockUI is true:
GUI.enabled = !blockUI;
// Main label:
GUI.Label(Rect(0, yShift, screenWidth, 30), "Welcome to the Game", header1Style);
// Message label:
if(error) {
GUI.Label(Rect(0, yShift + 70, screenWidth, 30), errorMessage, header2ErrorStyle);
} else {
GUI.Label(Rect(0, yShift + 70, screenWidth, 30), "Enter your Login and Password", header2Style);
}
// Login label and login text field:
GUI.Label(Rect(xShift, yShift + 120, 100, 30), "Login:", formFieldStyle);
data.login = GUI.TextField(Rect(xShift + 110, yShift + 120, 150, 30), data.login, 16);
// Password label and password text field:
GUI.Label(Rect(xShift, yShift + 170, 100, 30), "Password:", formFieldStyle);
data.password = GUI.PasswordField(Rect(xShift + 110, yShift + 170, 150, 30), data.password, "*"[0], 16);
// Login button:
if(GUI.Button(Rect(xShift, yShift + 220, 120, 30), "Enter Game")) {
enterGameHandler();
}
// Switch to registration view button:
if(GUI.Button(Rect(xShift + 140, yShift + 220, 120, 30), "Registration")) {
openRegistrationHandler();
}
// Enabling UI:
GUI.enabled = true;
}
public function setBlockUI(blockUI) {
this.blockUI = blockUI;
}
}
Listing 5. LoginView class
Also we need to modify StartMenuController to support this view rendering. Replace content of
StartMenuController file with listing 6.
// Common GUI skin:
public var guiSkin : GUISkin;
// GUI styles for labels:
public var header1Style : GUIStyle;
public var header2Style : GUIStyle;
public var header2ErrorStyle : GUIStyle;
public var formFieldStyle : GUIStyle;
public var errorMessageStyle : GUIStyle;
// Active view name:
var activeViewName : String = LoginView.NAME;
// Map views by name:
var viewByName : Hashtable;
// Login view:
var loginView : LoginView;
// Do we need block UI:
var blockUI = false;
// This function will be called when scene loaded:
function Start () {
// Setup of login view:
loginView.guiSkin = guiSkin;
loginView.header1Style = header1Style;
loginView.header2Style = header2Style;
loginView.header2ErrorStyle = header2ErrorStyle;
loginView.formFieldStyle = formFieldStyle;
viewByName = new Hashtable();
// Adding login view to views by name map:
viewByName[LoginView.NAME] = loginView;
}
// This function will draw UI components
function OnGUI () {
// Getting current view by active view name:
var currentView : View = viewByName[activeViewName];
// Set blockUI for current view:
currentView.setBlockUI(blockUI);
// Rendering current view:
currentView.render();
// Show box with "Wait..." when UI is blocked:
var screenWidth = Screen.width;
var screenHeight = Screen.height;
if(blockUI) {
GUI.Box(Rect((screenWidth - 200)/2, (screenHeight - 60)/2, 200, 60), "Wait...");
}
}
public var guiSkin : GUISkin;
// GUI styles for labels:
public var header1Style : GUIStyle;
public var header2Style : GUIStyle;
public var header2ErrorStyle : GUIStyle;
public var formFieldStyle : GUIStyle;
public var errorMessageStyle : GUIStyle;
// Active view name:
var activeViewName : String = LoginView.NAME;
// Map views by name:
var viewByName : Hashtable;
// Login view:
var loginView : LoginView;
// Do we need block UI:
var blockUI = false;
// This function will be called when scene loaded:
function Start () {
// Setup of login view:
loginView.guiSkin = guiSkin;
loginView.header1Style = header1Style;
loginView.header2Style = header2Style;
loginView.header2ErrorStyle = header2ErrorStyle;
loginView.formFieldStyle = formFieldStyle;
viewByName = new Hashtable();
// Adding login view to views by name map:
viewByName[LoginView.NAME] = loginView;
}
// This function will draw UI components
function OnGUI () {
// Getting current view by active view name:
var currentView : View = viewByName[activeViewName];
// Set blockUI for current view:
currentView.setBlockUI(blockUI);
// Rendering current view:
currentView.render();
// Show box with "Wait..." when UI is blocked:
var screenWidth = Screen.width;
var screenHeight = Screen.height;
if(blockUI) {
GUI.Box(Rect((screenWidth - 200)/2, (screenHeight - 60)/2, 200, 60), "Wait...");
}
}
Listing 6. Modified StartMenuController
Let see what we got. Press play button to switch to game mode. You will see depending on skybox you select something like on fig. 8.
Fig. 8. UI befor styling
All labels are black and almost not visible. We can change it setting style of labels, textfields and buttons. Select StartMenu game object. In Inspector panel you will see next variables:
- Gui Skin - common set of styles
- Header 1Style - defines main label style
- Header 2Style - defines message style
- Header 2Error Style - defines style of message when we need to display an error
- Form Field Style - set styles of fields in forms
Double click on Gui Skin. In Inspector You will see set of UI elements that style you can set using this skin. We need set next UI elements styles:
Button
- Font Size = 16
TextField
- Font Size = 16
- Alignment = Middle Left
Box:
- Normal/Text Color = RGB(255, 211, 211)
- Font Size = 16
- Font Style = Bold
- Normal/Text Color = RGB(255, 40, 40)
- Font Size = 20
- Font Style = Bold
- Normal/Text Color = very light color, I use RGB(131, 255, 219)
- Font Size = 22
- Alignment = Middle Center
Unfold Header 2Style and set next properties:
- Normal/Text Color = very light color, I use RGB(131, 255, 219)
- Font Size = 18
- Alignment = Middle Center
Unfold Header 2Error Style and set next properties:
- Normal/Text Color = very light color with red, I use RGB(255, 93, 93)
- Font Size = 18
- Alignment = Middle Center
Unfold Form Field Style and set next properties:
- Normal/Text Color = very light color, I use white RGB(255, 255, 255)
- Font Size = 16
- Alignment = Middle Right
Unfold Error Message Style and set next properties:
- Normal/Text Color = very light color, I use white RGB(255, 211, 211)
- Font Size = 16
- Font Style = Bold
- Alignment = Upper Left
Fig. 9. After styling
When user press registration button we should switch to registration view. We need create data and view classes for this. In folder StartMenu create RegistrationData javascript and put content of listing 7 in this file.
class RegistrationData {
public var login : String = "";
public var password : String = "";
public var passwordConfirm : String = "";
public var email : String = "";
public function clear() {
login = "";
password = "";
passwordConfirm = "";
email = "";
}
}
public var login : String = "";
public var password : String = "";
public var passwordConfirm : String = "";
public var email : String = "";
public function clear() {
login = "";
password = "";
passwordConfirm = "";
email = "";
}
}
Listing 8. RegistrationData class
Create RegistrationView javascript file in folder StartMenu with content from listing 9.
class RegistrationView implements View {
public final static var NAME : String = "Registration";
public var guiSkin : GUISkin;
public var header2Style : GUIStyle;
public var formFieldStyle : GUIStyle;
public var errorMessageStyle : GUIStyle;
public var error = false;
public var errorMessage : String = "";
public var data : RegistrationData = new RegistrationData();
public var registrationHandler;
public var cancelHandler;
private var blockUI = false;
function render() {
var screenWidth = Screen.width;
var screenHeight = Screen.height;
var xShift = (screenWidth - 360)/2;
var yShift = (screenHeight - 300)/2;
GUI.skin = guiSkin;
// Disable UI in case of blockUI is true or any error:
if(error || blockUI){
GUI.enabled = false;
} else {
GUI.enabled = true;
}
// Message label:
GUI.Label(Rect(0, yShift + 0, screenWidth, 30), "Enter Registration Data", header2Style);
// Login label and text filed:
GUI.Label(Rect(xShift, yShift + 50, 100, 30), "Login:", formFieldStyle);
data.login = GUI.TextField(Rect(xShift + 110, yShift + 50, 250, 30), data.login, 16);
// Password label and text filed:
GUI.Label(Rect(xShift, yShift + 100, 100, 30), "Password:", formFieldStyle);
data.password = GUI.PasswordField(Rect(xShift + 110, yShift + 100, 250, 30), data.password, "*"[0], 16);
// Confirm password label and text filed:
GUI.Label(Rect(xShift - 50, yShift + 150, 150, 30), "Confirm Password:", formFieldStyle);
data.passwordConfirm = GUI.PasswordField(Rect(xShift + 110, yShift + 150, 250, 30), data.passwordConfirm, "*"[0], 16);
// Email label and text filed::
GUI.Label(Rect(xShift, yShift + 200, 100, 30), "Your Email:", formFieldStyle);
data.email = GUI.TextField(Rect(xShift + 110, yShift + 200, 250, 30), data.email, 32);
// Register button:
if(GUI.Button(Rect(xShift + 50, yShift + 250, 120, 30), "Register")) {
registrationHandler();
}
// Cancel button:
if(GUI.Button(Rect(xShift + 190, yShift + 250, 120, 30), "Cancel")) {
cancelHandler();
}
// Enabling UI:
GUI.enabled = true;
// Show errors:
showErrors();
}
// In case of registration error render error window:
private function showErrors() {
if(error) {
var screenWidth = Screen.width;
var screenHeight = Screen.height;
windowRect = GUI.Window (0, Rect((screenWidth - 400)/2, (screenHeight - 300)/2, 400, 300),
renderErrorWindow, "Registration Error");
}
}
// Render error window content:
private function renderErrorWindow(windowId : int) {
GUI.Label(Rect(10, 30, 380, 230), errorMessage, errorMessageStyle);
if(GUI.Button(Rect((400 - 120)/2, 260, 120, 30), "OK")) {
error = false;
errorMessage = "";
}
}
}
public final static var NAME : String = "Registration";
public var guiSkin : GUISkin;
public var header2Style : GUIStyle;
public var formFieldStyle : GUIStyle;
public var errorMessageStyle : GUIStyle;
public var error = false;
public var errorMessage : String = "";
public var data : RegistrationData = new RegistrationData();
public var registrationHandler;
public var cancelHandler;
private var blockUI = false;
function render() {
var screenWidth = Screen.width;
var screenHeight = Screen.height;
var xShift = (screenWidth - 360)/2;
var yShift = (screenHeight - 300)/2;
GUI.skin = guiSkin;
// Disable UI in case of blockUI is true or any error:
if(error || blockUI){
GUI.enabled = false;
} else {
GUI.enabled = true;
}
// Message label:
GUI.Label(Rect(0, yShift + 0, screenWidth, 30), "Enter Registration Data", header2Style);
// Login label and text filed:
GUI.Label(Rect(xShift, yShift + 50, 100, 30), "Login:", formFieldStyle);
data.login = GUI.TextField(Rect(xShift + 110, yShift + 50, 250, 30), data.login, 16);
// Password label and text filed:
GUI.Label(Rect(xShift, yShift + 100, 100, 30), "Password:", formFieldStyle);
data.password = GUI.PasswordField(Rect(xShift + 110, yShift + 100, 250, 30), data.password, "*"[0], 16);
// Confirm password label and text filed:
GUI.Label(Rect(xShift - 50, yShift + 150, 150, 30), "Confirm Password:", formFieldStyle);
data.passwordConfirm = GUI.PasswordField(Rect(xShift + 110, yShift + 150, 250, 30), data.passwordConfirm, "*"[0], 16);
// Email label and text filed::
GUI.Label(Rect(xShift, yShift + 200, 100, 30), "Your Email:", formFieldStyle);
data.email = GUI.TextField(Rect(xShift + 110, yShift + 200, 250, 30), data.email, 32);
// Register button:
if(GUI.Button(Rect(xShift + 50, yShift + 250, 120, 30), "Register")) {
registrationHandler();
}
// Cancel button:
if(GUI.Button(Rect(xShift + 190, yShift + 250, 120, 30), "Cancel")) {
cancelHandler();
}
// Enabling UI:
GUI.enabled = true;
// Show errors:
showErrors();
}
// In case of registration error render error window:
private function showErrors() {
if(error) {
var screenWidth = Screen.width;
var screenHeight = Screen.height;
windowRect = GUI.Window (0, Rect((screenWidth - 400)/2, (screenHeight - 300)/2, 400, 300),
renderErrorWindow, "Registration Error");
}
}
// Render error window content:
private function renderErrorWindow(windowId : int) {
GUI.Label(Rect(10, 30, 380, 230), errorMessage, errorMessageStyle);
if(GUI.Button(Rect((400 - 120)/2, 260, 120, 30), "OK")) {
error = false;
errorMessage = "";
}
}
}
Listing 9. RegistrationView class
We need add support for registration view in StrartMenuController (listing 10):
- create instance of RegistrationView;
- add this instance to viewByName map;
- add hadnler for button Registration on LoginView (openRegistrationHandler) that will switch active view to registration;
- add handler for button Cancel on RegistrationView (cancelHandler) that will switch active view to login;
- also we will clear previouslly entered data in views using clear function.
// Common GUI skin:
public var guiSkin : GUISkin;
// GUI styles for labels:
public var header1Style : GUIStyle;
public var header2Style : GUIStyle;
public var header2ErrorStyle : GUIStyle;
public var formFieldStyle : GUIStyle;
public var errorMessageStyle : GUIStyle;
// Active view name:
var activeViewName : String = LoginView.NAME;
// Map views by name:
var viewByName : Hashtable;
// Login view:
var loginView : LoginView;
// Registration view:
var registrationView : RegistrationView;
// Do we need block UI:
var blockUI = false;
// This function will be called when scene loaded:
function Start () {
// Setup of login view:
loginView.guiSkin = guiSkin;
loginView.header1Style = header1Style;
loginView.header2Style = header2Style;
loginView.header2ErrorStyle = header2ErrorStyle;
loginView.formFieldStyle = formFieldStyle;
// Handler of registration button click:
loginView.openRegistrationHandler = function() {
// Clear reistration fields:
registrationView.data.clear();
// Set active view to registration:
activeViewName = RegistrationView.NAME;
};
// Setup of login view:
registrationView.guiSkin = guiSkin;
registrationView.header2Style = header2Style;
registrationView.formFieldStyle = formFieldStyle;
registrationView.errorMessageStyle = errorMessageStyle;
// Handler of cancel button click:
registrationView.cancelHandler = function() {
// Clear reistration fields:
loginView.data.clear();
// Set active view to registration:
activeViewName = LoginView.NAME;
};
viewByName = new Hashtable();
// Adding login view to views by name map:
viewByName[LoginView.NAME] = loginView;
viewByName[RegistrationView.NAME] = registrationView;
}
// This function will draw UI components
function OnGUI () {
// Getting current view by active view name:
var currentView : View = viewByName[activeViewName];
// Set blockUI for current view:
currentView.setBlockUI(blockUI);
// Rendering current view:
currentView.render();
// Show box with "Wait..." when UI is blocked:
var screenWidth = Screen.width;
var screenHeight = Screen.height;
if(blockUI) {
GUI.Box(Rect((screenWidth - 200)/2, (screenHeight - 60)/2, 200, 60), "Wait...");
}
public var guiSkin : GUISkin;
// GUI styles for labels:
public var header1Style : GUIStyle;
public var header2Style : GUIStyle;
public var header2ErrorStyle : GUIStyle;
public var formFieldStyle : GUIStyle;
public var errorMessageStyle : GUIStyle;
// Active view name:
var activeViewName : String = LoginView.NAME;
// Map views by name:
var viewByName : Hashtable;
// Login view:
var loginView : LoginView;
// Registration view:
var registrationView : RegistrationView;
// Do we need block UI:
var blockUI = false;
// This function will be called when scene loaded:
function Start () {
// Setup of login view:
loginView.guiSkin = guiSkin;
loginView.header1Style = header1Style;
loginView.header2Style = header2Style;
loginView.header2ErrorStyle = header2ErrorStyle;
loginView.formFieldStyle = formFieldStyle;
// Handler of registration button click:
loginView.openRegistrationHandler = function() {
// Clear reistration fields:
registrationView.data.clear();
// Set active view to registration:
activeViewName = RegistrationView.NAME;
};
// Setup of login view:
registrationView.guiSkin = guiSkin;
registrationView.header2Style = header2Style;
registrationView.formFieldStyle = formFieldStyle;
registrationView.errorMessageStyle = errorMessageStyle;
// Handler of cancel button click:
registrationView.cancelHandler = function() {
// Clear reistration fields:
loginView.data.clear();
// Set active view to registration:
activeViewName = LoginView.NAME;
};
viewByName = new Hashtable();
// Adding login view to views by name map:
viewByName[LoginView.NAME] = loginView;
viewByName[RegistrationView.NAME] = registrationView;
}
// This function will draw UI components
function OnGUI () {
// Getting current view by active view name:
var currentView : View = viewByName[activeViewName];
// Set blockUI for current view:
currentView.setBlockUI(blockUI);
// Rendering current view:
currentView.render();
// Show box with "Wait..." when UI is blocked:
var screenWidth = Screen.width;
var screenHeight = Screen.height;
if(blockUI) {
GUI.Box(Rect((screenWidth - 200)/2, (screenHeight - 60)/2, 200, 60), "Wait...");
}
Listing 10. Modified StartMenuController to support RegistrationView
If you press Play button and than press Registration button active view will be switched to registration (fig. 10). If you press Cancel button you will switch back to login.
Fig. 10. Registration form
Interact with HTTP server
Almost all games interact with servers. In this tutorial we also will implements login and registration functionality based on interaction with HTTP server. I create test HTTP server that support this functionality. Read more about test server API at http://unity-test-server.appspot.com.
Login functionality description:
- send login and password entered in LoginView to server using POST method;
- receive response from server in json format;
- if provided credentials is incorrect - we will display error message;
- if provided credentials is correct - we will load second scene.
- send registration data entered in RegistrationView using POST method;
- receive response from server in json format;
- if there is any error - we will display error messages;
- if registration was successful - we will load second scene.
class Response {
public var error = false;
public var message : String = "";
}
public var error = false;
public var message : String = "";
}
Listing 11. Response class
Response from server will be in JSON format. We need parser to convert JSON text into javascript object. In this tutorial we will use parser you can download by this link https://github.com/tonioloewald/jsonparse. Download JSONParse.js file, create Json folder in Asset/Scripts and put downloaded file in this folder.
Separate class LoginService will be responsible for request sending and response parsing. Create this class in StartMenu folder. Content of ServerLogin is in listing 12.
class LoginService {
public final static var LOGIN_URL = "http://unity-test-server.appspot.com/authentication/login";
function sendLoginData(loginData : LoginData, responseHandler) {
var response : Response = new Response();
Debug.Log("Sending login request to " + LOGIN_URL);
// Creating form with login and password fields:
var loginForm = new WWWForm();
loginForm.AddField("login", loginData.login);
loginForm.AddField("password", loginData.password);
// Sending request:
var httpResponse = new WWW(LOGIN_URL, loginForm);
// Waiting for response:
yield httpResponse;
if(httpResponse.error) {
// Error was while connecting/reading response
// from server:
Debug.Log("Error: " + httpResponse.error);
response.error = true;
response.message = "Error: failed connect to server";
} else {
// Response was received:
Debug.Log("Receive response: " + httpResponse.text);
// Parsing response:
var parsed : Boo.Lang.Hash = JSONParse.JSONParse(httpResponse.text);
if(parsed["error"]) {
// Wrong login or password:
Debug.Log("Error: " + parsed["errorMessage"]);
response.error = true;
response.message = parsed["errorMessage"];
} else {
// Correct login and password:
Debug.Log("You are loggin successfully");
response.error = false;
response.message = "";
}
}
// Calling response handler:
responseHandler(response);
}
}
public final static var LOGIN_URL = "http://unity-test-server.appspot.com/authentication/login";
function sendLoginData(loginData : LoginData, responseHandler) {
var response : Response = new Response();
Debug.Log("Sending login request to " + LOGIN_URL);
// Creating form with login and password fields:
var loginForm = new WWWForm();
loginForm.AddField("login", loginData.login);
loginForm.AddField("password", loginData.password);
// Sending request:
var httpResponse = new WWW(LOGIN_URL, loginForm);
// Waiting for response:
yield httpResponse;
if(httpResponse.error) {
// Error was while connecting/reading response
// from server:
Debug.Log("Error: " + httpResponse.error);
response.error = true;
response.message = "Error: failed connect to server";
} else {
// Response was received:
Debug.Log("Receive response: " + httpResponse.text);
// Parsing response:
var parsed : Boo.Lang.Hash = JSONParse.JSONParse(httpResponse.text);
if(parsed["error"]) {
// Wrong login or password:
Debug.Log("Error: " + parsed["errorMessage"]);
response.error = true;
response.message = parsed["errorMessage"];
} else {
// Correct login and password:
Debug.Log("You are loggin successfully");
response.error = false;
response.message = "";
}
}
// Calling response handler:
responseHandler(response);
}
}
Listing 12. LoginService class
We need add one more handler for Login button in StartMenuController javascript file. For this add LoginService variable to StartMenuController file (listing 13):
// Login service:
var loginService : LoginService;
var loginService : LoginService;
Listing 13. LoginService Variable
Add function to file StartMenuController that will process response from server (listing 14):
// Processing login response from HTTP server:
function loginResponseHandler(response : Response) {
blockUI = false;
loginView.error = response.error;
loginView.errorMessage = response.message;
}
function loginResponseHandler(response : Response) {
blockUI = false;
loginView.error = response.error;
loginView.errorMessage = response.message;
}
Listing 14. Login server response handler function
And last step - add handler for Login button in function Start() of StartMenuController (listing 15):
loginView.enterGameHandler = function() {
blockUI = true;
// Sending login request:
StartCoroutine(loginService.sendLoginData(loginView.data,
loginResponseHandler));
};
blockUI = true;
// Sending login request:
StartCoroutine(loginService.sendLoginData(loginView.data,
loginResponseHandler));
};
Listing 15. Login button handler
Press Play button, enter some login and password and press Login button. While you don't have a registered user with login and password you know you will see message "Incorrect login or password".
Now it is time to create RegistrationService that will send data for new user registration and wait for response. In folder StartMenu create javascript file with name RegistrationService. Content of RegistrationService should be replaced with listing 16.
class RegistrationService {
public final static var REGISTRATION_URL = "http://unity-test-server.appspot.com/authentication/register";
public function sendRegistrationData(registrationData : RegistrationData, responseHandler) {
var response : Response = new Response();
Debug.Log("Sending registration request to " + REGISTRATION_URL);
// Setting registration parameters:
var registrationForm = new WWWForm();
registrationForm.AddField("login", registrationData.login);
registrationForm.AddField("password", registrationData.password);
registrationForm.AddField("passwordConfirm", registrationData.passwordConfirm);
registrationForm.AddField("email", registrationData.email);
// Sending request:
var httpResponse = new WWW(REGISTRATION_URL, registrationForm);
// Waiting for response:
yield httpResponse;
if(httpResponse.error) {
// Error was while connecting/reading response from server:
Debug.Log("Error: " + httpResponse.error);
response.error = true;
response.message = "Error: failed connect to server";
} else {
// Response was received:
Debug.Log("Receive response: " + httpResponse.text);
// Parsing response:
var parsed : Boo.Lang.Hash = JSONParse.JSONParse(httpResponse.text);
if(parsed["error"]) {
// Error while login:
Debug.Log("Error: " + parsed["errorMessage"]);
response.error = true;
response.message = parsed["errorMessage"];
} else {
// Registration was successful:
Debug.Log("You was registered successfully");
response.error = false;
response.message = "";
}
}
// Calling response handler:
responseHandler(response);
}
}
public final static var REGISTRATION_URL = "http://unity-test-server.appspot.com/authentication/register";
public function sendRegistrationData(registrationData : RegistrationData, responseHandler) {
var response : Response = new Response();
Debug.Log("Sending registration request to " + REGISTRATION_URL);
// Setting registration parameters:
var registrationForm = new WWWForm();
registrationForm.AddField("login", registrationData.login);
registrationForm.AddField("password", registrationData.password);
registrationForm.AddField("passwordConfirm", registrationData.passwordConfirm);
registrationForm.AddField("email", registrationData.email);
// Sending request:
var httpResponse = new WWW(REGISTRATION_URL, registrationForm);
// Waiting for response:
yield httpResponse;
if(httpResponse.error) {
// Error was while connecting/reading response from server:
Debug.Log("Error: " + httpResponse.error);
response.error = true;
response.message = "Error: failed connect to server";
} else {
// Response was received:
Debug.Log("Receive response: " + httpResponse.text);
// Parsing response:
var parsed : Boo.Lang.Hash = JSONParse.JSONParse(httpResponse.text);
if(parsed["error"]) {
// Error while login:
Debug.Log("Error: " + parsed["errorMessage"]);
response.error = true;
response.message = parsed["errorMessage"];
} else {
// Registration was successful:
Debug.Log("You was registered successfully");
response.error = false;
response.message = "";
}
}
// Calling response handler:
responseHandler(response);
}
}
Listing 16. RegistrationService class
To use registration service we need modify StartMenuController. Add new variable (listing 17). Create handler function that will process registration response (listing 18). Set Register button handler in Start function to perform registration request and response processing (listing 19).
// Registration service:
var registrationService : RegistrationService;
var registrationService : RegistrationService;
Listing 17. RegistrationService Variable
// Processing registration response from HTTP server:
function registrationResponseHandler(response : Response) {
blockUI = false;
registrationView.error = response.error;
registrationView.errorMessage = response.message;
}
function registrationResponseHandler(response : Response) {
blockUI = false;
registrationView.error = response.error;
registrationView.errorMessage = response.message;
}
Listing 18. Registration service response handler function
// Handler of Register button:
registrationView.registrationHandler = function() {
blockUI = true;
// Sending registration request:
StartCoroutine(registrationService.sendRegistrationData(
registrationView.data, registrationResponseHandler));
};
registrationView.registrationHandler = function() {
blockUI = true;
// Sending registration request:
StartCoroutine(registrationService.sendRegistrationData(
registrationView.data, registrationResponseHandler));
};
Listing 19. Register button handler
Finally we can test how it works. Press Play button and switch to registration view by pressing of Registration button. If you left all registration fields empty and press Register you will see error message (fig. 11).
Fig. 11. Registration error
Even if you enter all fields and registration will be successful nothing will happens. You will see same registration form filled with your data.
Loading main game scene after login/registration was successful
One more thing we need to implement is switching to other scene when login or registration was successful. Also we need to identify user that was login to game. For this we will send user login to second (main game) scene and display welcome message to check that data was sent.
To get user login in main scene we need create game object that will survive after main scene will be loaded. For this add new GameObject and name it UserSession.
Create User forled as sub folder of Scripts folder in Assets. We need add two script to this folder:
- UserSession - contains user login (listing 20);
- UserSessionUtils - utilities that allow set/get user login (listing 21).
// User login:
public var userLogin : String;
function Awake() {
// Do not destroy this game object:
DontDestroyOnLoad(this);
}
public var userLogin : String;
function Awake() {
// Do not destroy this game object:
DontDestroyOnLoad(this);
}
Listing 20. UserSession scrip
// User session utils:
class UserSessionUtils {
public static function getUserLogin() {
return findSctiptInGameObject("UserSession",
"UserSession").userLogin;
}
public static function setUserLogin(userLogin : String) { findSctiptInGameObject("UserSession",
"UserSession").userLogin = userLogin;
}
private static function findSctiptInGameObject(
objectName : String, scriptName : String) {
var userSession : GameObject =
GameObject.Find(objectName);
return userSession.GetComponent(scriptName);
}
}
class UserSessionUtils {
public static function getUserLogin() {
return findSctiptInGameObject("UserSession",
"UserSession").userLogin;
}
public static function setUserLogin(userLogin : String) { findSctiptInGameObject("UserSession",
"UserSession").userLogin = userLogin;
}
private static function findSctiptInGameObject(
objectName : String, scriptName : String) {
var userSession : GameObject =
GameObject.Find(objectName);
return userSession.GetComponent(scriptName);
}
}
Listing 21. UserSessionUtils class
Add UserSession script to UserSession game object. You can do it selecting UserSession game object in Hierarchy and press Add Component button in Inspector. After that select Scripts -> User Session.
After success login or registration we need set user login to UserSession game object and load Main scene. To do it we need modify two functions loginResponseHandler and registrationResponseHandler in StartMenuController. Replace content of this functions with listing 22.
// Processing login response from HTTP server:
function loginResponseHandler(response : Response) {
blockUI = false;
loginView.error = response.error;
loginView.errorMessage = response.message;
if(!loginView.error) {
UserSessionUtils.setUserLogin(loginView.data.login);
Application.LoadLevel(1);
}
}
// Processing registration response from HTTP server:
function registrationResponseHandler(response : Response) {
blockUI = false;
registrationView.error = response.error;
registrationView.errorMessage = response.message;
if(!response.error) {
UserSessionUtils.setUserLogin(
registrationView.data.login);
Application.LoadLevel(1);
}
}
function loginResponseHandler(response : Response) {
blockUI = false;
loginView.error = response.error;
loginView.errorMessage = response.message;
if(!loginView.error) {
UserSessionUtils.setUserLogin(loginView.data.login);
Application.LoadLevel(1);
}
}
// Processing registration response from HTTP server:
function registrationResponseHandler(response : Response) {
blockUI = false;
registrationView.error = response.error;
registrationView.errorMessage = response.message;
if(!response.error) {
UserSessionUtils.setUserLogin(
registrationView.data.login);
Application.LoadLevel(1);
}
}
Listing 22. UserSession scrip
Add current scene to build: select Build Setting from File menu. Press Add Current button (fig. 12).
Fig. 12. Adding current scene to build
You can press Build and Run button to see how your project will look in web browser.
Create new scene File -> New Scene. Select some skybox for this scene. You can select skybox for this scene as we do for first scene. If you select other skybox the switching effect will be visible. Save this scene File -> Save Scene As... This will be our main game scene so lets call it Main. Now add this scene to build as we do for StartMenu scene. After that you will have two scenes in your build (fig. 13).
Fig. 13. Adding Main scene into build
Create MainMenu game object and MainMenuController javascript. This script will render simple message "Welcome [user name] to Main Game Scene!". Replace content of MainMenuController with listing 23.
// GUI styles for labels:
public var header1Style : GUIStyle;
// This function will draw UI components
function OnGUI () {
var screenWidth = Screen.width;
var screenHeight = Screen.height;
yShift = (screenHeight - 50)/2;
// Getting user login:
var userLogin : String = UserSessionUtils.getUserLogin();
// Main label:
GUI.Label(Rect(0, yShift, screenWidth, 50), "Welcome " +
userLogin + " to Main Game Scene!", header1Style);
}
// This function will draw UI components
function OnGUI () {
var screenWidth = Screen.width;
var screenHeight = Screen.height;
yShift = (screenHeight - 50)/2;
// Getting user login:
var userLogin : String = UserSessionUtils.getUserLogin();
// Main label:
GUI.Label(Rect(0, yShift, screenWidth, 50), "Welcome " +
userLogin + " to Main Game Scene!", header1Style);
}
Listing 23. MainMenuController scrip
Open first scene File -> Open Scene... and select StartMenu. Press Play button. If you pass login or registration successfully you will see main game scene with welcome message (fig. 14).
Fig. 14. Main game scene with welcome message
Try demo here http://unity-test-server.appspot.com/demo.