Game Logic In JavaScript
We'll implement the rules of the game in JavaScript as well. The general philosophy of Slint is that merely the user
interface is implemented in the .slint
language and the business logic in your favorite programming
language. The game rules shall enforce that at most two tiles have their curtain open. If the tiles match, then we
consider them solved and they remain open. Otherwise we wait for a little while, so the player can memorize
the location of the icons, and then close them again.
We'll modify the .slint
markup in the memory.slint
file to signal to the JavaScript code when the user clicks on a tile.
Two changes to MainWindow are needed: We need to add a way for the MainWindow to call to the JavaScript code that it should
check if a pair of tiles has been solved. And we need to add a property that JavaScript code can toggle to disable further
tile interaction, to prevent the player from opening more tiles than allowed. No cheating allowed! First, we paste
the callback and property declarations into MainWindow:
export component MainWindow inherits Window {
width: 326px;
height: 326px;
callback check_if_pair_solved(); // Added
in property <bool> disable_tiles; // Added
in-out property <[TileData]> memory_tiles: [
{ image: @image-url("icons/at.png") },
The last change to the .slint
markup is to act when the MemoryTile signals that it was clicked on.
We add the following handler in MainWindow:
for tile[i] in memory_tiles : MemoryTile {
x: mod(i, 4) * 74px;
y: floor(i / 4) * 74px;
width: 64px;
height: 64px;
icon: tile.image;
open_curtain: tile.image_visible || tile.solved;
// propagate the solved status from the model to the tile
solved: tile.solved;
clicked => {
// old: tile.image_visible = !tile.image_visible;
// new:
if (!root.disable_tiles) {
tile.image_visible = !tile.image_visible;
root.check_if_pair_solved();
}
}
}
On the JavaScript side, we can now add an handler to the check_if_pair_solved
callback, that will check if
two tiles are opened. If they match, the solved
property is set to true in the model. If they don't
match, start a timer that will close them after one second. While the timer is running, we disable every tile so
one can't click anything during this time.
Insert this code before the mainWindow.run()
call:
let model = new slint.ArrayModel(tiles);
mainWindow.memory_tiles = model;
mainWindow.check_if_pair_solved.setHandler(function () {
let flipped_tiles = [];
tiles.forEach((tile, index) => {
if (tile.image_visible && !tile.solved) {
flipped_tiles.push({
index,
tile
});
}
});
if (flipped_tiles.length == 2) {
let {
tile: tile1,
index: tile1_index
} = flipped_tiles[0];
let {
tile: tile2,
index: tile2_index
} = flipped_tiles[1];
let is_pair_solved = tile1.image === tile2.image;
if (is_pair_solved) {
tile1.solved = true;
model.setRowData(tile1_index, tile1);
tile2.solved = true;
model.setRowData(tile2_index, tile2);
} else {
mainWindow.disable_tiles = true;
slint.Timer.singleShot(1000, () => {
mainWindow.disable_tiles = false;
tile1.image_visible = false;
model.setRowData(tile1_index, tile1);
tile2.image_visible = false;
model.setRowData(tile2_index, tile2);
})
}
}
});
mainWindow.run();
These were the last changes and running the result gives us a window on the screen that allows us to play the game by the rules.