Tutorial 02: Variables and Types
Difficulty: Beginner
Time: ~25 minutes
Prerequisites: Tutorial 01
Goal
Learn how to store values with let and const, then work with the most important beginner-friendly types: int, double, string, and bool.
let and const
Use let for mutable variables:
let score: int = 0
let running: bool = trueUse const for compile-time constants:
const MAX_ROUNDS: int = 5
const GREETING: string = "Welcome!"The practical difference:
letcan change laterconstcannot change and must be a literal constant
int
int is the default numeric type for counters, timers, rounds, health-like values, and scoreboard-oriented logic.
let lives: int = 3
let wave: int = 1
wave = wave + 1Use int first unless you know you need fractional values or higher precision.
double
double is useful when you need floating-point precision.
let gravity: double = 9.81
let launch_angle: double = 45.0 as doubleRedScript does not do implicit numeric conversion. Cast intentionally:
let count: int = 5
let precise: double = count as doubleIf you only need whole numbers, stick with int. It is simpler and usually cheaper.
string
Use string for names, messages, and IDs.
let player_name: string = "Alex"
let item_id: string = "minecraft:golden_apple"For output, prefer f-strings:
let score: int = 12
say(f"Current score: {score}")bool
bool stores true or false.
let running: bool = false
let debug_mode: bool = trueBooleans work naturally in conditions:
if (debug_mode) {
say("Debug mode is enabled")
}Type Inference
You do not always have to write the type if the initializer is obvious:
let coins = 10
let title = "Shop"
let enabled = trueFor tutorials and early learning, explicit annotations are often clearer.
Small State Example
namespace tutorial02
const START_LIVES: int = 3
let lives: int = START_LIVES
let level_name: string = "Training Grounds"
let active: bool = false
let spawn_x: double = 12.5
@load
fn setup() {
active = true
say(f"Loaded {level_name}")
say(f"Lives: {lives}")
}This example shows a common pattern:
- constants for stable config
- mutable variables for game state
- strings for readable messages
- booleans for mode flags
- doubles for exact positions or calculations when needed
Updating Variables
@on_trigger("lose_life")
fn lose_life() {
if (lives > 0) {
lives = lives - 1
say(f"Lives left: {lives}")
}
}Casting Between int and double
fn average(total: int, players: int) -> double {
return total as double / players as double
}The explicit casts matter. They tell the compiler exactly which arithmetic model you want.
Full Example
namespace tutorial02
const START_LIVES: int = 3
const PACK_NAME: string = "Training Pack"
let lives: int = START_LIVES
let active: bool = false
let accuracy: double = 0.95
@load
fn setup() {
active = true
say(f"{PACK_NAME} loaded")
say(f"Accuracy target: {accuracy}")
}
@on_trigger("status")
fn status() {
tell(@s, f"Lives: {lives}")
tell(@s, f"Active: {active}")
}
@on_trigger("lose_life")
fn lose_life() {
if (lives > 0) {
lives = lives - 1
tell(@s, f"Lives left: {lives}")
}
}Practice
- Add a
const PACK_VERSION: string. - Add a
doublefor movement speed or radius. - Add a
boolthat toggles a debug message.