Game Loop¶
As every game functions generally in a loop, the game loop is the core of your Scorbit integration. This is where you'll update game state and send data to the Scorbit cloud service. The game loop should run continuously updating scores, modes, and player states, and committing changes at the end of each frame.
Basic Structure¶
// Initial setup before entering to game loop
sb_device_info_t device_info = {
.provider = "your_provider", // Required: your provider name
.machine_id = 1234, // Required: your machine ID
.game_code_version = "1.0.0", // Required: version tracking
.hostname = "staging", // Optional: staging, production, or custom URL
.uuid = NULL, // Optional: will be auto-generated if NULL
.serial_number = 0 // Optional: device serial number
};
// Use encrypt_tool to generate your encrypted key from your private key
const char* encrypted_key = "your_encrypted_key_here";
// Create game state object with encrypted key
sb_game_handle_t state = sb_create_game_state2(encrypted_key, &device_info);
// Main game loop
while (1) {
if (game_finished()) {
sb_set_game_finished(state);
}
if (game_started()) {
sb_set_game_started(state);
}
if ()
// Update scores, modes, and player states
update_game_state(state);
// IMPORTANT: call commit unconditionally at the end of each cycle
sb_commit(state);
}
// Cleanup when done
sb_destroy_game_state(state);
void game_loop() {
// Initialize game state with your device info
scorbit::DeviceInfo info;
info.provider = "your_provider"; // Required: your provider name
info.machineId = 1234; // Required: your machine ID
info.gameCodeVersion = "1.0.0"; // Required: version tracking
info.hostname = "staging"; // Optional: staging, production, or custom URL
info.uuid = ""; // Optional: will be auto-generated if empty
info.serialNumber = 0; // Optional: device serial number
// Use encrypt_tool to generate your encrypted key from your private key
std::string encrypted_key = "your_encrypted_key_here";
// Create game state object with encrypted key
auto gs = scorbit::createGameState(encrypted_key, std::move(info));
// Main game loop
while (game_is_running) {
// Update scores, modes, and player states
update_game_state(gs);
// Commit changes at the end of each frame
gs.commit();
// Optional: Add a small delay to control update frequency
std::this_thread::sleep_for(std::chrono::microseconds(16667)); // ~60fps
}
}
def game_loop():
# Initialize game state with your device info
info = scorbit.DeviceInfo()
info.provider = "your_provider" # Required: your provider name
info.machine_id = 1234 # Required: your machine ID
info.game_code_version = "1.0.0" # Required: version tracking
info.hostname = "staging" # Optional: staging, production, or custom URL
info.uuid = "" # Optional: will be auto-generated if empty
info.serial_number = 0 # Optional: device serial number
# Use encrypt_tool to generate your encrypted key from your private key
encrypted_key = "your_encrypted_key_here"
# Create game state object with encrypted key
gs = scorbit.create_game_state(encrypted_key, info)
# Main game loop
while game_is_running:
# Update scores, modes, and player states
update_game_state(gs)
# Commit changes at the end of each frame
gs.commit()
# Optional: Add a small delay to control update frequency
time.sleep(0.016667) # ~60fps
Key Concepts¶
1. Initialization¶
- Create a game state object at startup with device info and encrypted key
- Configure your device info with provider name and machine ID
- Set up any necessary callbacks (e.g., logging)
2. State Updates¶
- Update player scores
- Manage active modes
- Track current ball and player
- Handle game start/end conditions
3. Commit Frequency¶
- Call
commit()
at the end of each frame - Changes are only sent if state has been modified
- Typical update rate is 60fps (every ~16.7ms)
4. Status Monitoring¶
- Check connection status periodically (see Pairing & Status)
- Avoid checking more frequently than once per second
- Update UI indicators based on connection state
Logging¶
The SDK provides logging capabilities to help debug your integration. You can set up logging before creating your game state:
void loggerCallback(const char *message, sb_log_level_t level, const char *file, int line,
void *userData) {
// Handle log messages - example implementation:
printf("[%s] %s\n",
level == SB_DEBUG ? "DBG" :
level == SB_INFO ? "INF" :
level == SB_WARN ? "WRN" :
level == SB_ERROR ? "ERR" : "UNK",
message);
}
// Add logger before creating game state
sb_add_logger_callback(loggerCallback, NULL);
void loggerCallback(const std::string &message, scorbit::LogLevel level,
const char *file, int line, void *userData) {
// Handle log messages - example implementation:
std::cout << "[" << (
level == scorbit::LogLevel::Debug ? "DBG" :
level == scorbit::LogLevel::Info ? "INF" :
level == scorbit::LogLevel::Warn ? "WRN" :
level == scorbit::LogLevel::Error ? "ERR" : "UNK"
) << "] " << message << std::endl;
}
// Add logger before creating game state
scorbit::addLoggerCallback(loggerCallback);
def logger_callback(message, level, file, line):
# Handle log messages - example implementation:
level_str = {
scorbit.LogLevel.Debug: "DBG",
scorbit.LogLevel.Info: "INF",
scorbit.LogLevel.Warn: "WRN",
scorbit.LogLevel.Error: "ERR"
}.get(level, "UNK")
print(f"[{level_str}] {message}")
# Add logger before creating game state
scorbit.add_logger_callback(logger_callback)
The logger callback receives the following parameters:
Parameter | Type | Description |
---|---|---|
message |
string | The log message text |
level |
enum | Log severity (Debug, Info, Warning, Error) |
file |
string | Source file generating the log |
line |
integer | Line number in source file |
userData |
pointer | Optional context (C only) |
The callback is thread-safe and can be used to route logs to your preferred destination (console, file, etc.).
Example Integration¶
Here's a more detailed example showing common game state updates, including scores, players, modes and ball tracking:
void update_game_state(sb_game_handle_t state) {
// Handle game session state
if (is_game_starting()) {
sb_set_game_started(state);
}
if (is_game_active()) {
// Update current player and ball
sb_set_active_player(state, current_player);
sb_set_current_ball(state, current_ball);
// Update scores
sb_set_score(state, 1, player1_score, 0);
// Manage modes
if (multiball_active) {
sb_add_mode(state, "MB:Multiball");
}
}
if (is_game_ending()) {
sb_set_game_finished(state);
}
}
void update_game_state(scorbit::GameState& gs) {
// Handle game session state
if (is_game_starting()) {
gs.setGameStarted();
}
if (is_game_active()) {
// Update current player and ball
gs.setActivePlayer(current_player);
gs.setCurrentBall(current_ball);
// Update scores
gs.setScore(1, player1_score);
// Manage modes
if (multiball_active) {
gs.addMode("MB:Multiball");
}
}
if (is_game_ending()) {
gs.setGameFinished();
}
}
def update_game_state(gs):
# Handle game session state
if is_game_starting():
gs.set_game_started()
if is_game_active():
# Update current player and ball
gs.set_active_player(current_player)
gs.set_current_ball(current_ball)
# Update scores
gs.set_score(1, player1_score)
# Manage modes
if multiball_active:
gs.add_mode("MB:Multiball")
if is_game_ending():
gs.set_game_finished()
Note
The game loop should run continuously while your game is active. Make sure to properly clean up resources when shutting down.
Tip
While the examples show a 60fps update rate, you can adjust this based on your needs. Just ensure you're calling commit()
frequently enough to capture all important game state changes.