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.
Very good! Gonna try it right now! Just as a suggestion, share the complete project so we are able to quickly tweak it. Thanks!
ReplyDeleteThanks for your comments. I upload project zip archive to https://docs.google.com/file/d/0B0HipNssJJD-bEh0Wi1XeV9PSlE/edit
DeleteHave to remove sky box from project to reduce size
Nice tuto
ReplyDeleteYes, Tiagos suggestion would be a plus.
Cool tutorial! Thanks man! Very helpful
ReplyDeleteThanks for the tutorial and the files! Really helpful :)
ReplyDeleteThanx!
ReplyDeleteThe link
"Read more about test server API at http://unity-test-server.appspot.com."
give empty page with "Unity Test Server".
Could you update link, it's important info! Thanx.
Link was updated: you can read breaf information about server API. Thanks for comment
Deletehey great tutorial i was just wondering how to use your own server with this example ??
ReplyDeleteYes, you just need to write your own server. I will upgrade page with server API description. Thanks for comment
DeleteThis comment has been removed by the author.
ReplyDeleteThank you very much for this Tutorial.. Thnx again..!!!!!
ReplyDeleteNice Tutorial
ReplyDeletehttp://3dmodelsudk.blogspot.in/
Many thanks for an amazing tutorial. I am however having the following error:
ReplyDelete"NotImplementedException: The requested feature is not implemented.
RegistrationView.setBlockUI (System.Object blockUI)
StartMenuController.OnGUI () (at Assets/Standard Assets/Scripts/StartMenu/StartMenuController.js:73)"
Can you please advise what I am doing wrong.
Hi, thanks for comment. Try to download source code, there is a link in previous comments.
DeleteThis comment has been removed by the author.
ReplyDeleteThree typos:
ReplyDeleteadd hadnler for button
Create User forled as sub folder
findSctiptInGameObject (should be findScriptInGameObject, although it compiles fine)
this is great i ve done everything that has got to do with the unity part and works fine but what about the web part ?
ReplyDeletehttp://unity-test-server.appspot.com/authentication/register ???
http://unity-test-server.appspot.com/authentication/login ???
how do i do my own part of this ?
To do it you need create a web server that will handle http request for URIs /authentication/register and /authentication/login. You can do it using PHP or Java for example. The reason I did not cover it here - that completelly separate topic. Will try to post one more article to cover this server side part.
Deletecould you make an upload of the webserver so i could add it to my 000webhost please , thanks !
DeleteThe web server is for google application engine (GAE), so you can host it only at GAE. It need some modifications to work standalone not only on GAE cloud platform.
DeleteYou can download project by link: https://docs.google.com/file/d/0B0HipNssJJD-Ukd1ZFZZU2tiNms/edit
This is project for Eclipse. Read here how to install plugin for eclipse: https://developers.google.com/eclipse/docs/download
Great tutorials.
ReplyDeletewill this tutorial work on ios and android ?
I don't test it for ios and android. But probably it will not work. I use functions as callbacks in http services so don't think it will compile in java for android as there is no support for functions callback in java. It is planned for java 8. But most of android sdk versions use java 5.
DeleteGreat tutorial! It helped me out a lot. One small suggestion, you may want to put the link to the source files at the top of the page. I wasted a bit of time copying and pasting until I read the comments. Thanks again!
ReplyDeleteThanks for your comment. Put link at the top of article
DeleteThis comment has been removed by the author.
ReplyDeleteA Very good tutorial and it works when in JavaScript. However, as an exercise, I decided to try different .NET networking methods that are not supported in Javascript. That meant converting the entire project to C#. For the most part I don't have problems, but the button handlers can't be called from the login or registration View classes. For instance the enterGameHandler method is declared as an untyped variable in JavaScript, but that will not work in C#. Do I have to move the handlers back to their respective views?
ReplyDeleteI think the problem is C# djrs not support functions as callbacks. So you need some interface (this is java terms, sorry I don't speak C#) with some onProcess method. Basically you need to replace functions with some interface implementations. And call methods (functions) of this callbacks. Please if it's not clear back to me with your questions.
DeleteThis comment has been removed by the author.
DeletePlease, i need this php
ReplyDeletehttp://unity-test-server.appspot.com/authentication/register ???
http://unity-test-server.appspot.com/authentication/login ???
Sorry but this is java writen for google application engine restful service.
Delete
ReplyDeleteIf you don't stand for something you will fall for anything
Good friends, good books, and a sleepy conscience: this is the ideal life
mutant fighting cup 2 | manny pacquiao | stardew valley wiki | slither.io | powerpuff yourself | zumbi tsunami | fishdom | quotes about love | chinese food near me | snake game
I enjoyed over read your blog post. Your blog have nice information, I got good ideas from this amazing blog. I am always searching like this type blog post. I hope I will see again.
ReplyDeleteswords and souls | strike force kitty 2 | swords and souls game | strikeforce kitty 2
Now an individual can rate areas or firms which they could not ever have looked into. facebook reviews
ReplyDeleteThere's nothing 100 % free in this world, but make sure that you Buy facebook reviews only from the legitimate sources for successful reputation on the web. buy facebook likes reviews
ReplyDeleteLife-time Replacement is something that you rarely find, any time you Buy facebook reviews. Solitary a few decent companies give this. buy facebook review
ReplyDeleteAre you currently searching for ways to get global popularity shortly? You merely require to Buy Facebook Followers to become recognized online. buy followers facebook
ReplyDelete