Na początku trochę o rozłożeniu skryptu na obiektach. Dotychczas miałem w nawyku trzymanie możliwie jak największej liczby informacji w jednym skrypcie, co nie przeszkadzało w grach tworzonych z myślą o single player. Przy zabawia z trybem multi doszedłem do wniosku, że najlepiej będzie, gdy informacje związane ze sceną będą przechowywane tylko na kliencie, co da lekką ulgę serwerowi.
PlayerPrefab będzie natomiast zawierał skrypty związane z komunikacją między klientem a sceną. Skrypt umożliwiający wysyłanie serwerowi poleceń musi istnieć zarówno na obiekcie klienta, jak i odpowiedniku tego obiektu na serwerze i dlatego starałem się podzielić główny skrypt na dwie części. Sam schemat będzie wyglądać mniej więcej tak:
Scena
Chcemy mieć dwie sceny: scenę offline i scenę online. Na obu scenach będzie znajdować się kamera i źródło światła, na scenie offline będzie znajdował się obiekt ze skryptem
NetworkManager, a na scenie online będzie znajdować obiekt ze skryptem
NetworkIdentity z zaznaczą opcją
ServerOnly (będzie on służył do przechowywania danych o sytuacji na planszy). Po podłączeniu się na serwer online obiekt ze skryptem
NetworkManager przeniesie się ze sceny offline, wiec nie trzeba go tam umieszczać.
Musimy mieć jakiś prefab który umieścimy w skrypcie
NetowrkManager jako
PlayerPrefab. Do tego prefabu dodałem następujący skrypt:
using
UnityEngine;
using
System.Collections;
using
UnityEngine.Networking;
public
class
PlayerScript
: NetworkBehaviour
{
NetworkIdentity
MyNet;
void
Start () {
if
(isLocalPlayer) {
name
= "MyPlayer";
MyNet
= GetComponent<NetworkIdentity>
();
Instantiate
(Resources.Load
("PreMObject"));
}
}
}
Skrypt ten ma dodaną bibliotekę związaną z sieciami. Skrypt po uruchomieniu odpala funkcję Start, która najpierw sprawdza, czy
PlayerPrefab jest naszą własnością - po podłączeniu się innych graczy na naszej scenie pojawi się ich
PlayerPrefab, a my nie chcemy aby ten fragment kodu aktywował się na nie-naszych obiektach. Jeśli obiekt jest naszą własnością, to zmieniamy jego nazwę, abyśmy mogli łatwo go znaleźć na scenie. Drugą rzeczą jest przypisanie do zmiennej informacji o tym jaki konkretnie skrypt
NetworkIdentity jest do niego przyczepiony. Zmienną tą będziemy czasem przekazywać na serwer, aby móc ją odebrać z pozostałych klientów. Ostatnią rzeczą robioną przez ten fragment kodu jest utworzenie instancji prefabu o nazwie "PreMObject", który utworzyłem przedtem w folderze Resorces. Chciałem aby obiekt ten był tworzony za pośrednictwem skryptu aby mieć pewność, że uruchamiane przez niego funkcje zawsze uruchomią się po pojawianiu się
PlayerPrefabu. Gdyby kolejność była inna, to niektóre moje skrypty nie mogłyby odnaleźć naszego gracza i nie zadziałałyby poprawnie.
Mój prefab "PreMObject" zawiera obiekt ze skryptem zajmującym się sceną na kliencie. Ze starego skryptu zostawiłem fragmenty kodu związane z planszą i prócz tego na początku funkcji start dodałem linijkę kodu zmieniającą nazwę obiektu:
name
= "MObject";
Skrypt po staremu tworzy całą planszę, przechowuje o niej informacje i przypisuje do pól skrypt umożliwiający sterowanie, który trzeba nieco zmodyfikować.
Skrypt sterowania
Pierwszą zmianą jest dodanie zmiennej wskazującą na skrypt związany z komunikacją z serwerem, gdzie za typ zmiennej podstawiamy nazwę tamtego skryptu:
public
PlayerScript
PScript;
Następnie w funkcji Start dodałem linijkę kodu przypisujący skrypt do tej zmiennej:
PScript
= GameObject.Find
("MyPlayer").GetComponent<PlayerScript>
();
I przekształciłem linijkę kodu wywołującą funkcję tworzącą żeton, aby była ona wywoływana ze wspomnianego skryptu:
StartCoroutine
(PScript.UseToken (x, y));
Komunikacja z serwerem
Teraz powracamy do skryptu PlayerScript. Chcemy aby informacja o postawieniu żetonu była wysłana na serwer, by ten rozkazał klientom, aby utworzyli żeton. Jeśli chcemy wydać serwerowi polecenie z poziomu klienta, musimy zastosować atrybut command. Aby dodać ten atrybut trzeba przed funkcją napisać "
[Command]", a za trzy pierwsze znaki nazwy tej funkcji musimy wstawić "Cmd", tak jak na przykładzie:
[Command]
public
void
CmdUseToken (int
x, int
y) {
}
Z kolei jeśli z poziomu serwera chcemy wydać polecenie klientom, musimy zastosować atrybut
[ClientRpc], a trzema pierwszymi znakami nazwy funkcji muszą być znaki "Rpc", tak jak na przykładzie:
[ClientRpc]
public
void
RpcSpawnToken (int
x, int
y) {
}
Z taką wiedzą uzupełniamy skrypt PlayerScript o następujący fragment kodu:
public
IEnumerator
UseToken (int
x, int
y) {
CmdUseToken
(x, y);
yield
return
new
WaitForSeconds
(0.25f);
}
[Command]
public
void
CmdUseToken (int
x, int
y) {
RpcSpawnToken
(x, y);
}
[ClientRpc]
public
void
RpcSpawnToken (int
x, int
y) {
MScript
MScript = GameObject.Find
("MObject").GetComponent<MScript>
();
GameObject
Clone = Instantiate (Resources.Load
("PreToken"))
as
GameObject;
MScript.Token
[x, y] = Clone;
Clone.transform.parent
= MScript.Field [x, y].transform;
Clone.transform.localPosition
= new
Vector3
(0, 0, -7.5f);
Clone.transform.localScale
= new
Vector3
(0.9f, 0.9f, 1);
Clone.AddComponent<FallingScript>
();
if
(MyNet == GetComponent<NetworkIdentity>
()) {
Clone.GetComponent<Renderer>
().material.color = new
Color
(0.65f, 0.9f, 0.55f);
}
else
{
Clone.GetComponent<Renderer>
().material.color = new
Color
(0.85f, 0.6f, 0.6f);
}
Clone
= Instantiate (Resources.Load
("PreText"))
as
GameObject;
Clone.transform.parent
= MScript.Token [x, y].transform;
Clone.transform.localPosition
= new
Vector3
(0, 0, -0.01f);
Clone.transform.localScale
= new
Vector3
(0.9f, 0.9f, 1);
Clone.GetComponent<TextMesh>
().text = "2";
}
Ostatnia funkcja wyszukuje na kliencie skrypt z informacjami o scenie, aby móc przypisać do niego informacje o żetonie który tworzy. Warto tu zwrócić uwagę, że funkcja ta będzie wykonywana na każdym kliencie i na każdym kliencie ten skrypt jest wyszukiwany osobno. Kolejną rzeczą której przedtem nie było jest podmiana koloru żetonu: jeśli komponent
NetworkIdentity gracza który rozkazał postawienie żetonu jest taki sam co
NetworkIdentity klienta, to znaczy że tworzymy żeton na własnym kliencie i wtedy ma kolor zielony, w przeciwnym razie ma kolor czerwony. Wartość koloru jest wyrażana w wartości RGB. Do tego jeszcze dochodzi fragment kodu tworzący tekst wyświetlany nad żetonem.
Teraz możemy już stawiać żetony na różnych klientach i pojawiają się one na każdym z klientów.
Brak komentarzy:
Prześlij komentarz