docs/astro/src/content/docs/tutorial/game_logic.mdx
import { Tabs, TabItem } from '@astrojs/starlight/components'; import { extractLines } from '@slint/common-files/src/utils/utils.ts'; import { Code } from '@astrojs/starlight/components'; import LangRefLink from '@slint/common-files/src/components/LangRefLink.astro';
This step implements the rules of the game in your coding language of choice.
Slint's general philosophy is that you implement the user interface in Slint and the business logic in your favorite programming language.
The game rules enforce that at most two tiles have their curtain open. If the tiles match, then the game considers them solved and they remain open. Otherwise, the game waits briefly so the player can memorize the location of the icons, and then closes the curtains again.
<Tabs syncKey="dev-language"> <TabItem label="Rust" icon="seti:rust">Add the following code inside the <span class="hljs-title">MainWindow</span> component to signal to the Rust code when the user clicks on a tile.
<Code code={extractLines(gameLogicInRust, 107, 115)} lang="slint" />
This change adds a way for the <span class="hljs-title">MainWindow</span> to call to the Rust code that it should check if a player has solved a pair of tiles. The Rust code needs an additional property to toggle to disable further tile interaction, to prevent the player from opening more tiles than allowed. No cheating allowed!
The last change to the code is to act when the <span class="hljs-title">MemoryTile</span> signals that a player clicked it.
Add the following handler in the <span class="hljs-title">MainWindow</span> for loop clicked handler:
<Code code={extractLines(gameLogicInRust, 126, 143)} lang="slint" />
On the Rust side, you can now add a handler to the check_if_pair_solved callback, that checks if a player opened two tiles.
If they match, the code sets the solved property to true in the model. If they don't
match, start a timer that closes the tiles after one second. While the timer is running, disable every tile so
a player can't click anything during this time.
Add this code before the main_window.run().unwrap(); call:
<Code code={extractLines(gameLogicInRust, 25, 52)} lang="rust" />
The code uses a <LangRefLink lang="rust-slint" relpath="struct.Weak">Weak</LangRefLink> pointer of the main_window. This is
important because capturing a copy of the main_window itself within the callback handler would result in circular ownership.
The MainWindow owns the callback handler, which itself owns a reference to the MainWindow, which must be weak
instead of strong to avoid a memory leak.
Add the following code inside the <span class="hljs-title">MainWindow</span> component to signal to the C++ code when the user clicks on a tile.
import gameLogicInRust from '/src/content/code/main_game_logic_in_rust.rs?raw'
<Code code={extractLines(gameLogicInRust, 107, 115)} lang="slint" />
This change adds a way for the <span class="hljs-title">MainWindow</span> to call to the C++ code that it should check if a player has solved a pair of tiles. The Rust code needs an additional property to toggle to disable further tile interaction, to prevent the player from opening more tiles than allowed. No cheating allowed!
The last change to the code is to act when the <span class="hljs-title">MemoryTile</span> signals that a player clicked it.
Add the following handler in the <span class="hljs-title">MainWindow</span> for loop clicked handler:
<Code code={extractLines(gameLogicInRust, 126, 143)} lang="slint" />
On the C++ side, you can now add a handler to the check_if_pair_solved callback, that checks if a player opened two tiles.
If they match, the code sets the solved property to true in the model. If they don't
match, start a timer that closes the tiles after one second. While the timer is running, disable every tile so
a player can't click anything during this time.
Insert this code before the main_window->run() call:
import gameLogicInCpp from '/src/content/code/main_game_logic.cpp?raw'
<Code code={extractLines(gameLogicInCpp, 29, 65)} lang="cpp" />
The code uses a <LangRefLink lang="cpp" relpath="api/slint/componentweakhandle/">ComponentWeakHandle</LangRefLink> pointer of the main_window. This is
important because capturing a copy of the main_window itself within the callback handler would result in circular ownership.
The MainWindow owns the callback handler, which itself owns a reference to the MainWindow, which must be weak
instead of strong to avoid a memory leak.
Change the contents of memory.slint to signal to the JavaScript code when the user clicks on a tile.
<Code code={extractLines(gameLogicInRust, 107, 115)} lang="slint" />
This change adds a way for the <span class="hljs-title">MainWindow</span> to call to the JavaScript code that it should check if a player has solved a pair of tiles. The Rust code needs an additional property to toggle to disable further tile interaction, to prevent the player from opening more tiles than allowed. No cheating allowed!
The last change to the code is to act when the <span class="hljs-title">MemoryTile</span> signals that a player clicked it.
Add the following handler in the <span class="hljs-title">MainWindow</span> for loop clicked handler:
<Code code={extractLines(gameLogicInRust, 126, 143)} lang="slint" />
On the JavaScript side, now add a handler to the check_if_pair_solved callback, that checks if a player opened two tiles. If they match, the code sets the solved property to true in the model. If they don't
match, start a timer that closes the tiles after one second. While the timer is running, disable every tile so
a player can't click anything during this time.
Insert this code before the mainWindow.run() call:
import gameLogicInJs from '/src/content/code/main_game_logic.js?raw'
<Code code={extractLines(gameLogicInJs, 24, 57)} lang="js" /> </TabItem>
<TabItem label="Python" icon="seti:python">Change the contents of memory.slint to signal to the Python code when the user clicks on a tile.
<Code code={extractLines(gameLogicInRust, 107, 115)} lang="slint" />
This change adds a way for the <span class="hljs-title">MainWindow</span> to call to the Python code that it should check if a player has solved a pair of tiles. The Rust code needs an additional property to toggle to disable further tile interaction, to prevent the player from opening more tiles than allowed. No cheating allowed!
The last change to the code is to act when the <span class="hljs-title">MemoryTile</span> signals that a player clicked it.
Add the following handler in the <span class="hljs-title">MainWindow</span> for loop clicked handler:
<Code code={extractLines(gameLogicInRust, 126, 143)} lang="slint" />
On the Python side, now add a handler to the check_if_pair_solved callback, that checks if a player opened two tiles. If they match, the code sets the solved property to true in the model. If they don't
match, start a timer that closes the tiles after one second. While the timer is running, disable every tile so
a player can't click anything during this time.
Insert this function in the MainWindow class, annotated with @slint.callback to associated it with check_if_pair_solved:
import gameLogicInPython from '/src/content/code/main_game_logic.py?raw'
<Code code={extractLines(gameLogicInPython, 13, 52)} lang="python" /> </TabItem> </Tabs>
These were the last changes and running the code opens a window that allows a player to play the game by the rules.