This shows you the differences between two versions of the page.
|
pjv:laboratoare:2025:a05 [2025/12/10 12:11] alexandru.gradinaru |
pjv:laboratoare:2025:a05 [2025/12/10 12:46] (current) alexandru.gradinaru [Cerinte] |
||
|---|---|---|---|
| Line 32: | Line 32: | ||
| ==== Cerinte ===== | ==== Cerinte ===== | ||
| - | Realizarea unui joc multiplayer de tip social: | + | Realizarea unui joc multiplayer de tip social, prin folosirea/implementarea unui server multiplayer dedicat: |
| + | |||
| + | |||
| + | * Player avatar sincronizat la nivel de pozitie si animatii: minim 2 playeri/clienti | ||
| + | * Comunicare chat cu interfata grafica | ||
| - | <hidden> | ||
| - | * Player avatar sincronizat la nivel de pozitie si animatii | ||
| - | * Comunicare chat sau voice | ||
| - | * Server multiplayer dedicat, implementare proprie | ||
| - | </hidden> | ||
| Line 132: | Line 132: | ||
| Pentru realizarea clientului puteti folosi direct pachetul din Asset Store [[https://assetstore.unity.com/packages/tools/network/darkrift-networking-2-95309|DarkRift Networking 2]] | Pentru realizarea clientului puteti folosi direct pachetul din Asset Store [[https://assetstore.unity.com/packages/tools/network/darkrift-networking-2-95309|DarkRift Networking 2]] | ||
| - | Exemplu de conectare si trimitere de mesaj: | + | Exemplu de conectare si trimitere de mesaj simplu: |
| <code> | <code> | ||
| Line 165: | Line 165: | ||
| Puteti folosi tag-uri pentru a delimita diverse tipuri de mesaje. | Puteti folosi tag-uri pentru a delimita diverse tipuri de mesaje. | ||
| - | De exemplu pentru actualizare de miscare puteti folosi tagul 1 si pentru chat puteti folosi tag-ul 11 | + | De exemplu pentru actualizare de miscare puteti folosi tagul 1 si pentru chat puteti folosi tag-ul 10 |
| + | Exemplu de trimitere mesaj de chat | ||
| + | <code> | ||
| + | //This will be called when the user presses enter in the input field | ||
| + | public void MessageEntered() | ||
| + | { | ||
| + | //Check we have a client to send from | ||
| + | if (client == null) | ||
| + | { | ||
| + | Debug.LogError("No client assigned to Chat component!"); | ||
| + | return; | ||
| + | } | ||
| + | //First we need to build a DarkRiftWriter to put the data we want to send in, it'll default to Unicode | ||
| + | //encoding so we don't need to worry about that | ||
| + | using (DarkRiftWriter writer = DarkRiftWriter.Create()) | ||
| + | { | ||
| + | //We can then write the input text into it | ||
| + | writer.Write(input.text); | ||
| + | //Next we construct a message, in this case we can just use a default tag because there is nothing fancy | ||
| + | //that needs to happen before we read the data. | ||
| + | using (Message message = Message.Create(10, writer)) | ||
| + | { | ||
| + | //Finally we send the message to everyone connected! | ||
| + | client.SendMessage(message, SendMode.Reliable); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Pentru actualizare miscarii, trebuie sa tinem cont de ficare client in parte: | ||
| + | * trimtem actualizari de la input doar pentru clientul curent | ||
| + | <code> | ||
| + | void UpdateNetworkPosition() { | ||
| + | if ( | ||
| + | Vector3.Distance(lastPosition, transform.position) > moveDistance || | ||
| + | Vector3.Distance(lastRotation, transform.eulerAngles) > moveDistance | ||
| + | | ||
| + | ) | ||
| + | { | ||
| + | using (DarkRiftWriter writer = DarkRiftWriter.Create()) | ||
| + | { | ||
| + | writer.Write(transform.position.x); | ||
| + | writer.Write(transform.position.y); | ||
| + | writer.Write(transform.position.z); | ||
| + | writer.Write(transform.eulerAngles.x); | ||
| + | writer.Write(transform.eulerAngles.y); | ||
| + | writer.Write(transform.eulerAngles.z); | ||
| + | |||
| + | using (Message message = Message.Create(1, writer)) | ||
| + | Client.SendMessage(message, SendMode.Unreliable); | ||
| + | } | ||
| + | |||
| + | lastPosition = transform.position; | ||
| + | lastRotation = transform.eulerAngles; | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | * instantiem diferit playerii: unul controlabil din input local, pentru clientul curent, si ceilalti doar sincronizati la actualizarile din server | ||
| + | <code> | ||
| + | void SpawnPlayer(object sender, MessageReceivedEventArgs e) | ||
| + | { | ||
| + | |||
| + | using (Message message = e.GetMessage()) | ||
| + | using (DarkRiftReader reader = message.GetReader()) | ||
| + | { | ||
| + | if (message.Tag == 0) | ||
| + | { | ||
| + | while (reader.Position < reader.Length) | ||
| + | { | ||
| + | | ||
| + | ushort id = reader.ReadUInt16(); | ||
| + | | ||
| + | |||
| + | Vector3 position = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); | ||
| + | Vector3 euler = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); | ||
| + | | ||
| + | GameObject obj; | ||
| + | |||
| + | if (id == client.ID) | ||
| + | { | ||
| + | // instantiate local user | ||
| + | obj = Instantiate(localPrefab, position, Quaternion.identity) as GameObject; | ||
| + | |||
| + | } | ||
| + | else | ||
| + | { | ||
| + | // instantiate network user | ||
| + | obj = Instantiate(networkPrefab, position, Quaternion.identity) as GameObject; | ||
| + | | ||
| + | //keep a list with all network players | ||
| + | networkPlayerManager.Add(id, playObj); | ||
| + | } | ||
| + | |||
| + | | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | | ||
| + | </code> | ||
| + | * actualizam sincronizarile din server pentru toti playerii. Pentru asta in general avem nevoie sa tinem minte toata lista de clienti | ||
| + | <code> | ||
| + | Dictionary<ushort, NetworkPlayerObj> networkPlayers = new Dictionary<ushort, NetworkPlayerObj>(); | ||
| + | |||
| + | void MessageReceived(object sender, MessageReceivedEventArgs e) | ||
| + | { | ||
| + | using (Message message = e.GetMessage() as Message) | ||
| + | { | ||
| + | Debug.Log("network message "); | ||
| + | if (message.Tag == 1) | ||
| + | { | ||
| + | // Debug.Log("position message "); | ||
| + | using (DarkRiftReader reader = message.GetReader()) | ||
| + | { | ||
| + | ushort id = reader.ReadUInt16(); | ||
| + | Vector3 newPosition = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); | ||
| + | Vector3 newEulerAngles = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); | ||
| + | |||
| + | if (networkPlayers.ContainsKey(id)) | ||
| + | { | ||
| + | // Debug.Log("new network position: "+newPosition); | ||
| + | networkPlayers[id].movePosition = newPosition; | ||
| + | networkPlayers[id].currentEulerAngles = newEulerAngles; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| ==== Server Plugin ===== | ==== Server Plugin ===== | ||
| Line 335: | Line 464: | ||
| } | } | ||
| </code> | </code> | ||
| + | |||
| + | |||
| + | Pentru sincronizarea de animatii se poate proceda in mai multe feluri, in functie si de modul de gestiune al animatiilor: | ||
| + | * fie se trimite si un indicator de stare al animatiei si se sincornizeaza over network | ||
| + | * fie se folosesc valori de speed, hieght etc (calculate prin diferenta sau luate/transmise direct) | ||
| ==== Chat ===== | ==== Chat ===== | ||