programming

Unity3D – Tutorials – UI – Responsive Slider

Unity3D – Tutorials – UI – Responsive Slider

The Event System check the user input over the Canvas elements.

This feature is avaiable for Unity3D 4.6 or above.

Create Objects

1. Open Unity3D and create:

– MAIN TOP MENU> GameObject> Camera, name it ‘Main Camera’
– MAIN TOP MENU> GameObject> UI> Slider

NOTICE: Canvas will be created inside Layer UI

NOTICE: In the Hierarchy there is:

– Canvas
-> Slider
->> Background
-> Fill Area
->> Fill
-> Handle Slide Area
->> Handle

– EventSystem

Setup Viewports and Tools

2. 3D Viewport select orthographic X View
3. TOP LEFT> TOOLS> Canvas Manipulation icon
4. Game Viewport> 4:3

Canvas Setup

Hierarchy> Canvas> Inspector>

>Canvas
– Render Mode> Screen Space – Overlay
– Pixel Perfect: check

>Canvas Scaler
– Ui Scale Mode: Scale With Screen Size
– Reference Resolution: 800×600
– Screen Match Mode: Match Width or Height

Slider Setup

Hierarchy> Slider> Inspector>

>Rect Transform>
– Pos X=0 Y=0 Z=0
– Width=800 Height=20 (The same of Canvas Scaler> Reference Resolution)
– Anchor Preset Button (the square icon on top left with a target): middle center

Play and try resize the Game Viewport

Event Listener

1. Hierarchy> select Slider> Inspector> Slider (Script)> +>
– Interactible> check (true)
– DRAG AND DROP into empty slot> Main Camera
– ON THE RIGHT rollout> Camera> fieldOfView

2. Slider (Script)> Min Value=1 Max Value=179

Eligible Functions

Functions that return a FLOAT value

Slider as Energy Bar – Graphic Setup

Hierarchy> Canvas> Slider> Background> uncheck, it removes the background OR simple change color to green

Hierarchy> Canvas> Slider> Fill Area> Fill> change color to red

Hierarchy> Canvas> Slider> Handle Slide Area> Handle> uncheck, it removes the handle

Slider as Energy Bar – JS

Slider (Script)> Interactable> uncheck (false)

1. Hierarchy> Slider> Add Component> New Script> EnergyBar.js


#pragma strict

var theSliderComponent : UI.Slider; // ASSIGN IN INSPECTOR!!!

function Awake () {
}

function Start () {
}

function Update () {
theSliderComponent.value = Mathf.MoveTowards (theSliderComponent.value, 100.0f,0.15f);
}

2. Hierarchy DRAG AND DROP Slider over Inspector> EnergyBar.js> var theSliderComponent

3. Play :)

By |Unity3D, Video Games Development|Commenti disabilitati su Unity3D – Tutorials – UI – Responsive Slider

Unity3D – Tutorials – UI – Responsive BG Image Setup

Unity3D – Tutorials – UI – Responsive BG Image Setup

This feature is avaiable for Unity3D 4.6 or above.

Create Objects

1. Open Unity3D and create:

– MAIN TOP MENU> GameObject> Camera, name it ‘Main Camera’
– MAIN TOP MENU> GameObject> UI> Canvas
– MAIN TOP MENU> GameObject> UI> Image

NOTICE: Canvas will be created inside Layer UI

NOTICE: In the Hierarchy there is:
– Canvas
-> Image (it is the child of Canvas)

Setup Viewports and Tools

2. 3D Viewport select orthographic X View
3. TOP LEFT> TOOLS> Canvas Manipulation icon
4. Game Viewport> 4:3

Setup Canvas

5. Hierarchy> Canvas> Inspector>

Canvas>
– Render Mode: ScreenSpace – Overlay (you will see the button over 3D scene)
– Pixel Perfect: check

Setup BG Image – Single – No Free Aspect

This setup will work fine only with Fixed Aspect

Canvas Scaler>
– Ui Scale Mode> Scale with Screen Size
– Reference Resolution: 800×600 (Remember that Game Viewport is set at 4:3)
E’ solo una unità di riferimento, non sono pixel, ci baseremo su questo parametro per settare i parametri di Rect Transform
– Screen Match Mode: Match Width or Height

NOTE: Pixel Perfect means when displaying a 2D texture, each pixel in the texture is represented by only one pixel on the screen. When you want your 2D-displayed textures to look their best, this is often what is strived for.

0. Project Window> RMB> Import New Asset…> myimage.jpg> Inspector> Texture Type> Sprite (2D and UI)

1. Hiearchy> Image> Inspector

> DRAG AND DROP myimage.jpg over Image (Script)> Source Image slot

> Rect Transform
– Anchor Preset Button (the square icon on top left with a target): middle center
– Anchors: Min X=0.5 Y=0.5 Max X=0.5 Y=0.5 Pivot X=0.5 Y=0.5
– Pos X=0 Y=0 Z=0
– Width= 800 Height= 600 (Remember: Canvas> Reference Resolution: 800×600)

> Image (Script)
– Image Type: Simple

2. Play and try to resize the game port.

Setup BG Image – Tiled – Yes Free Aspect – 1st Solution

This setup will work fine with Free Aspect

Canvas Scaler>
– Ui Scale Mode> Constant Physical Size

NOTE: Pixel Perfect means when displaying a 2D texture, each pixel in the texture is represented by only one pixel on the screen. When you want your 2D-displayed textures to look their best, this is often what is strived for.

0. Project Window> RMB> Import New Asset…> myimage.jpg> Inspector> Texture Type> Sprite (2D and UI)

1. Hiearchy> Image> Inspector

> DRAG AND DROP myimage.jpg over Image (Script)> Source Image slot

> Rect Transform
– Anchor Preset Button (the square icon on top left with a target): middle center
– Anchors: Min X=0.5 Y=0.5 Max X=0.5 Y=0.5 Pivot X=0.5 Y=0.5
– Pos X=0 Y=0 Z=0
– Width= 800 Height= 600 (Remember: Canvas> Reference Resolution: 800×600)

> Image (Script)
– Image Type: Tiled

> Rect Transform
– Scale: setup the size of the tiles

2. Play and try to resize the game port.

Setup BG Image – Tiled – Yes Free Aspect – 2nd Solution

Create in the scene:

1. MAIN TOP MENU> GameObject> UI> Panel

2. Inspector> Panel> Image (Script)>
– Source Image> DRAG AND DROP the sprite here
– Image Type> Tiled

Setup Alpha

Hierarchy> Image> Inspector> Image (Script)> Color> click over the color slot> in the color picker setup Alpha Channel using the slider A

Multi Image Setup

1. MAIN TOP MENU> GameObject> UI> Image add two or more images at the Canvas

2. Hiearchy>

– Canvas
-> Image 1
->> Image 2 (Image 2 is over Image 1)

OR

– Canvas
-> Image 2
->> Image 1 (Image 1 is over Image 2)

By |Unity3D, Video Games Development|Commenti disabilitati su Unity3D – Tutorials – UI – Responsive BG Image Setup

Unity3D Tutorials – Multiplayer Introduction

Unity3D Tutorials – Multiplayer Introduction

In this article I discuss how to create a simple multiplayer game using a Windows Home Network and 2 PC.
First we need some basic concept about Network and Networking.

Network Computing – Basic Concepts

A Network of PC
To create a network we need 2 or more PC connected with a Router using a LAN cable.

The simplest network is:

PC1 <-> Router <-> PC2

The router is a networking device that forwards data packets between computer networks.

Network Software Setup

If you use Windows7 is very simple setup a Home Network, go to Start button> ‘Control Panel’ and typing homegroup in the search box, and then clicking HomeGroup. After that Windows7 assigns a dynamic IP adress to every PC connected on the network.

An IP adress is a adress that uniquely identifies that individual host maschine inside the network.
An IP adress can be:
– Dynamic, the router assigns automatically a different IP number to every PC connected
– Static, you can manually assign the IP number to your PC

The final resul will be:

PC1(IP 192.168.1.10) <-> Router <-> PC2(IP 192.168.1.11)

IP Private – IP Public & NAT

The most common form of network translation involves a large private network using addresses in a private range (10.0.0.0 to 10.255.255.255, 172.16.0.0 to 172.31.255.255, or 192.168.0 0 to 192.168.255.255). The private addressing scheme works well for computers that only have to access resources inside the network, like workstations needing access to file servers and printers. Routers inside the private network can route traffic between private addresses with no trouble.

However, to access resources outside the network, like the Internet, these computers have to have a public address in order for responses to their requests to return to them. This is where NAT (Network Address Translation) comes into play.
A workstation inside a network makes a request to a computer on the Internet. Routers within the network recognize that the request is not for a resource inside the network, so they send the request to the firewall. The firewall sees the request from the computer with the internal IP. It then makes the same request to the Internet using its own public address, and returns the response from the Internet resource to the computer inside the private network. From the perspective of the resource on the Internet, it is sending information to the address of the firewall. From the perspective of the workstation, it appears that communication is directly with the site on the Internet. When NAT is used in this way, all users inside the private network access the Internet have the same public IP address when they use the Internet. That means only one public addresses is needed for hundreds or even thousands of users.

The scheme is:

PC1(IP Private) | <->
PC2(IP Private) | <->
PC2(IP Private) | <-> Router <-> Firewall (NAT) assign one IP Public <-> Internet
PC2(IP Private) | <->
PC2(IP Private) | <->

Ports

In computer networking, a port is an application-specific or process-specific software construct serving as a communications endpoint in a computer’s host operating system. The purpose of ports is to uniquely identify different applications or processes running on a single computer and thereby enable them to share a single physical connection to a packet-switched network like the Internet. In the context of the Internet Protocol, a port is associated with an IP address of the host, as well as the type of protocol used for communication.

An example for the use of ports is the Internet mail system. A server used for sending and receiving email generally needs two services. The first service is used to transport email to and from other servers. This is accomplished with the Simple Mail Transfer Protocol (SMTP). The SMTP service application usually listens on TCP port 25 for incoming requests. The second service is usually either the Post Office Protocol (POP) or the Internet Message Access Protocol (IMAP) which is used by e-mail client applications on user’s personal computers to fetch (recuperare) email messages from the server. The POP service listens on TCP port number 110.

The well-known ports (also known as system ports) are those from 0 through 1023.

Very popular are:

20 & 21: File Transfer Protocol (FTP)
22: Secure Shell (SSH)
23: Telnet remote login service
25: Simple Mail Transfer Protocol (SMTP)
53: Domain Name System (DNS) service
80: Hypertext Transfer Protocol (HTTP) used in the World Wide Web
110: Post Office Protocol (POP3)
119: Network News Transfer Protocol (NNTP)
143: Internet Message Access Protocol (IMAP)
161: Simple Network Management Protocol (SNMP)
194: Internet Relay Chat (IRC)
443: HTTP Secure (HTTPS)
465: SMTP Secure (SMTPS)

The registered ports are those from 1024 through 49151.

The scheme is:

External application <-> Router IP/Port <-> destination in network IP/Port

Port 25001 is default port for Unity3D game engine networking, UDP protocol.

Game Network approches

There are two common and proven approaches to structuring a network game which are known as Authoritative Server and Non-Authoritative Server.

The authoritative server approach requires the server to perform all world simulation, application of game rules and processing of input from the player clients.

A non-authoritative server does not control the outcome of every user input. The clients themselves process user input and game logic locally, then send the result of any determined actions to the server. The server then synchronizes all actions with the world state. This is easier to implement from a design perspective, as the server really just relays messages between the clients and does no extra processing beyond what the clients do.

Methods of Network Communication

How clients and servers can talk to each other?

There are two relevant methods: Remote Procedure Calls and State Synchronization. It is not uncommon to use both methods at different points in any particular game.

Remote Procedure Calls (RPCs) are used to invoke functions on other computers across the network, although the “network” can also mean the message channel between the client and server when they are both running on the same computer. Clients can send RPCs to the server, and the server can send RPCs to one or more clients. Most commonly, they are used for actions that happen infrequently. For example, if a client flips a switch to open a door, it can send an RPC to the server telling it that the door has been opened. The server can then send another RPC to all clients, invoking their local functions to open that same door. They are used for managing and executing individual events.

State Synchronization is used to share data that is constantly changing. The best example of this would be a player’s position in an action game. The player is always moving, running around, jumping, etc. All the other players on the network, even the ones that are not controlling this player locally, need to know where he is and what he is doing. By constantly relaying data about this player’s position, the game can accurately represent that position to the other players.

Minimizing Network Bandwidth

When working with State Synchronization across multiple clients, you don’t necessarily need to synchronize every single detail in order to make objects appear synchronized. For example, when synchronizing a character avatar you only need to send its position and rotation between clients.

For example, you know that assets like textures and meshes exist on all installations and they usually don’t change, so they will never have to be synchronized.

Bear in mind that you can use a single RPC call with a level name to make all clients load the entire specified level and add their own networked elements automatically. Structuring your game to make each client as self-sufficient as possible will result in reduced bandwidth.

Server Physical Location

The physical location and performance of the server itself can greatly affect the playability of a game running on it. Clients which are located a continent away from the server may experience a great deal of lag.

Unity 3D – State Synchronization

For this Unity3D tutorial I am going to work with a simple Home Network created with Windows7.

1. Create a scene with:
– Main Camera
– Cube, Pos XYZ 0,0.5,0 – Scale xYZ 1,1,1
– Plane, Pos XYZ 0,0,0 – Scale xYZ 10,10,10
– Directional Light
– Empty Object, name it ‘NetworkController’

2. Attach to the Cube, Movement.js


#pragma strict
 
function Start () {
 
}
 
function Update () {
 
 var horiz : float = Input.GetAxis("Horizontal"); // get AD buttons input
 var vert : float = Input.GetAxis("Vertical");    // get WS buttons input
 transform.Translate(Vector3(horiz,0,vert));      // move along X -> AD and Z -> WS
}

3. Attach to NetworkController, NetworkManagerScript.js


#pragma strict

var btnX:float; // Buttons Setup
var btnY:float;
var btnW:float;
var btnH:float;

function Start () {
	btnX = Screen.width * 0.05; // Buttons Setup
	btnY = Screen.width * 0.05; // Dimension based on Screen.width
	btnW = Screen.width * 0.2;
	btnH = Screen.width * 0.2;

}

function startServer() {
        // This machine will be the sever
        // Initialize the server, number of allowed connection 32, listenport 25001, NOT have a public IP Adress
	Network.InitializeServer(32,25001, !Network.HavePublicAddress);
}

// Called when Network.InitializeServer was invoked and has completed.
function OnServerInitialized() {
	Debug.Log("Server Initialized");
}

function OnGUI() {
	if(GUI.Button(Rect(btnX, btnY,btnW,btnH),"Start Server")){
	Debug.Log("Starting Server");
	startServer();
	}
	
	if(GUI.Button(Rect(btnX, btnY*1.2+btnH,btnW,btnH),"Refresh Hosts")){
	Debug.Log("Refreshing");
	
	}
}

function Update () {

}

Play, in the console you will receive the message ‘Sever Initialized’
Good! Now my Unity3D application is the Server.

Next, improve NetworkManagerScript.js


#pragma strict

var gameName: String = "MyFirstNetGame"; 

private var btnX:float; // Buttons Setup
private var btnY:float;
private var btnW:float;
private var btnH:float;

function Start () {
	btnX = Screen.width * 0.05; // Buttons Setup
	btnY = Screen.width * 0.05; // Dimension based on Screen.width
	btnW = Screen.width * 0.2;
	btnH = Screen.width * 0.2;

}

function startServer() {
        // This machine will be the Server
        // Initialize the server, number of allowed connection 32, listenport 25001, NOT have a public IP Adress
	Network.InitializeServer(32,25001, !Network.HavePublicAddress);
	
	// Register this server on the master server 
	// The Master Server is a meeting place that puts game instances in touch with the player clients who want to connect to them. 
	// Each individual running game instance provides a Game Type to the Master Server
	//(gameTypeName: string, gameName: string, comment: string = "")
	MasterServer.RegisterHost(gameName, "My Game Name", "This is a comment");
}

// Called when Network.InitializeServer was invoked and has completed.
function OnServerInitialized() {
	Debug.Log("Server Initialized");
}

// Called on clients or servers when reporting events from the MasterServer
function OnMasterServerEvent(mse:MasterServerEvent){
        // check if registration is ok
	if (mse == MasterServerEvent.RegistrationSucceeded){
	Debug.Log("Registrered Server!");
	}
}

function OnGUI() {
	if(GUI.Button(Rect(btnX, btnY,btnW,btnH),"Start Server")){
	Debug.Log("Starting Server");
	startServer();
	}
	
	if(GUI.Button(Rect(btnX, btnY*1.2+btnH,btnW,btnH),"Refresh Hosts")){
	Debug.Log("Refreshing");
	
	}
}

function Update () {

}

Play it, you will get in console “Server Initialized -> Registrered Server!”

For italian people: come funziona?

1. Network.InitializeServer(32,25001, !Network.HavePublicAddress);
Inizializza l’applicazione Server attraverso il network, identifica IP, la porta, il numero massimo di connessioni ammesse.

2. MasterServer.RegisterHost(gameName, “My Game Name”, “This is a comment”);
Il MasterServer è il punto di incontro tra i vari Clients, quindi registriamo presso il MasterServer l’applicazione con un identificativo di tipo, nome e un commento.

Next, improve NetworkManagerScript.js


#pragma strict

var gameName: String = "MyFirstNetGame"; 
private var refreshing: boolean;
private var hostData: HostData[];

private var btnX:float; // Buttons Setup
private var btnY:float;
private var btnW:float;
private var btnH:float;

function Start () {
	btnX = Screen.width * 0.05; // Buttons Setup
	btnY = Screen.width * 0.05; // Dimension based on Screen.width
	btnW = Screen.width * 0.2;
	btnH = Screen.width * 0.2;

}

function startServer() {
    // This machine will be the Server
    // Initialize the server, number of allowed connection 32, listenport 25001, NOT have a public IP Adress
	Network.InitializeServer(32,25001, !Network.HavePublicAddress);
	
	// Register this server on the master server 
	// The Master Server is a meeting place that puts game instances in touch with the player clients who want to connect to them. 
	// Each individual running game instance provides a Game Type to the Master Server
	//(gameTypeName: string, gameName: string, comment: string = "")
	MasterServer.RegisterHost(gameName, "My Game Name", "This is a comment");
} // END startServer

function refreshHostList() {
    // check the number of hosts registered in MasterServer
    // controlla il numero di applicazioni registrate in MasterServer con 'gameName'
    // la registrazione al MasterServer può richiedere dai 3 ai 6 secondi
	MasterServer.RequestHostList(gameName);
	refreshing = true;
} // END refreshHostList

// Called when Network.InitializeServer was invoked and has completed.
function OnServerInitialized() {
	Debug.Log("Server Initialized");
}// END OnServerInitialized

// Called on clients or servers when reporting events from the MasterServer
function OnMasterServerEvent(mse:MasterServerEvent){
    // check if registration is ok
	if (mse == MasterServerEvent.RegistrationSucceeded){
	Debug.Log("Registrated Server!");
	}
}

// GUI Graphic User Interface
function OnGUI() {
//  if your peer type is NOT client AND is NOT server, cioè se non è già connnesso
// questo if fa scomparire i bottoni una volta cliccato su 'Start Server'
if (!Network.isClient && !Network.isServer){
	if(GUI.Button(Rect(btnX, btnY,btnW,btnH),"Start Server")){
	Debug.Log("Starting Server");
	startServer();
	}
	
	if(GUI.Button(Rect(btnX, btnY*1.2+btnH,btnW,btnH),"Refresh Hosts")){
	Debug.Log("Refreshing");
	refreshHostList();
	}
	
	// se esistono dei gameName registrati su MasterServer
	if (hostData){
		// visualizza un array di bottoni con tutti i gameName registrati come MasterServer
		for(var i:int = 0; i<hostData.length; i++){
		    // se viene premuto il bottone
			if (GUI.Button(Rect(btnX*1.5 + btnW, btnY*1.2 + (btnH * i),btnW*3, btnH*0.5), hostData[i].gameName)){
				// Connect to the specified host (ip or domain name) and server port
				// Example: Network.Connect("127.0.0.1", 25000)
				Network.Connect(hostData[i]);
			}
		}
	}
}	
}// END OnGUI

function Update () {
    // se refreshing è true, cioè ho cliccato sul bottone 'Refresh Hosts'
	if (refreshing) {
		// se c'è almeno una registrazione
		if (MasterServer.PollHostList().Length > 0)  {
		// disabilita il refreshing per evitare che continui ad eseguirlo ad ogni ciclo Update
		refreshing = false;
		Debug.Log(MasterServer.PollHostList().Length);
		// array con tutte le registrazioni al MasterServer
		hostData = MasterServer.PollHostList();
		}	
	}// END Refreshing

}// END Update

For italia people: come funziona?

1. Inseriamo in un array – private var hostData: HostData[] – tutte le connessioni registrare nel MasterServer
2. Con un ciclo for le visualizzo utilizzando una grafica composta di bottoni – (var i:int = 0; iTestBuild.exe

1. MAIN TOP MENU> Edit> Project Settings> Player> Inspector> Settings for PC Mac LinuX Standalone> Run in Background: check

L’applicazione deve essere attiva in background perchè deve continuare ad inviare dati al MasterServer anche quando non lo stiamo utilizzando.
Se così non fosse ogni volta che usciamo dal gioco, lasciandolo attivo nella barra di windows, la connessione con il MasterServer andrebbe persa.
Con l’applicazione settata per funzionare in background invece posso lasciare il gioco attivo, utilizzare un’altra applicazione e tornare al gioco senza dover di nuovo effettuare la procedura di registrazione al MasterServer.

2. MAIN TOP MENU> File> Buil Settings…> PC Mac Linux Standalone> Build, TestBuild.exe

a. Run the standalone build, click ‘Start Server’, the buttons will disapper
b. Play inside Unity3D the Project> click ‘Refresh Hostst’, you will see the registered host, yeah it works!

For italian people: come funziona?
a. Creo un buil stand alone e l’avvio, questa crea il MasterServer e si registra presso il MasterServer come client
b. Avvio da Unity3D il progetto, cliccando su’Refresh Hosts’ osservo che effettivamente la build standalone funziona ed è reistrata presso il MasterServer.
c. Posso provare a chiedere TestBuild.exe e riavviare il progetto su Unity3D, cliccare su ‘Refresh Hosts’, nessun applicazione risulterà registrata a MasterServer

Network View Component

1. Hierarchy> select Cube (our player)> Inspector > ‘Add Component’> Miscellaneous> Network View:

– State Syncronization: Reliable Delta Compressed
The difference between the last state and the current state will be sent, if nothing has changed nothing will be sent.

– Observed: Cube(Transform)
The Component data that will be sent across the network

‘Network Views’ are the gateway to creating networked multiplayer games in Unity.

New TestBuild.exe

1. Save the scene and the project
2. Build and run the standalone exe, press ‘Start Server’, all buttons disappear.
3. Play inside Unity3D the Project> click ‘Refresh Hosts’, the button ‘Tutorial Game Name’ appears, press it to starl this client, all buttons disappear.
4. Jump to standalone exe, move the Cube using the arrow key. In the Unity Game window you will see the cube goes all around!

For italian people: come funziona?

1. Primo eseguibile: premendo ‘Start Server’ questa applicazione funzionerà da Server e in più si registrerà come client
2. Secondo eseguibile: facendo un refresh degli hosts si visualizza il Server attualmente registrato (il primo eseguibile)
3. Secondo eseguibile: facendo click sul nome del Server si registra il secondo eseguibile come client
Se si tenta di far partire il server dal secondo eseguibile si riceverà la risposta che il server è già stato avviato.

The Player is mine!

A this point in time both players can move the same cube… mmm… it sounds strange…

Let’s take a look to the new Movement.js


#pragma strict
 
function Start () {
 
}// END Start()
 
function Update () {
 
 var horiz : float = Input.GetAxis("Horizontal"); // get AD buttons input
 var vert : float = Input.GetAxis("Vertical");    // get WS buttons input
 
 // Solo il server, cioè quello che parte per primo potrà spostare il cubo
 // Object instanted by me
 if (networkView.isMine){
 		transform.Translate(Vector3(horiz,0,vert));      // move along X -> AD and Z -> WS
	}
}// END Update()

For italian people: come funziona?
1. Il primo eseguibile che viene avviato genera l’oggetto e diventa di sua proprietà – networkView.isMine –
2. Solo se l’oggetto è di mia proprietà puoi muoverlo
3. Il secondo eseguibile può solo assistere al movimento del cubo senza poter inviare dei comandi

Spawn Player

1. Add to NetworkManagerScript.js the code:


...

var playerPrefab: GameObject;
var spawnObject: Transform;

...

function spawnPlayer() {
	Network.Instantiate(playerPrefab, spawnObject.position, Quaternion.identity, 0);
}

// Called when Network.InitializeServer was invoked and has completed.
function OnServerInitialized() {
	Debug.Log("Server Initialized");
	spawnPlayer();
}// END OnServerInitialized

function OnConnectedToServer() {
	spawnPlayer();
}

...

2. DRAG ANG DROP the Cube from Hierarchy to Project, it will become a Prefab

3. Hierarchy> select Cube and press CANC on the keyboard

4. MAIN TOP MENU> GameObject> Create Empty, name it SpawnPoint, position it in the point where the Cube will appear.

5a. DRAG AND DROP Hierarchy> SpawnPoint over NetworkController> NetworkManagerScript> var spawnObject
5b. DRAG AND DROP Project> Cube over NetworkController> NetworkManagerScript> var playerPrefab

6. Add to NetworkManagerScript.js the code:


...

 if (networkView.isMine){
 		transform.Translate(Vector3(horiz,0,vert));      // move along X -> AD and Z -> WS
	} else {
	enabled = false;
	}
}// END Update()

...

For italian people: come funziona?
1. Trasformo il Cubo che rappresenta il nostro player in un Prefab e poi lo cancello dalla scena rimuovendolo da Hierarchy
2. Aggiungo un oggetto vuoto per segnare la posizione di generazione del Cubo
3. Con la modifica effettuata al codice ogni client genera il proprio Cubo, mi devo ricordare di assegnare in Inspector il Prefab che rappresenta il player e l’oggetto Empty che rappresenta la posizione in cui il player sarà generato.
5. In comune resta solo l’ambientazione costituita dal piano e dalla luce
6a. spawnPlayer() viene richiamata all’inizializzazione del server – OnServerInitialized() – per l’eseguibile server
6b. spawnPlayer() viene richiamata all’inizializzazione del client – OnConnectedToServer() – per l’eseguibile client
7. Se l’oggetto non è mio, disabilitalo – enabled = false; –

Unity 3D – RPC

0. Project> select the Cube> Add Component> Physic> Rigid Body> check ‘Is Kinematic’
NOTE: Without Rigid Body Component collisions will not be detected!

1. MAIN TOP MENU> GameObject> 3D Object> Sphere> Inspector> Collider> check ‘Is Trigger’, move it at Position X=-3 Y=0 Z=0

2. Attach to the Sphere, SphereScript.js


#pragma strict

function Start () {
}

function Update () {
}

function OnTriggerEnter (other : Collider) {
		Debug.Log("Collision detected!");
		renderer.material.color = Color(1,0,0,1);
}// END OnTriggerEnter

3. Play, ‘Start the Server’, move the Cube to collide with the Sphere, the Sphere will change color to red.

4. Hierarchy> select the Sphere> Inspector> ‘Add Component’> Miscellaneus> Network View:
– State Syncronization: Off, it is ideal for RPC
– Observed: None

Change SphereScript.js as:


function OnTriggerEnter () {
	Debug.Log("Collision detected!");	
	var newCol:Vector3 = Vector3(1,0,0);
	// Is sends the function SetColor(), to everyone and adds to the buffer
	networkView.RPC("SetColor",RPCMode.AllBuffered, newCol);
}// END OnTriggerEnter

// RPC Tag
@RPC
function SetColor(newColor:Vector3) {
	renderer.material.color = Color(newColor.x,newColor.y,newColor.z,1);
}// END SetColor()

For italian peolple: come funziona?
1. Non abbiamo bisogno di controllare costantemente il colore della sfera con una comunicazione di tipo Inspector> NetworkView> StateSyncronization, che viene disabilitata.
2. Operiamo il cambio di colore solo se c’è la collisione, quindi selezioniamo un metodo RPC
3. – networkView.RPC(“SetColor”,RPCMode.AllBuffered, newCol); – segnala a tutti i client connessi di avviare la funzione – SetColor() – che cambia il colore ad ogni sfera in ogni client connesso.
4. In definitiva posso avviare i 2 eseguibili, ogni giocatore muoverà il suo player (Cube) e il primo che arriva alla sfera gli farà cambiare colore in rosso.

Final Overview

Now a final overview:

Hierarchy:

– Main Camera
– Sphere (it is the goal to reach)
– Plane
– Directional Light
– NetworkController (Empty)
– SpawnPoint (Empty, give the PosXYZ to spawn Cube)

Project:

– Cube (prefab, It is our Player)
– Scene
– Scripts

Particular Components List:

– NetworkController (Empty)
— NetworkManagerScript.js to manage Server and Client

– Cube (prefab, It is our Player)
— Rigid Body – is kinematic
— Box Collider
— MovementScript,js to move the cube
— NetworkView – State Syncronization Reliable Delta Compressed

– Sphere (it is the goal to reach)
— Sphere Collider – is Trigger
— SphereScript.js to cahnge its color
— NetworkView – StateSyncronization None becuase it use RPC communication inside SphereScript.js

The final scripts:

Movement.js


#pragma strict
 
function Start () {
 
}// END Start()
 
function Update () {
 
 var horiz : float = Input.GetAxis("Horizontal"); // get AD buttons input
 var vert : float = Input.GetAxis("Vertical");    // get WS buttons input
 
 // Solo il server, cioè quello che parte per primo potrà spostare il cubo
 // Object instanted by me
 if (networkView.isMine){
 		transform.Translate(Vector3(horiz,0,vert));      // move along X -> AD and Z -> WS
	} else {
	enabled = false;
	}
}// END Update()

NetworkManagerScript.js


#pragma strict

var playerPrefab: GameObject;
var spawnObject: Transform;

var gameName: String = "MyFirstNetGame"; 

private var refreshing: boolean;
private var hostData: HostData[];

private var btnX:float; // Buttons Setup
private var btnY:float;
private var btnW:float;
private var btnH:float;

function Start () {
	btnX = Screen.width * 0.05; // Buttons Setup
	btnY = Screen.width * 0.05; // Dimension based on Screen.width
	btnW = Screen.width * 0.2;
	btnH = Screen.width * 0.2;

}

function startServer() {
    // This machine will be the Server
    // Initialize the server, number of allowed connection 32, listenport 25001, NOT have a public IP Adress
	Network.InitializeServer(32,25001, !Network.HavePublicAddress);
	
	// Register this server on the master server 
	// The Master Server is a meeting place that puts game instances in touch with the player clients who want to connect to them. 
	// Each individual running game instance provides a Game Type to the Master Server
	//(gameTypeName: string, gameName: string, comment: string = "")
	MasterServer.RegisterHost(gameName, "My Game Name", "This is a comment");
} // END startServer

function refreshHostList() {
    // check the number of hosts registered in MasterServer
    // controlla il numero di applicazioni registrate in MasterServer con 'gameName'
    // la registrazione al MasterServer può richiedere dai 3 ai 6 secondi
	MasterServer.RequestHostList(gameName);
	refreshing = true;
} // END refreshHostList

function spawnPlayer() {
	Network.Instantiate(playerPrefab, spawnObject.position, Quaternion.identity, 0);
}

// Called when Network.InitializeServer was invoked and has completed.
function OnServerInitialized() {
	Debug.Log("Server Initialized");
	spawnPlayer();
}// END OnServerInitialized

function OnConnectedToServer() {
	spawnPlayer();
}

// Called on clients or servers when reporting events from the MasterServer
function OnMasterServerEvent(mse:MasterServerEvent){
    // check if registration is ok
	if (mse == MasterServerEvent.RegistrationSucceeded){
	Debug.Log("Registrated Server!");
	}
}

// GUI Graphic User Interface
function OnGUI() {
//  if your peer type is NOT client AND is NOT server, cioè se non è già connesso
// questo if fa scomparire i bottoni una volta cliccato su 'Start Server'
if (!Network.isClient && !Network.isServer){
	if(GUI.Button(Rect(btnX, btnY,btnW,btnH),"Start Server")){
	Debug.Log("Starting Server");
	startServer();
	}
	
	if(GUI.Button(Rect(btnX, btnY*1.2+btnH,btnW,btnH),"Refresh Hosts")){
	Debug.Log("Refreshing");
	refreshHostList();
	}
	
	// se esistono dei gameName registrati su MasterServer
	if (hostData){
		// visualizza un array di bottoni con tutti i gameName registrati come MasterServer
		for(var i:int = 0; i<hostData.length; i++){
		    // se viene premuto il bottone
			if (GUI.Button(Rect(btnX*1.5 + btnW, btnY*1.2 + (btnH * i),btnW*3, btnH*0.5), hostData[i].gameName)){
				// Connect to the specified host (ip or domain name) and server port
				// Example: Network.Connect("127.0.0.1", 25000)
				Network.Connect(hostData[i]);
			}
		}
	}
}	
}// END OnGUI

function Update () {
    // se refreshing è true, cioè ho cliccato sul bottone 'Refresh Hosts'
	if (refreshing) {
		// se c'è almeno una registrazione
		if (MasterServer.PollHostList().Length > 0)  {
		// disabilita il refreshing per evitare che continui ad eseguirlo ad ogni ciclo Update
		refreshing = false;
		Debug.Log(MasterServer.PollHostList().Length);
		// array con tutte le registrazioni al MasterServer
		hostData = MasterServer.PollHostList();
		}	
	}// END Refreshing

}// END Update

SphereScript.js


function OnTriggerEnter () {
	Debug.Log("Collision detected!");	
	var newCol:Vector3 = Vector3(1,0,0);
	// Is sends the function SetColor(), to everyone and adds to the buffer
	networkView.RPC("SetColor",RPCMode.AllBuffered, newCol);
}// END OnTriggerEnter

// RPC Tag
@RPC
function SetColor(newColor:Vector3) {
	renderer.material.color = Color(newColor.x,newColor.y,newColor.z,1);
}// END SetColor()

That’s all folks!

NOTE: You will notice a small delay between the input and the actual movement, this is because the position is updated after the new data is received. All we can do is predict what is going to happen based on the old data.

One method to predict the next position is by taking the velocity into account. A more accurate end position can be calculated by adding the velocity multiplied by the delay.

See the lesson 2 about Multiplayer – Latency Compensating Methods at:
http://www.lucedigitale.com/blog/unity3d-tutorials-multiplayer-latency-compensating-methods/

My official website: http://www.lucedigitale.com

References:

– http://docs.unity3d.com/Manual/net-HighLevelOverview.html
– http://www.inetdaemon.com/tutorials/internet/ip/whatis_ip_network.shtml
– http://whatismyipaddress.com/nat
– http://vimeo.com/33996023#
– http://www.paladinstudios.com/2013/07/10/how-to-create-an-online-multiplayer-game-with-unity/

Extra resources:

– http://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
– http://developer.valvesoftware.com/wiki/Lag_Compensation
– http://developer.valvesoftware.com/wiki/Working_With_Prediction
– http://www.gamasutra.com/resource_guide/20020916/lambright_01.htm

By |Unity3D, Video Games Development|Commenti disabilitati su Unity3D Tutorials – Multiplayer Introduction

CSharp – Namespace

CSharp – Namespace

Defining a namespace

Con la keyword ‘namespace’ possiamo definire un set di ‘nomi’ riservati ad un determinato scopo comune.
All’interno di un ‘namespace’ ci posso essere classi, funzioni e variabili.

Syntax:

...
// Define a namespace
namespace namespace_name
{
   // code declarations
}
....
// Call a namespace
namespace_name.item_name;
...

Example:


using System;
namespace first_space
{
   class namespace_cl
   {
      public void func()
      {
         Console.WriteLine("Inside first_space");
      }
   }
}
namespace second_space
{
   class namespace_cl
   {
      public void func()
      {
         Console.WriteLine("Inside second_space");
      }
   }
}   
class TestClass
{
   static void Main(string[] args)
   {
      // dichiaro fc di tipo classe namespace_cl() prelevata dal namespace first_space
      first_space.namespace_cl fc = new first_space.namespace_cl();
      // dichiaro sc di tipo classe namespace_cl() prelevata dal namespace second_space
      second_space.namespace_cl sc = new second_space.namespace_cl();
      // avvia le funzioni prelevate dal namespace first_space
      fc.func();
      // avvia le funzioni prelevate dal namespace second_space
      sc.func();
      // aspetto che l'utente interagisca con la tastiera prima di chiudere la finestra
      Console.ReadKey();
   }
}

The result is:

Inside first_space
Inside second_space

using

Con la keyword ‘using’ indichiamo al compilatore che il codice che scriveremo userà i ‘nomi’ specificati nel ‘namespace’ indicato.
In questo modo siamo in grado di scrivere codice più compatto.

In C# lo utilizziamo nelle applicazioni console per indicare al compilatore che utilizziamo il namespace ‘using System;’ fornito da Microsoft.

using System;
Console.WriteLine ("Hello there");

è equivalente a:

System.Console.WriteLine("Hello there");

Vediamo un esempio con un namespace creato da noi:


using System;
using first_space;
using second_space;

namespace first_space
{
   class abc
   {
      public void func()
      {
         Console.WriteLine("Inside first_space");
      }
   }
}
namespace second_space
{
   class efg
   {
      public void func()
      {
         Console.WriteLine("Inside second_space");
      }
   }
}   
class TestClass
{
   static void Main(string[] args)
   {
      abc fc = new abc();
      efg sc = new efg();
      fc.func();
      sc.func();
      Console.ReadKey();
   }
}

The result is:

Inside first_space
Inside second_space

Notare come è stato sufficiente scrivere:

abc fc = new abc(); // dichiaro che fc è tipo classe abc
fc.func(); // richiamo la funzione

invece di:

first_space.namespace_cl fc = new first_space.namespace_cl();
fc.func();

Molto più breve e merno soggetto a errori di battitura.

By |CSharp|Commenti disabilitati su CSharp – Namespace

CSharp – Static Polymorphism – Function Overloading

CSharp – Static Polymorphism – Function Overloading

Polymorphism is a Greek word that means “many-shaped”
With Function Overloading you can have multiple definitions for the same function name in the same scope.
Same name for the function, many-shaped variables.


using System;

namespace ConsoleApplication1
{

    class Printdata
    {
        void print(int i)
        {
            Console.WriteLine("Printing int: {0}", i);
        }

        void print(double f)
        {
            Console.WriteLine("Printing float: {0}", f);
        }

        void print(string s)
        {
            Console.WriteLine("Printing string: {0}", s);
        }
        static void Main(string[] args)
        {
            Printdata p = new Printdata();
            // Call print to print integer
            p.print(5);
            // Call print to print float
            p.print(500.263);
            // Call print to print string
            p.print("Hello C++");
            Console.ReadKey();
        }
    }

}

The result is:

Printing int: 5
Printing float: 500.263
Printing string: Hello C++

For italian people: come funziona?
C# distingue automaticamente la funzione chiamata in base alle variabili che gli vengono spedite, quindi:
p.print(5); -> void print(int i)
p.print(500.263); -> void print(double f)
p.print(“Hello C++”); -> void print(string s)

By |CSharp|Commenti disabilitati su CSharp – Static Polymorphism – Function Overloading