05 SendingReceivingMessages - project-SIMPLE/simple.toolchain GitHub Wiki
Link to the example model: LinkToUnity/Models/Code Examples/Send Receive Messages.gaml
The SIMPLE toolkit allows to send a message from GAMA to Unity and a message from Unity to GAMA.
Sending a message from GAMA to Unity requires to use the action send_message
of the Unity_linker agent. The message should be a map (key: name of the attribute; value: value of this attribute). The name of the attribute should be the same as the variable in the serialized class in Unity (c# script)
For example, to send a message to a all the players that contains the current cycle of the simulation, we can use:
do send_message players: unity_player as list mes: ["cycle":: cycle];
In Unity, a serialized class in Unity has to be defined to serialize (decrypt) the message:
[System.Serializable]
public class GAMAMessage
{
public int cycle;
public static GAMAMessage CreateFromJSON(string jsonString)
{
return JsonUtility.FromJson<GAMAMessage>(jsonString);
}
}
Then the message can be received in the SimulationManager class:
public class SendReceiveMessageExample : SimulationManager
{
GAMAMessage message = null;
//allow to serialize the message as GAMAMessage object
protected override void ManageOtherMessages(string content)
{
message = GAMAMessage.CreateFromJSON(content);
}
//action activated at the end of the update phase (every frame)
protected override void OtherUpdate()
{
// if a message was received, display in the console the content of the message
if (message != null)
{
Debug.Log("received from GAMA: cycle " + message.cycle);
message = null;
}
}
}
The principle is to call from Unity an action defined in the Unity Linker.
For example, we define in GAMA, in the unity_linker species a new action called "receive_message" that just display in the console the id of the player sending the message and the content of it:
species unity_linker parent: abstract_unity_linker {
//action that will be called by the Unity player to send a message to the GAMA simulation
action receive_message (string id, string mes) {
write "Player " + id + " send the message: " + mes;
}
}
Then, in the SimulationManager of Unity, we ask the unity_linker to call this action with the corresponding arguments:
protected override void OtherUpdate()
{
if (IsGameState(GameState.GAME))
{
string mes = "A message from Unity at time: " + Time.time;
//call the action "receive_message" from the unity_linker agent with two arguments: the id of the player and a message
Dictionary<string, string> args = new Dictionary<string, string> {
{"id",ConnectionManager.Instance.getUseMiddleware() ? ConnectionManager.Instance.GetConnectionId() : ("\"" + ConnectionManager.Instance.GetConnectionId() + "\"") },
{"mes", mes }};
Debug.Log("sent to GAMA: " + mes);
ConnectionManager.Instance.SendExecutableAsk("receive_message", args);
}
}