csharp

Create OnLine Multiplayer Games – Unity3D – Photon PUN – C#

Create OnLine Multiplayer Games – Unity3D – Photon PUN – C#

How specialized services impacted my game development?

To create an online multiplayer game you need a cloud service specialized in gaming.

Manage a multiplayer game is very different than create a web site o simple saving scores inside a MySQL database.

Obstacles to overcome are many:

a. LAG: it is a noticeable delay between the action of players and the reaction of the server.

– It may occur due to insufficient processing power in the server.

– It may occur because of the network latency between a player’s computer (client), and the game server. To improve ping you have to consider the physical location of the server. Clients which are located a continent away from the server may experience a great deal of lag.

b. Cross-Platform: will your game run over different platform? PC, XBox, PS3…

c. Scalability: today you have 100 players, if you are luck tomorrow they will be 100.000 :)

d. Integration with your game framework; if it is possible we would like to develop without pain 😛

e. Integration with the management of player accounts, data storage, social tools, push notification.

f. Integration with the management of virtual goods as vanity items, power enhancements, boosts, consumables.

Ok, then now we have realized that with a specialized service will be much easier develop our games!

Photon PUN Plans

The service Photon PUN is available at: https://www.exitgames.com/en/PUN

Photon have 80.000 developers and top developers also, as Square Enix, Warner Bros Games and others.

The PUN API is very similar to Unity’s networking solution.

Photon Cloud’s hosting centers in US, Europe, Asia (Singapore, Japan) & Australia provide low latency for your games all over the world.

At the moment we have 2 PUN plans:

a. PUN FREE (https://www.assetstore.unity3d.com/en/#!/content/1786)

– Unity free license: no Android and IOS export
– Unity Pro: yes Android and IOS

– included FREE Photon Cloud plan

– included 20 CCU Subscription life-time – 8k;
CCU is concurrent users worldwide for that game id/account.
‘Concurrent users’ refers to the total number of people using the resource within predefined period of time.
In plain words you can develop an RPG and run 1 dungeon with 20 heroes or 2 dungeon with 10 heroes at the same time. Others players stand in queue.

b. PUN PLUS (https://www.assetstore.unity3d.com/en/#!/content/12080 – 95 USD)

– Unity free license: yes Android and IOS export
– Unity Pro: yes Android and IOS

– included 100 CCU Subscription life-time – 40k;

– ‘Ultimate FPS’ integrated (First person shooter framework)

– ‘PlayMaker’ integrated (Quickly make gameplay prototype)

Other plans:

You can upgrade from PUN FREE and PUN PLUS

– 95 USD for 100 CCU life-time – 40k; for example 10 rooms with 10 players in every room at the same time.

– 89 USD/monthly for 500 CCU – 200k;

– 169 USD/monthly for 1000 CCU;

– Overage, CCU Burst: you can exceed your CCU limit and optionally upgrade, so you don’t need to worry about your users losing out on service. Apps and licenses exceeding limits longer than 48 hours will be capped at their plan’s CCU.

Photon Server Side Options

Exit Games Cloud

– It provides hosted Photon Servers for you, fully managed by Exit Games.
– The server can not be authoritative.
– The clients need to be authoritative.
– Clients are identified by “application id”, with ‘game title’ and ‘version’ included.

Photon Server SDK

– You can run your own server and develop server side logic
– The server can be authoritative
– The clients can be authoritative.
– Full control of the server logic.

PUN Network Logic

PUN network logic is well organized, see the scheme below:

Client -> Master Server -> send to address
-> Game Server, game Rooms here
-> Game Server, game Rooms here
-> Game Server, game Rooms here

The individual matches are known as Rooms and are grouped into one or multiple lobbies.

My Game
-> | Lobby1 -> Room1, Room2, Room3
-> | Lobby2 -> Room4, Room5, Room6
-> | Lobby3 -> Room7, Room8, Room9

Multiple lobbies mean the clients get shorter rooms lists. There is no limit to the rooms lists.
If you don’t use custom lobbies explicitly, PUN will use a single lobby for all rooms.

Random matchmaking: it will try to join any room and fail if none has room for another player.
If fails it will create a room without name and wait until other players join it randomly.

Player resquest a matchmaking -> if Room exists -> join it
-> if Room not exist -> create a Room and wait another player

Room properties are synced to all players in the room (current map, round, starttime…).

Offline mode: it is a feature to be able to re-use your multiplayer code in singleplayer game modes as well.
PhotonNetwork needs to be able to distinguish erroneous from intended behaviour.
Using this feature you can reuse certain multiplayer methods without generating any connections and errors.

The cure is simple:

PhotonNetwork.offlineMode = true;

Photon Unity Networking (PUN) VS Unity Networking (UN)

a. Host model: using standard UN, if the player who creates the room (host) leave, the room will crash with all clients. Photon is server-client based as well, but has a dedicated server; No more dropped connections due to hosts leaving.

b. Connectivity: Unity networking works with NAT punch-through to try to improve connectivity: since players host the network servers, the connection often fails due to firewalls/routers etc…
Photon has a dedicated server, there is no need for NAT punch-through or other concepts. Connectivity is a guaranteed 100%.

c. Photon is specialized to provide rooms, matchmaking and in-room communication between players.

NOTE: the matchmaking is a system that finds 2 or more players to play a match. An example, in a MMORPG there are doungeons you can play only with a party. In front of the entrance you will press the button ‘Matchmaking’, the message will be send over the server and others players will join your team. If there is no players after 5 minutes your request will be erased.

To know more about UN see me article about using UN at:
http://www.lucedigitale.com/blog/unity3d-tutorials-multiplayer-introduction/

PUN Installation

1. Download fron Asset Store ‘Photon Cloud Free’
You can find it C:\Utenti\mycomputername\AppData\Roaming\Unity\Asset Store\Exit Games\ScriptingNetwok\Photon Unity Networking Free.unitypackage

2. Go to https://www.exitgames.com/en/PUN and register with your email

3. You will receive a first email, follow the link and create a password

4. You will receive a second email, follow the link ‘Your first Photon Realtime application is already setup in your account.’, get your Application Id

5. Unity3D> MAIN TOP MENU> Window> Photon Unity Networking> PUN Wizard> Settings ‘Setup’> I am already signed up. Let me enter my AppId ‘Setup’> Your AppId>
a. copy here your AppId
b. Cloud Region: eu (example: Europe)
c. Save

Project> Photon Unity Networking> Resources> PhotonServerSettings> Inspector, here your setup.

I found the next code in Paladin Studio’s website, and it was very useful for me, I ‘ll try to explain it in a different way.

I choose C# language istead of JS because Photon PUN is written in C#. You can use JS, if you like, but you will lose some features.
If you can not live without JS :) please read PUN manuals, the installation is slightly different.
To use JS, you’ll need to move the Photon Unity Networking \Plugins folder to the root of your project.

NetworkManger.cs

Create a scene with:
– Main Camera
– Directional Light
– Plane (as ground)
– NetworkController (Empty Object), attach NetworkManager.cs

NetworkManager.cs


using UnityEngine;
using System.Collections;

public class NetworkManager : MonoBehaviour {
	
	// Use this for initialization
	void Start () {
		// Connect to Photon (game version)
		PhotonNetwork.ConnectUsingSettings("0.1");
	}// END Start

	void OnGUI()
	{
		// Message: ConnectingMasterServer -> Authentication -> JoinedLobby
		GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString());
	}
	
	// Update is called once per frame
	void Update () {
		
	}// END Update
}

After the connection has been established, we need to create and connect to a Room.


using UnityEngine;
using System.Collections;

public class NetworkManager : MonoBehaviour {

	private const string roomName = "RoomName"; // Create a Room
	private RoomInfo[] roomsList; // Array of Rooms

	// Use this for initialization
	void Start () {
		// Connect to Photon (game version)
		PhotonNetwork.ConnectUsingSettings("0.1");
	}// END Start


	void OnGUI()
	{
		if (!PhotonNetwork.connected) // se la connessione è andata a buon fine
		{
			// Message: ConnectingMasterServer -> Authentication -> JoinedLobby
			GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString());
		}
		else if (PhotonNetwork.room == null) // se non esiste una Room
		{
			// Create Room
			if (GUI.Button(new Rect(100, 100, 250, 100), "Start Server"))
                                // CreateRoom (string roomName, bool isVisible, bool isOpen, int maxPlayers)
                                // Creates a room with given name but fails if this room is existing already. 
				PhotonNetwork.CreateRoom(roomName, true, true, 5);
			
			// Join Room
			if (roomsList != null) // se esiste una Room
			{
				for (int i = 0; i < roomsList.Length; i++)
				{
					if (GUI.Button(new Rect(100, 250 + (110 * i), 250, 100), "Join " + roomsList[i].name))
					// JoinRoom (string roomName, bool createIfNotExists)	
					PhotonNetwork.JoinRoom(roomsList[i].name);
				}
			}
		}
	}// END OnGUI()
	
	void OnReceivedRoomListUpdate()
	{
		// Get Room list
		roomsList = PhotonNetwork.GetRoomList();
	}// END OnReceivedRoomListUpdate()

	void OnJoinedRoom()
	{
		// Connected!
		Debug.Log("Connected to Room");
	}// END OnJoinedRoom()
	
	// Update is called once per frame
	void Update () {
		
	}// END Update
}

Stay focus on ‘PhotonNetwork.CreateRoom(roomName, true, true, 5);’:
– roomName Unique name of the room to create. Pass null or “” to make the server generate a name.
– isVisible Shows (or hides) this room from the lobby’s listing of rooms.
– isOpen Allows (or disallows) others to join this room.
– maxPlayers Max number of players that can join the room.
Creates a room with given name but fails if this room is existing already.

After that PhotonNetwork.GetRoomList();:
gets currently known rooms as RoomInfo array.

After that PhotonNetwork.JoinRoom(roomsList[i].name);:
JoinRoom() -> success calls OnJoinedRoom().
JoinRoom() -> fails if the room is either full or no longer available.

Ok, build it and let’s try!
1. Run the first executable on your 1st PC, press “Start Server”, this creates the server RoomName.
2. Run a second executable on your 2nd PC, press “RoomName”, this joins as client into RoomName

1rs .exe -> create the room
2nd .exe -> join the room

For italian people: come funziona?

1. Stabilisco una connessione con i server di Photon – PhotonNetwork.ConnectUsingSettings(“0.1”); –

2. Se è riuscita invio dei messaggi di connessione – GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString()); –

3. Ricevo in continuazione la lista delle Room disponibili – OnReceivedRoomListUpdate() –

3a. Se non esiste una Room – if (PhotonNetwork.room == null) – visualizza il bottone per avviare il Server – “Start Server” –
3b. Se esiste una una Room – (roomsList != null) – visualizza il bottone “Start Server” e il bottone con il nome dalla Room

4. Se premo il bottone “Start Server” creo la Room che farà da hosting

5. Se premo il bottone “RoomName” entro come client nella Room creata nel punto 4.

6. Controllo se sono riuscito ad entrare nella Room – OnJoinedRoom() – se ci riesco scrivo in console – Debug.Log(“Connected to Room”); –

Player

1. MAIN TOP MENU> GameObject> 3D Object> Cube> Inspector> Transform X=0 Y=0.5 Z=0, attach Player.cs
2. ProjecT> Cube> Inspector> ‘Add Component’> Physic> RigidBody

PlayerScript.cs


using UnityEngine;
using System.Collections;

public class PlayerScript : MonoBehaviour {

	public float speed = 10f;
	
	void Update()
	{
		InputMovement();
	}
	
	void InputMovement()
	{
		if (Input.GetKey(KeyCode.W))
			rigidbody.MovePosition(rigidbody.position + Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.S))
			rigidbody.MovePosition(rigidbody.position - Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.D))
			rigidbody.MovePosition(rigidbody.position + Vector3.right * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.A))
			rigidbody.MovePosition(rigidbody.position - Vector3.right * speed * Time.deltaTime);
	}
}


The player will use classic ‘WASD’ keyboard key controls to move the Cube.

a. Execute the 1st game, move the Cube using ‘WASD’ and press “Start Server”
b. Execute the 2nd game, move the Cube using ‘WASD’ and press “RoomName”
1st and 2nd join in the same room but they can’t see each other.

‘Photon View’ will send data to the server to synchronize the player.

3. ProjecT> Cube> Inspector> ‘Add Component’> Photon Networking> Photon View (C#)

– Observe option: ‘Reliable Delta Compressed’, data will be sent automatically, but only if its value changed, it is ‘State Synchronization’ method.
– Observed Components: DRAG AND DROP here Cube> Transform component
– Transform Serialization: Only Position

4. Project> create a folder ‘Resources’> DRAG AND DROP here from Hierarchy> Cube
Cube will turn in prefab, after that delete Hierarchy> Cube to remove it from the scene.
Instantiating on a Photon network requires the prefab to be placed in the Resources folder.

6. Improving NetworkManager.cs


using UnityEngine;
using System.Collections;

public class NetworkManager : MonoBehaviour {

	private const string roomName = "RoomName"; // Create a Room
	private RoomInfo[] roomsList; // Array of Rooms

	public GameObject playerPrefab; // Assign in Inspector

	// Use this for initialization
	void Start () {
		// Connect to Photon (game version)
		PhotonNetwork.ConnectUsingSettings("0.1");
	}// END Start


	void OnGUI()
	{
		if (!PhotonNetwork.connected) // se la connessione è andata a buon fine
		{
			// Message: ConnectingMasterServer -> Authentication -> JoinedLobby
			GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString());
		}
		else if (PhotonNetwork.room == null) // se non esiste una Room
		{
			// Create Room
			if (GUI.Button(new Rect(100, 100, 250, 100), "Start Server"))
				PhotonNetwork.CreateRoom(roomName, true, true, 5);
			
			// Join Room
			if (roomsList != null) // se esiste una Room
			{
				for (int i = 0; i < roomsList.Length; i++)
				{
					if (GUI.Button(new Rect(100, 250 + (110 * i), 250, 100), "Join " + roomsList[i].name))
						PhotonNetwork.JoinRoom(roomsList[i].name);
				}
			}
		}
	}// END OnGUI()
	
	void OnReceivedRoomListUpdate()
	{
		// Get Room list
		roomsList = PhotonNetwork.GetRoomList();
	}// END OnReceivedRoomListUpdate()

	void OnJoinedRoom()
	{
		// Connected!
		Debug.Log("Connected to Room");

		// Spawn player
		PhotonNetwork.Instantiate(playerPrefab.name, Vector3.up * 5, Quaternion.identity, 0);
	}// END OnJoinedRoom()
	
	// Update is called once per frame
	void Update () {
		
	}// END Update
}

Notice:

...
public GameObject playerPrefab; // Assign in Inspector
...
void OnJoinedRoom()
	{
		// Connected!
		Debug.Log("Connected to Room");

		// Spawn player
		PhotonNetwork.Instantiate(playerPrefab.name, Vector3.up * 5, Quaternion.identity, 0);
	}/
...

Projects> Resources> Cube DRAG AND DROP NetworkController> Network Manager (Script)> Player Prefab var

Create 2 builds and play them:

1rs .exe -> create the room
2nd .exe -> join the room
1rs .exe -> WASD move all cubes
2nd .exe -> WASD move all cubes

Ops! There is an error, but we can fix it easy :)

We are going to check Cube, it has to receive WASD input only from the .exe that instantiated the object.

7. Improving PlayerScript.cs


using UnityEngine;
using System.Collections;

public class PlayerScript : Photon.MonoBehaviour {

	public float speed = 10f;
	
	void Update()
	{
		if (photonView.isMine)
		InputMovement();
	}
	
	void InputMovement()
	{
		if (Input.GetKey(KeyCode.W))
			rigidbody.MovePosition(rigidbody.position + Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.S))
			rigidbody.MovePosition(rigidbody.position - Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.D))
			rigidbody.MovePosition(rigidbody.position + Vector3.right * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.A))
			rigidbody.MovePosition(rigidbody.position - Vector3.right * speed * Time.deltaTime);
	}
}


Notice:

...
public class PlayerScript : Photon.MonoBehaviour {
...
if (photonView.isMine)
InputMovement();
...

a. We load – Photon.MonoBehaviour not MonoBehaviour –
b. Move the player only if is mine!

Create 2 builds and play them:

1rs .exe -> create the room
2nd .exe -> join the room
1rs .exe -> WASD move 1st cube
2nd .exe -> WASD move 2nd cube

We have got it!

Personalized State Synchronization

1. Project> Resources> Cube> Photon View (Script)> Observed Components> DRAG AND DROP here Inspector> Cube> Player Script.cs
Transform components will be overwritten.

2. We can write our own synchronization method in PlayerScript.cs:


using UnityEngine;
using System.Collections;

public class PlayerScript : Photon.MonoBehaviour {

	public float speed = 10f;

	// It is automatically called every time it either sends or receives data
	void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
	{
		// If the user is the one updating the object, he writes to the stream.
		// This occurs automatically based on the sendrate
		if (stream.isWriting)
		{
			// It sends the rigidbody’s position with stream.SendNext()
			stream.SendNext(rigidbody.position);
		}
		else
		{
			// this is received by the clients with stream.ReceiveNext()
			rigidbody.position = (Vector3)stream.ReceiveNext();
		}
	}

	void Update()
	{
		if (photonView.isMine)
		InputMovement();
	}
	
	void InputMovement()
	{
		if (Input.GetKey(KeyCode.W))
			rigidbody.MovePosition(rigidbody.position + Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.S))
			rigidbody.MovePosition(rigidbody.position - Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.D))
			rigidbody.MovePosition(rigidbody.position + Vector3.right * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.A))
			rigidbody.MovePosition(rigidbody.position - Vector3.right * speed * Time.deltaTime);
	}
}


Notice:


// It is automatically called every time it either sends or receives data
	void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
	{
		// If the user is the one updating the object, he writes to the stream.
		// This occurs automatically based on the sendrate
		if (stream.isWriting)
		{
			// It sends the rigidbody’s position with stream.SendNext()
			stream.SendNext(rigidbody.position);
		}
		else
		{
			// this is received by the clients with stream.ReceiveNext()
			rigidbody.position = (Vector3)stream.ReceiveNext();
		}
	}

For italian people: come funziona?
Scrivere uno ‘State Synchronization’ personalizzato ci permette di avere maggior controllo sui parametri che vogliamo inviare in sincronizzazione, slegandoci dall’utilizzo dei soli componenti già pronti. Nel caso sopra visivamente il risultato sarà lo stesso ma invece di inviare il componente ‘Transform’ invio i dati di posizione tramite un componente ‘Script’, specificando via codice esattamente cosa inviare. Con questo sistema posso inviare qualsiasi dato che io possa codificare in uno script, ad esempio una funzione personalizzata per gestire un inventario o lo sblocco di una porta o le caratteristiche di un armamento in un gioco sparatutto.

Interpolation

Have you noticed the LAG? There is a delay between the action of players and the reaction of the server, this happens because the position is updated after the new data is received.

MAIN TOP MENU> Edit> Project Settings > Network> Send Rate: 15
The standard settings in Unity3D is that a package is being tried to send 15 times per second, but our eyes are faster than 15 fps and we will see the LAG! It is not a good practice use a greater value than 15, because we have to optimized the data will send thought the network.

To smooth the transition from the old to the new data values and fix these latency issues, interpolation can be used.

In computer animation, interpolation is inbetweening, or filling in frames between the key frames. It typically calculates the in between frames through use of (usually) piecewise polynomial interpolation to draw images semi-automatically.

We will interpolate between the current position and the new position received after synchronization.

Improving PlayerScript.cs


using UnityEngine;
using System.Collections;

public class PlayerScript : Photon.MonoBehaviour {

	public float speed = 10f;

	private float lastSynchronizationTime = 0f;
	private float syncDelay = 0f;
	private float syncTime = 0f;
	private Vector3 syncStartPosition = Vector3.zero;
	private Vector3 syncEndPosition = Vector3.zero;

	// It is automatically called every time it either sends or receives data
	void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
	{
		// If the user is the one updating the object, he writes to the stream.
		// This occurs automatically based on the sendrate
		if (stream.isWriting)
		{
			// It sends the rigidbody’s position with stream.SendNext()
			stream.SendNext(rigidbody.position);
		}
		else
		{
			// this is received by the clients with stream.ReceiveNext()
			syncEndPosition = (Vector3)stream.ReceiveNext();
			syncStartPosition = rigidbody.position;
			
			syncTime = 0f;
			syncDelay = Time.time - lastSynchronizationTime;
			lastSynchronizationTime = Time.time;
		}
	}

	void Update()
	{
		if (photonView.isMine)
		{
			InputMovement();
		}
		else
		{
			SyncedMovement();
		}
	}

	private void SyncedMovement()
	{
		syncTime += Time.deltaTime;
		rigidbody.position = Vector3.Lerp(syncStartPosition, syncEndPosition, syncTime / syncDelay);
	}
	
	void InputMovement()
	{
		if (Input.GetKey(KeyCode.W))
			rigidbody.MovePosition(rigidbody.position + Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.S))
			rigidbody.MovePosition(rigidbody.position - Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.D))
			rigidbody.MovePosition(rigidbody.position + Vector3.right * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.A))
			rigidbody.MovePosition(rigidbody.position - Vector3.right * speed * Time.deltaTime);
	}
}


Notice:


...

private float lastSynchronizationTime = 0f;
	private float syncDelay = 0f;
	private float syncTime = 0f;
	private Vector3 syncStartPosition = Vector3.zero;
	private Vector3 syncEndPosition = Vector3.zero;
...

else
			// this is received by the clients with stream.ReceiveNext()
			syncEndPosition = (Vector3)stream.ReceiveNext();
			syncStartPosition = rigidbody.position;
			
			syncTime = 0f;
			syncDelay = Time.time - lastSynchronizationTime;
			lastSynchronizationTime = Time.time;
...

else
		{
			SyncedMovement();
		}
	}

	// Movimento sincronizzato
	private void SyncedMovement()
	{
		syncTime += Time.deltaTime;
		// calculate the interpolation - Lerp interpolates between from and to by the fraction t
		rigidbody.position = Vector3.Lerp(syncStartPosition, syncEndPosition, syncTime / syncDelay);
	}
...

Prediction

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.

Improving PlayerScript.cs


using UnityEngine;
using System.Collections;

public class PlayerScript : Photon.MonoBehaviour {

	public float speed = 10f;

	private float lastSynchronizationTime = 0f;
	private float syncDelay = 0f;
	private float syncTime = 0f;
	private Vector3 syncStartPosition = Vector3.zero;
	private Vector3 syncEndPosition = Vector3.zero;

	// It is automatically called every time it either sends or receives data
	void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
	{
		// If the user is the one updating the object, he writes to the stream.
		// This occurs automatically based on the sendrate
		if (stream.isWriting)
		{
			// It sends the rigidbody’s position with stream.SendNext()
			stream.SendNext(rigidbody.position);
			stream.SendNext(rigidbody.velocity);
		}
		else
		{
		Vector3 syncPosition = (Vector3)stream.ReceiveNext();
		Vector3 syncVelocity = (Vector3)stream.ReceiveNext();
		
		syncTime = 0f;
		syncDelay = Time.time - lastSynchronizationTime;
		lastSynchronizationTime = Time.time;
		
		syncEndPosition = syncPosition + syncVelocity * syncDelay;
		syncStartPosition = rigidbody.position;
		}
	}

	void Update()
	{
		if (photonView.isMine)
		{
			InputMovement();
		}
		else
		{
			SyncedMovement();
		}
	}

	// Movimento sincronizzato
	private void SyncedMovement()
	{
		syncTime += Time.deltaTime;
		// calculate the interpolation - Lerp interpolates between from and to by the fraction t
		rigidbody.position = Vector3.Lerp(syncStartPosition, syncEndPosition, syncTime / syncDelay);
	}
	
	void InputMovement()
	{
		if (Input.GetKey(KeyCode.W))
			rigidbody.MovePosition(rigidbody.position + Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.S))
			rigidbody.MovePosition(rigidbody.position - Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.D))
			rigidbody.MovePosition(rigidbody.position + Vector3.right * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.A))
			rigidbody.MovePosition(rigidbody.position - Vector3.right * speed * Time.deltaTime);
	}
}

Notice:


void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
	{
		// If the user is the one updating the object, he writes to the stream.
		// This occurs automatically based on the sendrate
		if (stream.isWriting)
		{
			// It sends the rigidbody’s position with stream.SendNext()
			stream.SendNext(rigidbody.position);
			stream.SendNext(rigidbody.velocity);
		}
		else
		{
		Vector3 syncPosition = (Vector3)stream.ReceiveNext();
		Vector3 syncVelocity = (Vector3)stream.ReceiveNext();
		
		syncTime = 0f;
		syncDelay = Time.time - lastSynchronizationTime;
		lastSynchronizationTime = Time.time;
		
		syncEndPosition = syncPosition + syncVelocity * syncDelay;
		syncStartPosition = rigidbody.position;
		}
	}

Remote Procedure Calls (RPCs) – photonView.RPC()

RPCs is the best choice when data does not constantly change.
For example you will use RPC when an enemy explode or you get the flag of opponents.

To better understand:

Player’s position -> change constantly -> State Synchronization
Enemy’s explosion -> change only one time -> RPCs

RPCs sends thought the network less data than State Synchronization and we like that!

RPCs is only able to send integers, floats, strings, vectors and quaternions.
To send other data you can convert it before sending, for example a color can be send by converting it to a vector or quaternion.

photonView.RPC() can send to:
– Server: it sends data to Server only. (no buffered)
– Others: it sends data to everyone on the server except yourself. (yes buffered)
– All: it sends data to everyone. (yes buffered)

If buffered the data will be storaged in RAM and newly connected players receiving all these buffered values.

Improving PlayerScript.cs


using UnityEngine;
using System.Collections;

public class PlayerScript : Photon.MonoBehaviour {

	public float speed = 10f;

	private float lastSynchronizationTime = 0f;
	private float syncDelay = 0f;
	private float syncTime = 0f;
	private Vector3 syncStartPosition = Vector3.zero;
	private Vector3 syncEndPosition = Vector3.zero;

	// It is automatically called every time it either sends or receives data
	void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
	{
		// If the user is the one updating the object, he writes to the stream.
		// This occurs automatically based on the sendrate
		if (stream.isWriting)
		{
			// It sends the rigidbody’s position with stream.SendNext()
			stream.SendNext(rigidbody.position);
			stream.SendNext(rigidbody.velocity);
		}
		else
		{
		Vector3 syncPosition = (Vector3)stream.ReceiveNext();
		Vector3 syncVelocity = (Vector3)stream.ReceiveNext();
		
		syncTime = 0f;
		syncDelay = Time.time - lastSynchronizationTime;
		lastSynchronizationTime = Time.time;
		
		syncEndPosition = syncPosition + syncVelocity * syncDelay;
		syncStartPosition = rigidbody.position;
		}
	}

	void Update()
	{
		if (photonView.isMine)
		{
			// If I have spawned the player
			// move it
			InputMovement();
			// change its color
			InputColorChange();
		}
		else
		{
			SyncedMovement();
		}
	}// END Update()

	// Change the player's color pressing R on the keyboard
	private void InputColorChange()
	{
		if (Input.GetKeyDown(KeyCode.R))
			// convert color to Vector3 because of RPCs' limits
			// RPCs is only able to send integers, floats, strings, vectors and quaternions 
			ChangeColorTo(new Vector3(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f)));
	}// END InputColorChange()
	
	// if called RPC sends data though the network
	[RPC] void ChangeColorTo(Vector3 color)
	{
		renderer.material.color = new Color(color.x, color.y, color.z, 1f);
		
		        if (photonView.isMine)
			// - OthersBuffered - it sends data to everyone on the server except yourself
			photonView.RPC("ChangeColorTo", PhotonTargets.OthersBuffered, color);
	}// END ChangeColorTo()

	// Movimento sincronizzato
	private void SyncedMovement()
	{
		syncTime += Time.deltaTime;
		// calculate the interpolation - Lerp interpolates between from and to by the fraction t
		rigidbody.position = Vector3.Lerp(syncStartPosition, syncEndPosition, syncTime / syncDelay);
	}
	
	void InputMovement()
	{
		if (Input.GetKey(KeyCode.W))
			rigidbody.MovePosition(rigidbody.position + Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.S))
			rigidbody.MovePosition(rigidbody.position - Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.D))
			rigidbody.MovePosition(rigidbody.position + Vector3.right * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.A))
			rigidbody.MovePosition(rigidbody.position - Vector3.right * speed * Time.deltaTime);
	}
}


Notice:


...

if (photonView.isMine)
		{
			// If I have spawned the player
			// move it
			InputMovement();
			// change its color
			InputColorChange();
...

private void InputColorChange()
	{
		if (Input.GetKeyDown(KeyCode.R))
			// convert color to Vector3 because of RPCs' limits
			// RPCs is only able to send integers, floats, strings, vectors and quaternions 
			ChangeColorTo(new Vector3(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f)));
	}// END InputColorChange()
	
	// if called RPC sends data though the network
	[RPC] void ChangeColorTo(Vector3 color)
	{
		renderer.material.color = new Color(color.x, color.y, color.z, 1f);
		
		if (photonView.isMine)
			// - OthersBuffered - it sends data to everyone on the server except yourself
			photonView.RPC("ChangeColorTo", PhotonTargets.OthersBuffered, color);
	}// END ChangeColorTo()
...

Resume

Now it is time for a final resume.

Install Photon PUN Free, activate your free account, get an AppID.

Create a scene with:

– Main Camera
– Directional Light
– Plane (as ground)
– NetworkController (Empty Object), attach NetworkManager.cs (Script)
– Project/Resources/Cube (prefab as player), attach a Rigidbody, PhotonView (Script), PlayerScript.cs (Script)

PhotonView (Script)

Observed Components -> Cube (PlayerScript.cs)

NetworkManager.cs (Script)

Inspector> Player Prefar var> Cube (prefab)


using UnityEngine;
using System.Collections;

public class NetworkManager : MonoBehaviour {

	private const string roomName = "RoomName"; // Create a Room
	private RoomInfo[] roomsList; // Array of Rooms

	public GameObject playerPrefab; // Assign in Inspector

	// Use this for initialization
	void Start () {
		// Connect to Photon (game version)
		PhotonNetwork.ConnectUsingSettings("0.1");
	}// END Start


	void OnGUI()
	{
		if (!PhotonNetwork.connected) // se la connessione è andata a buon fine
		{
			// Message: ConnectingMasterServer -> Authentication -> JoinedLobby
			GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString());
		}
		else if (PhotonNetwork.room == null) // se non esiste una Room
		{
			// Create Room
			if (GUI.Button(new Rect(100, 100, 250, 100), "Start Server"))
				PhotonNetwork.CreateRoom(roomName, true, true, 5);
			
			// Join Room
			if (roomsList != null) // se esiste una Room
			{
				for (int i = 0; i < roomsList.Length; i++)
				{
					if (GUI.Button(new Rect(100, 250 + (110 * i), 250, 100), "Join " + roomsList[i].name))
						PhotonNetwork.JoinRoom(roomsList[i].name);
				}
			}
		}
	}// END OnGUI()
	
	void OnReceivedRoomListUpdate()
	{
		// Get Room list
		roomsList = PhotonNetwork.GetRoomList();
	}// END OnReceivedRoomListUpdate()

	void OnJoinedRoom()
	{
		// Connected!
		Debug.Log("Connected to Room");

		// Spawn player
		PhotonNetwork.Instantiate(playerPrefab.name, Vector3.up * 5, Quaternion.identity, 0);
	}// END OnJoinedRoom()
	
	// Update is called once per frame
	void Update () {
		
	}// END Update
}

PlayerScript.cs (Script)


using UnityEngine;
using System.Collections;

public class PlayerScript : Photon.MonoBehaviour {

	public float speed = 10f;

	private float lastSynchronizationTime = 0f;
	private float syncDelay = 0f;
	private float syncTime = 0f;
	private Vector3 syncStartPosition = Vector3.zero;
	private Vector3 syncEndPosition = Vector3.zero;

	// It is automatically called every time it either sends or receives data
	void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
	{
		// If the user is the one updating the object, he writes to the stream.
		// This occurs automatically based on the sendrate
		if (stream.isWriting)
		{
			// It sends the rigidbody’s position with stream.SendNext()
			stream.SendNext(rigidbody.position);
			stream.SendNext(rigidbody.velocity);
		}
		else
		{
		Vector3 syncPosition = (Vector3)stream.ReceiveNext();
		Vector3 syncVelocity = (Vector3)stream.ReceiveNext();
		
		syncTime = 0f;
		syncDelay = Time.time - lastSynchronizationTime;
		lastSynchronizationTime = Time.time;
		
		syncEndPosition = syncPosition + syncVelocity * syncDelay;
		syncStartPosition = rigidbody.position;
		}
	}

	void Update()
	{
		if (photonView.isMine)
		{
			// If I have spawned the player
			// move it
			InputMovement();
			// change its color
			InputColorChange();
		}
		else
		{
			SyncedMovement();
		}
	}// END Update()

	// Change the player's color pressing R on the keyboard
	private void InputColorChange()
	{
		if (Input.GetKeyDown(KeyCode.R))
			// convert color to Vector3 because of RPCs' limits
			// RPCs is only able to send integers, floats, strings, vectors and quaternions 
			ChangeColorTo(new Vector3(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f)));
	}// END InputColorChange()
	
	// if called RPC sends data though the network
	[RPC] void ChangeColorTo(Vector3 color)
	{
		renderer.material.color = new Color(color.x, color.y, color.z, 1f);
		
		if (photonView.isMine)
			// - OthersBuffered - it sends data to everyone on the server except yourself
			photonView.RPC("ChangeColorTo", PhotonTargets.OthersBuffered, color);
	}// END ChangeColorTo()

	// Movimento sincronizzato
	private void SyncedMovement()
	{
		syncTime += Time.deltaTime;
		// calculate the interpolation - Lerp interpolates between from and to by the fraction t
		rigidbody.position = Vector3.Lerp(syncStartPosition, syncEndPosition, syncTime / syncDelay);
	}
	
	void InputMovement()
	{
		if (Input.GetKey(KeyCode.W))
			rigidbody.MovePosition(rigidbody.position + Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.S))
			rigidbody.MovePosition(rigidbody.position - Vector3.forward * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.D))
			rigidbody.MovePosition(rigidbody.position + Vector3.right * speed * Time.deltaTime);
		
		if (Input.GetKey(KeyCode.A))
			rigidbody.MovePosition(rigidbody.position - Vector3.right * speed * Time.deltaTime);
	}
}

Have fun!

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

Reference:
– http://doc-api.exitgames.com/en/pun/current/pun/doc/class_photon_network.html
– http://doc.exitgames.com/en/pun/current/tutorials/tutorial-marco-polo
– http://www.paladinstudios.com/2014/05/08/how-to-create-an-online-multiplayer-game-with-photon-unity-networking/

By |Unity3D, Video Games Development|Commenti disabilitati su Create OnLine Multiplayer Games – Unity3D – Photon PUN – C#

Unity3D – Access GameObjects and Components – CSharp

Unity3D – Access GameObjects and Components – CSharp

In Unity3D GameObjects are all entities in Unity scenes.

MAIN TOP MENU> GameObject>
– Particle System
– Camera
– GUI Text
– GUI Texture
– 3D Text
– Directional Light
– Point Light
– Spot Light
– Area Light
– Meshes
– etc…

To manage GameObjects in code you have to use the ‘gameObject’ base class.

In Unity3D Components are all ‘modifiers’ you can attach to a Gameobject.

MAIN TOP MENU> Components>
– Mesh
– Effects
– Physics
– Physics 2D
– Navigation
– etc…

Accessing this GameObject

1. Create a Cube, go to Inspector and add the script ‘DestroyBasic.cs’ as component.

DestroyBasic.cs:


using UnityEngine;
using System.Collections;

public class DestroyBasic : MonoBehaviour
{
    void Update ()
    {
        if(Input.GetKey(KeyCode.Space))
        {
            Destroy(gameObject); // notice the keyword gameObject
        }
    }
}

Play, press Space to destroy it.

Notice: ‘Destroy(gameObject)’, you can use simple the keyword ‘gameObject’ and Unity3D will destroy the game object attached to the script.

Accessing this Component

1. Create a Cube, go to Inspector and add the scripts:
– ‘OtherScript.cs’ as component
– ‘example.cs’ as component

example.cs:


using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    void Update() {
        // first declare the variable otherScript of type OtherScrip and store the component 'GetComponent'
        // type variablename = get <scriptname>
        OtherScript otherScript = GetComponent<OtherScript>();
        otherScript.DoSomething(); // manipulate the component
    }
}

Accessing Other GameObjects – Inspector assignable references

If you set a varible as ‘public’ you can assign it in Inspector, even while you are playing!


using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    // scope type variablename
    public Transform target; // Setup in Inspector
    void Update() {
        target.Translate(0, 1, 0);
    }
}

Below you can drag a Gameobject that contains the ‘OtherScript’ on the target slot in the inspector.


using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    // scope type variablename
    public OtherScript target; // Drag and Drop in Inspector a Gameobject with the script 'OtherScript' 
    void Update() {
        target.foo = 2;              // using OtherScript variables
        target.DoSomething("Hello"); // usibg OtherScript functions
    }
}

Located through the object hierarchy

1. Create the hierarchy:

Forearm (parent)
– Hand (child)

Attach to Forearm example.cs:


using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    void Example() {
        transform.Find("Hand").Translate(0, 1, 0); // find childs with name
    }
}

Once you have found the transform in the hierarchy, you can use GetComponent to get to other scripts.


using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    void Example() {
        transform.Find("Hand").GetComponent<OtherScript>().foo = 2;
        transform.Find("Hand").GetComponent<OtherScript>().DoSomething("Hello");
        transform.Find("Hand").rigidbody.AddForce(0, 10, 0);
    }
}

You can loop over all children:


using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    void Example() {
        foreach (Transform child in transform) {
            child.Translate(0, 10, 0);
        }
    }
}

Located by name


using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    void Start() {
        // type varname = find the gameobject SomeGuy
        GameObject go = GameObject.Find("SomeGuy"); // find in Project window the object with name 'SomeGuy'
        // manipulate SomeGuy 
        go.transform.Translate(0, 1, 0);

        GameObject player = GameObject.FindWithTag("Player");
        player.transform.Translate(0, 1, 0);
    }
}

Located by tag

To assign a tag go to Inspector> Tag> Add Tag


using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    void Start() {
        // type varname = find a gameobject with tag Player
        GameObject player = GameObject.FindWithTag("Player");
        // get from Player the component OtherScript
        player.GetComponent<OtherScript>().DoSomething();
    }
}

Passed as parameters


using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    // se il trigger entra in contatto con altri oggetti
    void OnTriggerStay(Collider other) {
        // se gli altri oggetti hanno un rigidbody
        if (other.rigidbody)
            // aggiungi una forza
            other.rigidbody.AddForce(0, 2, 0);
        
    }
}


using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    // se il trigger entra in contatto con altri oggetti
    void OnTriggerStay(Collider other) {
        // se gli altri componenti hanno lo script OtherScript
        if (other.GetComponent<OtherScript>())
            // ottieni OtherScript e fai qualcosa
            other.GetComponent<OtherScript>().DoSomething();
        
    }
}

All scripts of one Type

Find any object of one class or script name.

FindObjectOfType


// Search object of class GUITexture

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
    void Start() {
        GUITexture texture = FindObjectOfType(typeof(GUITexture));
        if (texture)
            Debug.Log("GUITexture object found: " + texture.name);
        else
            Debug.Log("No GUITexture object could be found");
    }
}  

FindObjectsOfType

Il precedente era singolare ‘FindObjectOfType’, questo è plurale ‘FindObjectsOfType’


// When clicking on the object, it will disable all springs on all 
// hinges in the scene

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
    void OnMouseDown() {
        HingeJoint[] hinges = FindObjectsOfType(typeof(HingeJoint)) as HingeJoint[];
        foreach (HingeJoint hinge in hinges) {
            hinge.useSpring = false;
        }
    }
}

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

Ref: http://docs.unity3d.com/412/Documentation/ScriptReference/index.Accessing_Other_Game_Objects.html

By |Unity3D, Video Games Development|Commenti disabilitati su Unity3D – Access GameObjects and Components – CSharp

CSharp – Properties – get-set

CSharp – Properties – get-set

Properties allow you to control the accessibility of a classes variables.
A property consists of 2 parts, a get and a set method, wrapped inside the property.
Only one method is required, this allows you to define read-only and write-only properties.

Syntax:

...

// la proprietà è la stringa Color
public string Color
{
    // get restituisce il valore di una variabile
    get { return color; }

    // set assegna a color il valore  - keyword value - proveniente dall'esterno 
    set { color = value; }
}
...

Example:


// definisco la proprietà Color come pubblica e di tipo stringa
public string Color
{
    get 
    {
        return color.ToUpper(); // converte una stringa in caratteri maiuscoli
    }
    set 
    { 
        if(value == "Red")
            color = value; // keyword value assegna il valore proveniente dall'esterno a color
        else
            Console.WriteLine("This car can only be red!");
    }
}

For italian people: come funziona?
1. if(value == “Red”) -> se la variabile è uguale a ‘Red’ -> set -> color = Red
2. get -> ritorna ‘RED’

Example:


class TimePeriod
{
    private double seconds;

    // proprietà - double Hours -
    public double Hours
    {
        get { return seconds / 3600; }
        set { seconds = value * 3600; }
    }
}


class Program
{
    static void Main()
    {
        TimePeriod t = new TimePeriod();

        // Assigning the Hours property causes the 'set' accessor to be called.
        t.Hours = 24;

        // Evaluating the Hours property causes the 'get' accessor to be called.
        System.Console.WriteLine("Time in hours: " + t.Hours);
    }
}
// Output: Time in hours: 24

For italian people: come funziona?
1. si avvia Main()
2. dichiato ‘t’ come variabile di tipo TimePeriod, la sintassi è la stessa che uso per richiamare una funzione
3. t.Hours = 24; -> assegnare un valore a ‘Hours’ causa l’avvio di ‘set’ che memorizza i dati in secondi
4. restituisce ‘get’ -> restituisce i dati in ore
5. System.Console.WriteLine(“Time in hours: ” + t.Hours); -> t.Hours è quello restituito da get

Example:


// Declare a Code property of type string:
public string Code
{
   get
   {
      return code;
   }
   set
   {
      code = value;
   }
}

// Declare a Name property of type string:
public string Name
{
   get
   {
     return name;
   }
   set
   {
     name = value;
   }
}

// Declare a Age property of type int:
public int Age
{ 
   get
   {
      return age;
   }
   set
   {
      age = value;
   }
}

Working Example:


using System;
namespace tutorialspoint
{
   class Student
   {

      private string code = "N.A";
      private string name = "not known";
      private int age = 0;

      // Declare a Code property of type string:
      public string Code
      {
         get
         {
            return code;
         }
         set
         {
            code = value;
         }
      }
   
      // Declare a Name property of type string:
      public string Name
      {
         get
         {
            return name;
         }
         set
         {
            name = value;
         }
      }

      // Declare a Age property of type int:
      public int Age
      {
         get
         {
            return age;
         }
         set
         {
            age = value;
         }
      }
      public override string ToString()
      {
         return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
      }
    }
    class ExampleDemo
    {
      public static void Main()
      {
         // Create a new Student object:
         Student s = new Student();
            
         // Setting code, name and the age of the student
         s.Code = "001";
         s.Name = "Zara";
         s.Age = 9;
         Console.WriteLine("Student Info: {0}", s);
         //let us increase age
         s.Age += 1;
         Console.WriteLine("Student Info: {0}", s);
         Console.ReadKey();
       }
   }
}

The result is:

Student Info: Code = 001, Name = Zara, Age = 9
Student Info: Code = 001, Name = Zara, Age = 10

For italian people: come funziona?
1. si avvia per prima Main()
2. Student s = new Student(); -> dichiaro l’oggetto s di tipo Student()
3. s.Code = “001”; -> avvia ‘class Studen’t> proprietà ‘Code’> set> code=001
4. get -> ritorna il valore code=001, quindi al di fuori di ‘class Student’ la proprietà Code=001

Ref: http://www.tutorialspoint.com/csharp/csharp_properties.htm

By |CSharp|Commenti disabilitati su CSharp – Properties – get-set

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 – Operator Overloading

CSharp – Static Polymorphism – Operator Overloading

Polymorphism is a Greek word that means “many-shaped”
Overloaded operators are functions with special names the keyword ‘operator’ followed by the symbol for the operator being defined.

Syntax:

...
public static Box operator+ (Box b, Box c)
....

Notice: ‘operator+’ keyword

Example:


using System;

namespace ConsoleApplication1
{

    class Box
    {
        private double length;      // Length of a box
        private double breadth;     // Breadth of a box
        private double height;      // Height of a box

        public double getVolume()
        {
            return length * breadth * height;
        }
        public void setLength(double len)
        {
            length = len;
        }

        public void setBreadth(double bre)
        {
            breadth = bre;
        }

        public void setHeight(double hei)
        {
            height = hei;
        }
        // Overload + operator to add two Box objects.
        public static Box operator +(Box b, Box c)
        {
            Box box = new Box();
            box.length = b.length + c.length;
            box.breadth = b.breadth + c.breadth;
            box.height = b.height + c.height;
            return box;
        }

    }

    class Tester
    {
        static void Main(string[] args)
        {
            Box Box1 = new Box();         // Declare Box1 of type Box
            Box Box2 = new Box();         // Declare Box2 of type Box
            Box Box3 = new Box();         // Declare Box3 of type Box
            double volume = 0.0;          // Store the volume of a box here

            // box 1 specification
            Box1.setLength(6.0);
            Box1.setBreadth(7.0);
            Box1.setHeight(5.0);

            // box 2 specification
            Box2.setLength(12.0);
            Box2.setBreadth(13.0);
            Box2.setHeight(10.0);

            // volume of box 1
            volume = Box1.getVolume();
            Console.WriteLine("Volume of Box1 : {0}", volume);

            // volume of box 2
            volume = Box2.getVolume();
            Console.WriteLine("Volume of Box2 : {0}", volume);

            // Add two object as follows:
            Box3 = Box1 + Box2;

            // volume of box 3
            volume = Box3.getVolume();
            Console.WriteLine("Volume of Box3 : {0}", volume);
            Console.ReadKey();
        }
    }

}

The result is:

Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400

For italian people: come funziona?

1. Viene eseguita prima Main()
2. Box Box1 = new Box(); -> dichiaro le variabili come appartenenti al tipo classe ‘Box’
3. Box1.setLength(6.0); -> invio alla classe ‘Box’ funzione ‘setLenght’ il valore 6.0 -> che viene assegnato a ‘length’
4. Idem come sopra per tutte le specifiche di Box1′ e ‘Box2’
5. public static Box operator +(Box b, Box c) … return box; -> Overload dell’operatore, vengono computati separatamente Box1′ e ‘Box2’
6. volume = Box1.getVolume(); -> avvia dalla classe ‘Box’ la funzione ‘getVolume()’ e calcola il volume

Se togliamo le righe…


      // Overload + operator to add two Box objects.
      public static Box operator+ (Box b, Box c)
      {
         Box box = new Box();
         box.length = b.length + c.length;
         box.breadth = b.breadth + c.breadth;
         box.height = b.height + c.height;
         return box;
      }

verrà restituito un errore di compilazione.

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