Bonus Chapter: How to prepare your UI to work with a backend
With our UI complete we can now start integrating it into our game. But before we can do that we need to make a few changes to our FrontEnd code.
Setting our body to be transparent
For the purpose of this guide we made our UI to have a black background. This allowed us to be able to demonstrate the different features that we made more easily.
This however won’t allow us to use the same UI in a game, as it won’t show the game underneath. To fix that we’ll change the body
background-color to transparent in our style.css
file:
background-color: transparent;
Removing the models and mocked data
Since our models will now be created on the backend, we can remove the model
and map
constants we declared in the model.js
file.
Then we just need to remove the creation of the mock models and we’ll be left with the following code in our model.js
function getCurrentTime() {
const date = new Date();
return `${date.getHours()}:${date.getMinutes()}`;
}
function updateCurrentTime() {
setInterval(() => {
PlayerModel.time = getCurrentTime();
engine.updateWholeModel(PlayerModel);
engine.synchronizeModels();
}, 60000);
}
engine.whenReady.then(() => {
engine.registerBindingAttribute('poi', POIHandler);
engine.createObservableModel("activeItem");
PlayerModel.time = getCurrentTime();
updateCurrentTime();
engine.updateWholeModel(PlayerModel);
engine.synchronizeModels();
});
Here as you can see we are leaving the time update function, because we want to use the built in JavaScript functions to get the time.
We are also leaving the engine.registerBindingAttribute
and the engine.createObservableModel
functions since they have to be used on the Front End. However, since the observable model’s properties need to be synchronized with the model properties from the backend (as to not have a desynchronization between the game and UI), we also need to add a so-called synchronization dependency, in order to be updated accordingly like this:
engine.whenReady.then(() => {
engine.registerBindingAttribute('poi', POIHandler);
engine.createObservableModel("activeItem");
engine.addSynchronizationDependency(PlayerModel, activeItem);
PlayerModel.time = getCurrentTime();
updateCurrentTime();
engine.updateWholeModel(PlayerModel);
engine.synchronizeModels();
});
Removing the mocked event listeners
In the previous chapters of the guide we demonstrated how to trigger and listen for events. Since we want to integrate our UI with a game engine we need to remove some of them as the engine will have to handle them now.
In the script.js
file we’ll start by removing the pause_toggle
event.
Next in the same file, we can remove the change_menu
event listener as well.
Expecting events to attach slider listeners
The attachSliderListeners
function will now become an engine.on
function, which will expect an event with the same name to be invoked from the backend, to indicate when the slider event listeners should be attached:
function attachSliderListeners() {
const sliderVolume = document.querySelector(".slider-volume");
const volumeValue = document.querySelector(".volume-value");
sliderVolume.addEventListener("sliderupdate", (e) => {
volumeValue.textContent = e.detail;
});
const sliderDifficulty = document.querySelector(".slider-difficulty");
const difficultyValue = document.querySelector(".difficulty-value");
sliderDifficulty.addEventListener("sliderupdate", (e) => {
difficultyValue.textContent = e.detail;
});
}
This is changed to:
engine.on("attachSliderListeners", () => {
const sliderVolume = document.querySelector(".slider-volume");
const volumeValue = document.querySelector(".volume-value");
sliderVolume.addEventListener("sliderupdate", (e) => {
volumeValue.textContent = e.detail;
});
const sliderDifficulty = document.querySelector(".slider-difficulty");
const difficultyValue = document.querySelector(".difficulty-value");
sliderDifficulty.addEventListener("sliderupdate", (e) => {
difficultyValue.textContent = e.detail;
});
});
Adding new event triggers
The last step of the process would be to add new event triggers to the mapDrag
and zoom
functions in the script.js
file. This will allow us to make changes to the model inside the engine.
To do that we’ll start by removing the following code from the mapDrag
function:
MapModel.x = clamp(MapModel.x + event.clientX - startX, -limitX, 0);
MapModel.y = clamp(MapModel.y + event.clientY - startY - offsetY, -limitY, 0);
and replacing it with:
engine.trigger('map_move',
clamp(MapModel.x + event.clientX - startX, -limitX, 0),
clamp(MapModel.y + event.clientY - startY - offsetY, -limitY, 0)
);
Then we can do the same for the zoom
function. Remove:
MapModel.x = clamp(MapModel.x + event.clientX * (MapModel.zoom - initialScale) * -1, -limitX, 0);
MapModel.y = clamp(MapModel.y + (event.clientY - offsetY) * (MapModel.zoom - initialScale) * -1, -limitY, 0);
and replace with:
engine.trigger('map_move',
clamp(MapModel.x + event.clientX * (MapModel.zoom - initialScale) * -1, -limitX, 0),
clamp(MapModel.y + (event.clientY - offsetY) * (MapModel.zoom - initialScale) * -1, -limitY, 0)
);
This will allow us to send the move coordinates to the engine so the model can be updated.
And last we need to do the same for the map zoom. Again in the zoom
functione we’ll replace:
MapModel.zoom = clamp(MapModel.zoom + event.deltaY * -0.01, 1, 3);
with
engine.trigger('map_zoom', clamp(MapModel.zoom + event.deltaY * -0.01, 1, 3))
And with that our UI is ready to be used inside a game.