[198] Elixir and Unity3d

Rendering our spaceships simulator in 3D with Unity3D

Subscribe now

Elixir and Unity3d [05.13.2016]

In today's episode we tie the spaceship simulator in with Unity3D via a quickie TCPServer. I don't have a detailed script for this episode, but what I can show you in the text version is the TCPServer and the Unity C# code.

TCP Server

defmodule Spaceships.TCPServer do
  def listen(port, state_pid) do
    IO.puts "listening on port #{port}"
    tcp_options = [:binary, {:packet, 0}, {:active, false}]
    {:ok, listening_socket} = :gen_tcp.listen(port, tcp_options)
    do_accept(listening_socket, state_pid)
  end

  def do_accept(listening_socket, state_pid) do
    {:ok, socket} = :gen_tcp.accept(listening_socket)
    start(socket, state_pid)
  end

  def start(socket, state_pid) do
    loop(socket, state_pid)
  end

  def loop(socket, state_pid) do
    case :gen_tcp.recv(socket, 0) do
      {:ok, "quit\r\n"} -> :ok
      {:ok, data} ->
        Spaceships.State.get_ships(state_pid)
        |> render_ships
        |> tcp_send(socket)
        loop(socket, state_pid)
      {:error, :closed} -> :ok
    end
  end

  def tcp_send(data, socket) do
    :gen_tcp.send(socket, data)
  end

  def render_ships(ships) do
    ships
    |> Enum.map(&render_ship/1)
    |> Enum.join "|"
  end

  def render_ship(ship) do
    vector_x = :math.cos ship.angle
    vector_y = :math.sin ship.angle
    "#{ship.id}=" <>
    Enum.join([
      Float.to_string(400+ship.x, decimals: 2),
      Float.to_string(400+ship.y, decimals: 2),
      Float.to_string(vector_x, decimals: 2),
      Float.to_string(vector_y, decimals: 2)
    ], ",")
  end
end

Unity Code

#...
public class Emitter : MonoBehaviour {
  #...
    // Update is called once per frame
    void Update () {
        //Debug.Log (CharacterTranform.position);
        CharacterPos = CharacterTranform.position;

        ProcessData(rawEntityCoords);
    }

    static void sendData ()
    {
        try
        {
            Int32 port = 8400;
            TcpClient client = new TcpClient("localhost", port);
            NetworkStream stream = client.GetStream();
            while (running)
            {
        // Translate the passed message into ASCII and store it as a Byte array.
                String message = CharacterPos.x.ToString() + "," + CharacterPos.z.ToString();
        Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
        // Send the message to the connected TcpServer.
                stream.Write(data, 0, data.Length);
                // Receive the TcpServer.response.
        // Buffer to store the response bytes.
                data = new Byte[2048];
        // String to store the response ASCII representation.
                String responseData = String.Empty;
        // Read the first batch of the TcpServer response bytes.
                Int32 bytes = stream.Read(data, 0, data.Length);
                responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);

                rawEntityCoords = responseData;

                Thread.Sleep(10);
            }
            // Close everything.
            stream.Close();
            client.Close();
        }
        catch (Exception ex)
        {
            Debug.Log("Failed To Connect to the Server: " + ex.Message);
        }
    }

    void ProcessData(string responseData)
    {
        if(responseData.Length == 0) return;
        if(responseData == "null") return;

        // #Ref<0.0.0.1728>=66.94,41.21|#Ref<0.0.0.1778>=15.94,47.10|#Ref<0.0.0.1833>=68.32,58.76|#Ref<0.0.0.1680>=1.20,3.40
        Array coords = responseData.Split('|');
        foreach (string coord in coords)
        {
            Array element = coord.Split('=');
            string entityId = element.GetValue(0).ToString();
            Array entityCoords = element.GetValue(1).ToString().Split(',');
            float entityCoordsX = float.Parse (entityCoords.GetValue(0).ToString());
            float entityCoordsZ = float.Parse (entityCoords.GetValue(1).ToString());
            float entityVectorX = float.Parse (entityCoords.GetValue(2).ToString());
            float entityVectorZ = float.Parse (entityCoords.GetValue(3).ToString());

            // create a cube if not exists
            GameObject obj = GameObject.Find(entityId);
            if (obj == null) createCube(entityId, entityCoordsX, entityCoordsZ, entityVectorX, entityVectorZ);
            // move if exists
            else
            {
                obj.transform.position = new Vector3 (entityCoordsX, (float)0.6, entityCoordsZ);
                obj.transform.rotation = Quaternion.LookRotation(new Vector3(entityVectorX, 270, entityVectorZ));
            }
        }
    }

    void createCube(string entityId, float entityCoordsX, float entityCoordsZ, float entityVectorX, float entityVectorZ)
    {
        //GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        //cube.name = entityId;
        //cube.transform.position = new Vector3 (entityCoordsX, (float)0.6, entityCoordsZ);
        //cube.transform.localScale = new Vector3 (1, 1, 1);

        UnityEngine.Object bot = Instantiate(preFactBot, new Vector3 (entityCoordsX, (float)0.6, entityCoordsZ), Quaternion.LookRotation(new Vector3(entityVectorX, 0, entityVectorZ)));
        bot.name = entityId;
    }

    void OnDestroy()
    {
        Debug.Log("Stopping...");
        running = false;
    }
}

Summary

So sorry there's not great text here, but you want to watch this one anyway if this sounds fun at all :) See you soon!

Resources