2.9.9
Coherent GT
A modern user interface library for games
Sample - C++ and JavaScript binding

This sample demonstrates the communication between C++ and JavaScript

  • transferring data
  • executing C++ from JavaScript and JavaScript from C++
Note
Supplied code is not representative for a well-designed, high-performance solution. It's written for simplicity and its purpose is to demonstrate features of Coherent GT.

Building the Binding sample

The sample solution is already configured and you only have to compile and run it.

It uses a sample mini game framework that provides very basic functionality.

The output will be in the Coherent/bin directory.

Prerequisites

This sample builds upon the HelloGT sample and assumes that you understand it.

Key points

  1. Coherent::UIGT::ViewListener::OnReadyForBindings is overridden to allow registration of C++ handlers to be called from JavaScript.
  2. The debugger port is set inside the Coherent::UIGT::SystemSettings to allow easier development and troubleshooting.
  3. A simple C++ structure, GameOptions is exposed to Coherent GT so as to illustrate the transfer of structures between C++ and JavaScript.

Sample walk-through

When the view is ready for the registration of C++ call and event handlers Coherent::UIGT::ViewListener::OnReadyForBindings is called

virtual void OnReadyForBindings() override
{
// When a routine is called in JS with these identifiers we specify what functions must be called in C++
m_View->BindCall("ApplyOptions", Coherent::UIGT::MakeHandler(&g_OptionsHandler, &OptionsHandler::ApplyOptions));
m_View->BindCall("GetLatency", Coherent::UIGT::MakeHandler(&GetNetworkLatency));
m_View->BindCall("GetGameTime", Coherent::UIGT::MakeHandler(&GetGameTime));
// register handler for an engine event
m_View->RegisterForEvent("ViewReady", Coherent::UIGT::MakeHandler(this, &ViewEventListener::ViewReady));
}

The HTML and JavaScript code for this sample is in Coherent/Samples/Sample_Binding/uiresources/binding.html.

When the document has been loaded and C++ handlers have been registered the Ready event is fired.

engine.on('Ready', function () {
// trigger event handled by C++
engine.trigger('ViewReady');
});

This actually triggers

void ViewReady()
{
m_View->TriggerEvent("OpenOptions", m_Options);
}

Since the GameOptions structure is exposed to Coherent GT via the method CoherentBind, this allows for it to be transferred between C++ and JavaScript.

void CoherentBind(Coherent::UIGT::Binder* binder, GameOptions* options)
{
// Specify the exposed name of the type
if(auto type = binder->RegisterType("GameOptions", options))
{
// expose normal data properties
type.Property("Backend", &GameOptions::Backend)
.Property("Width", &GameOptions::Width)
.Property("Height", &GameOptions::Height)
// expose read-only property with getter function
.PropertyReadOnly("Username", &GameOptions::GetUserName)
// expose read/write property with get/set functions
.Property("NetworkPort", &GameOptions::GetNetPort, &GameOptions::SetNetPort);
}
}

JavaScript functions bound to event "OptionOptions" receive an JavaScript object with the described properties and values taken from the C++ options object given to Coherent::UIGT::View::TriggerEvent.

function openOptions(options) {
$("#options").dialog( "open" );
$("#backend").text(options.Backend);
$("#gameWidth").val(options.Width);
$("#gameHeight").val(options.Height);
$("#user").text(options.Username);
$("#netPort").val(options.NetworkPort);
}
engine.on("OpenOptions", openOptions);

If JavaScript calls C++ function that takes an GameOptions as an argument, the JavaScript object must have a property __Type with the registered name for the GameOptions structure - GameOptions

function onApplyButton(){
var options = {};
options.__Type = "GameOptions";
options.Backend = $("#backend").text();
options.Width = Number($("#gameWidth").val());
options.Height = Number($("#gameHeight").val());
options.Username = $("#user").text();
options.NetworkPort = Number($("#netPort").val());
// This will call the C++ engine code with the just created structure. It'll be correclty populated
engine.call("ApplyOptions", options);
}