Introduction
This MMO demo is a sample game developed using AppWarpS2 and Unity to showcase how one can develop an MMO game with AppWarpS2. MMO games have different challenges than other genres of multiplayer games. One such difficulty is interest management. Since AppWarp cloud server was limited to our logic only, AppWarpS2 allowed developers to extend the logic and host their server wherever they want. Henceforth, AppWarpS2 can be used to make MMO games.
Introducción
Este demo MMO es un juego de muestra desarrollado usando AppWarpS2 y Unity para mostrar cómo se puede desarrollar un juego MMO con AppWarp S2. Juegos MMO tienen distintos retos que otros géneros de juegos multijugador. Una de estas dificultades es la gestión de intereses. Desde que el servidor de nube AppWarp es limitado a nuestra lógica solamente, AppWarp S2 permite a los desarrolladores extender la lógica y alojar su servidor donde quieran. De ahora en adelante, AppWarp S2 puede ser usado para hacer juegos MMO.
Código de fuente está disponible en github
Para aprender mas acerca de Gestion de interés, puede leer nuestra documentación para Space War Fare MMO Sample, el cual es un juego MMO desarrollado para Flash y AppWarp S2. Puede encontrar el wiki de Space War Fare aquí.
Esta muestra usa la misma lógica del servidor y codificación como la desarrollada en Space War Fare demo con pequeños cambios para el intercambio de mensajes en formato binario.
Mecánica del juego
Es muy simple, al principio se le pedirá que seleccione un nombre único. Una vez conectado, el jugador estará parado en una isla desierta con un pilar en el medio. Use flechas de movimiento para moverse en el juego. Solo podrá ver los jugadores que están a su alrededor.
Cliente de la Unidad
El cliente es hecho en Unity. Para cambiar la posición de los jugadores, usamos mensajes binarios. Los mensajes binarios son enviados a través de del método SendUpdatePeers(). Cada mensaje consiste en 6 floats seguido de una cadena que representa el nombre del jugador. Los 6 floats representan los componentes x,y Y z de la posición y rotación. Para enviar esta información, primero debemos convertir los floats y cadenas en bytes.
La red espera datos binarios para ser en la forma de Big Endian. Así que asegúrese de convertir los mensajes a Big Endian, si el sistema es Little Endian.
Estamos usando el método System.BitConverter.GetBytes() para convertir cualquier dato a bytes y System.Array.Reverse para revertir el conjunto de bytes, si el sistema es Little Endian.
int data_len = (sizeof(float)*6) + (USER.Length*sizeof(char));
byte[] data = new byte[data_len];
for(int i=0; i<6; ++i)
{
byte[] converted = System.BitConverter.GetBytes(data_f[i]);
if(System.BitConverter.IsLittleEndian)
{
System.Array.Reverse(converted);
}
for(int j=0; j<sizeof(float); ++j)
{
data[i*sizeof(float)+j] = converted[j];
}
}
char[] charUser = USER.ToCharArray();
int offset = sizeof(float)*6;
for(int i=0; i<charUser.Length; ++i)
{
byte[] converted = System.BitConverter.GetBytes(charUser[i]);
if(System.BitConverter.IsLittleEndian)
{
System.Array.Reverse(converted);
}
for(int j=0; j<sizeof(char); ++j)
{
data[offset+(i*sizeof(char)+j)] = converted[j];
}
}
Similarmente, tenemos que decodificar los mensajes de binario al mensaje original cuando estos lleguen al servidor del cliente.
Hemos usado mensajes binarios solamente para intercambio de posiciones. Para enviar información como si un jugador haya dejado su área de interés, entonces enviamos ese mensaje a través del chat.
Del lado del cliente, la lógica es muy simple, cuando un mensaje es recibido, revisamos si ya existe un jugador que conocemos con ese nombre de remitente, si es así, simplemente actualizamos el objeto de juego de ese jugador con la nueva posición y si el mensaje fue enviado por un jugador quien es nuevo para nosotros, instanciamos uno prefabricado correspondiente y lo actualizamos con la posición dada. Y cuando existe un mensaje de chat que el jugador ha abandonado la región o una notificación del jugador que ha dejado la sala, borramos el objeto de juego correspondiente.
Para hacer de la jugabilidad más simple, no enviamos la posición de manera frecuente sino 10 por segundo.
Servidor
Como lo mencione anteriormente, hemos usado el mismo código que escribimos en la muestra Space War Fare pero era un juego 2D y ya que esta muestra es 3D, lo modificamos un poco. Como el jugador solo camina en los planos X-Z, podemos ignorar el eje Y. Por lo tanto, hemos mapeado los ejes X-Z como los ejes X-Y en el servidor para hacerlos funcionar con nuestra simulación 2D MMO ya escrita.
Lo siguiente, como el cliente está enviando mensajes en formato binario, necesitamos convertirlos de nuevo a la forma original en el lado del servidor. Pero desde que ya sabemos que los mensajes siempre vienen en Big Endian, podemos manejarlos de manera fácil.
public void handleUpdatePeersRequest(IUser sender, byte[] update, HandlingResult result) {
ByteBuffer buffer = ByteBuffer.wrap(update).order(ByteOrder.BIG_ENDIAN);
float x = buffer.getFloat(); // Position - X
float y = buffer.getFloat(); // Position - Y
float z = buffer.getFloat(); // Position - Z
float rx = buffer.getFloat(); // Rotation - X
float ry = buffer.getFloat(); // Rotation - Y
float rz = buffer.getFloat(); // Rotation - Z
String name = "";
while(buffer.remaining() > 0)
{
name += buffer.getChar();
}
...
}
Lo siguiente, como el cliente está enviando mensajes en formato binario, necesitamos convertirlos de nuevo a la forma original en el lado del servidor. Pero desde que ya sabemos que los mensajes siempre vienen en Big Endian, podemos manejarlos de manera fácil.
Conclusión
Así es como hacemos un juego básico MMO pero puede usar cualquier lógica/patrón para escribir su propio juego MMO.
Por favor contáctenos a support@shephertz.com en caso de alguna duda o sugerencia.
Source code is available on github
To learn more about Interest Management, you can read our already written documentation for Space War Fare MMO Sample, which is an MMO game developed for Flash and AppWarp S2. You can find Space War Fare’s wiki here
This sample uses the same server logic and code as developed in Space War Fare demo with minor changes for exchanging messages in binary format.
Gameplay
Gameplay is very simple. In the beginning, you will be asked to select a unique name for yourself. Once connected, the player will be standing in between a deserted island with a pillar in the middle of the land. Use Arrow keys to move in the game. You will be able to see only those players that are near you.
Unity Client
The client is made in Unity. To exchange position of players, we are using binary messages. The binary messages are sent through SendUpdatePeers() method. Every message consists of 6 floats followed by a string representing the name of a player. The 6 floats represent the x,y and z components of position & rotation. To send this information, we have to first convert the floats & string into bytes.
The Network expects your binary data to be in the form of Big Endian. So, make sure you convert the messages into Big Endian, if the system is Little Endian.
We are using System.BitConverter.GetBytes() method to convert any data into bytes and System.Array.Reverse to reverse the array of bytes, if the system is Little Endian.
int data_len = (sizeof(float)*6) + (USER.Length*sizeof(char));
byte[] data = new byte[data_len];
for(int i=0; i<6; ++i)
{
byte[] converted = System.BitConverter.GetBytes(data_f[i]);
if(System.BitConverter.IsLittleEndian)
{
System.Array.Reverse(converted);
}
for(int j=0; j<sizeof(float); ++j)
{
data[i*sizeof(float)+j] = converted[j];
}
}
char[] charUser = USER.ToCharArray();
int offset = sizeof(float)*6;
for(int i=0; i<charUser.Length; ++i)
{
byte[] converted = System.BitConverter.GetBytes(charUser[i]);
if(System.BitConverter.IsLittleEndian)
{
System.Array.Reverse(converted);
}
for(int j=0; j<sizeof(char); ++j)
{
data[offset+(i*sizeof(char)+j)] = converted[j];
}
}
Similarly, we have to decode the messages from binary to original message when these arrive from server to client.
We have used binary messages only for exchanging positions. To send information like if a player has left your interest area then we send that message through chat.
On client side, the logic is very simple, whenever there is a message received, we check if there is already a player that we know with that sender name, if yes, we simply update that player’s game object with the new position & if the message was sent by a player who is new to us, we instantiate a corresponding prefab and update it with the given position. And, whenever there is a chat message that the player has left a region or notification for player leaving the room occurs, we delete the corresponding game object.
To make game play smooth, we are not sending positions frequently but 10 per second. Then we lerp between these discreet values.
Server
As mentioned earlier, we have utilized the same code that we wrote in Space War Fare sample but it was a 2D game and since this sample was 3D, we modified it a little. As the player is only walking in X-Z plan, we can easily ignore Y-axis. Therefore, we mapped X-Z axis as X-Y axis on server to make it work with our already written 2D MMO simulation.
Next, as the client is sending messages in binary format, we need to convert it back into original form on server side. But since, we already knew that messages always come in Big Endian, we can handle it very easily.
public void handleUpdatePeersRequest(IUser sender, byte[] update, HandlingResult result) {
ByteBuffer buffer = ByteBuffer.wrap(update).order(ByteOrder.BIG_ENDIAN);
float x = buffer.getFloat(); // Position - X
float y = buffer.getFloat(); // Position - Y
float z = buffer.getFloat(); // Position - Z
float rx = buffer.getFloat(); // Rotation - X
float ry = buffer.getFloat(); // Rotation - Y
float rz = buffer.getFloat(); // Rotation - Z
String name = "";
while(buffer.remaining() > 0)
{
name += buffer.getChar();
}
...
}
After having the position of player, we update the world with new position of that player which re-calculates which player has entered or left your interest region. Later, we send corresponding messages to represent this addition and removal of players from interest region.
Conclusion
This is how we made a basic MMO game but you can use any pattern/logic to write your own MMO game play.
If you have queries or need any further assistance, please feel free to reach us at support@shephertz.com
Leave A Reply