SMILE 2.0Learn & build
Language guide

03 / Make the rules

Decisions, loops & routines

Games are rules in motion. Choose what happens, repeat it when needed, and give useful actions names you can call again.

If chooses what happens next

Imagine the player has 30 health. Your game can show a different message when health is low or reaches zero. Each condition is a Boolean question. SMILE takes the first true branch, then continues after End If.

Dim Health As Number

Health = 30

If Health <= 0 Then
    Print "Game over"
Else If Health < 10 Then
    Print "Find a potion"
Else
    Print "Ready for adventure"
End If
Health ≤ 0?Yes → Game over
Health < 10?Yes → Find a potion
OtherwiseReady for adventure
Try health values 0, 5, and 30. Only one message prints each time.

The order matters. A health value of zero is also below ten; checking zero first makes the game-over rule win. Else If and Else are optional, but every multiline If needs End If.

Select Case matches one value to several choices

Use Select Case when you are comparing the same value with a menu of alternatives. This example chooses an action from text already stored in Choice; it does not ask the player to type.

Dim Choice As Text

Choice = "Attack"

Select Case Choice
    Case "Attack"
        Print "You swing your sword."
    Case "Defend"
        Print "You raise your shield."
    Case Else
        Print "Choose Attack or Defend."
End Select

A matching branch runs without falling through into the next one. Case Else catches values with no listed match. The selector and case values must have matching types. Enums work well here once your game's states have names.

For repeats a known number of times

A For loop counts through whole Number values. Both endpoints are included. The first loop below prints 1, 2, 3; the second prints 3, 2, 1.

Dim Turn As Number

For Turn = 1 To 3
    Print Turn
End For

For Turn = 3 Down To 1
    Print Turn
End For

Use To to count upward by one and Down To to count downward by one. For an array of three elements, count from 0 To 2. Exit For leaves the nearest active For loop early.

Do repeats until you are finished

A Do ... Loop Until loop checks its stopping condition at the bottom. That means its body runs at least once. This small countdown prints 3, 2, 1.

Dim Countdown As Number

Countdown = 3

Do
    Print Countdown
    Countdown = Countdown - 1

Loop Until Countdown = 0

Sometimes the loop must check a rule before taking another turn. Put an If and Exit Do near the top. This version starts at 30 health, takes damage in chunks of ten, and stops before taking another turn at zero:

Dim Health As Number

Health = 30

Do
    If Health <= 0 Then
        Exit Do
    End If

    Health = Max(0, Health - 10)
    Print "Health: "; Health

Loop
Current syntax boundary.

Use Do, Loop, Loop Until, and Exit Do in SMILE 2.0. A While ... End While block or Do While is not part of this documented language surface. Also, old BASIC console Input, data-list Data, and Read statements are not implemented. Keyboard game input is covered below.

A loop needs a way to finish or keep the game responsive. Forgetting to update a stopping value can make the same instructions run forever. In a graphical game, input, updating, drawing, and Show Screen belong together in the main loop.

Give a group of instructions a name

A Sub performs an action. A Function calculates and returns a value. Parameters are named inputs; arguments are the values supplied in a call.

Dim Score As Number
Dim Reward As Number

Score = 10

Call GiveBonus(Score)

Reward = PointsFor(3)
Print Score
Print Reward

Sub GiveBonus(ByRef Total As Number, Optional Amount As Number = 5)

    Total = Total + Amount

End Sub

Function PointsFor(TurnNumber As Number) As Number

    Dim Result As Number

    Result = TurnNumber * 10

    Return Result

End Function

GiveBonus uses ByRef, so Total refers to the caller's actual Score variable. The call adds five points to Score. PointsFor(3) returns 30. Storing that result in Reward makes it available for printing, adding to a score, or inspecting in the debugger.

FeatureMeaning
Call Name(...)Run a Sub.
Name(...) in an expressionUse a Function's returned value.
Return ValueFinish a Function and send its result back.
ByVal, or no mode writtenPass the value. For Number, Boolean, Text, Double, Enum and Type, changing the parameter does not change the caller's value.
ByRefPass a writable location of exactly the declared type. A literal such as 10 cannot be a ByRef destination.
Routine-local DimA variable visible from its declaration through the end of that routine.

A Function declares its result type using As. For a calculated return value, this guide follows SMILE's formatting convention: calculate into a named local variable, then return that variable. Keeping the steps separate makes the value easy to inspect.

Optional and named arguments make calls readable

An Optional parameter supplies a default when the caller leaves it out. A named argument uses the parameter's name followed by :=.

Call Announce(65)
Call Announce(Caption:="Round score", Value:=65)

Sub Announce(Value As Number, Optional Caption As Text = "Score")

    Print Caption + ": "; Value

End Sub

The first call prints Score: 65; the second prints Round score: 65. In the second call, the names explain each argument even though the order differs from the declaration.

  • Put all required parameters before optional parameters.
  • Give each optional parameter an explicit type and a compile-time default.
  • Optional parameters are ByVal; they cannot be ByRef.
  • If you mix positional and named arguments, put positional arguments first.
  • Supply a parameter at most once. Named arguments belong to user routines and member routines; built-in functions use positional arguments.
  • Explicit arguments are evaluated once, in the order written in the call.

Class values have shared-reference behavior even with ByVal. Learn that distinction in Types and Classes before passing objects around.

A game reads keys one frame at a time

Get Key Key puts a queued key event into a Number variable. Key_Held(KEY_RIGHT) asks whether Right is currently held. Use events for a one-time action such as accepting a menu choice; use held state for continuous movement.

This is a fragment for inside a Game Window loop, with Key and PlayerX declared as Number. The Star Collector lesson provides the complete runnable game around it.

Get Key Key

If Key = KEY_ESCAPE Then
    Exit Do
End If

If Key_Held(KEY_RIGHT) Then
    PlayerX = PlayerX + 4
End If

Movement of four pixels per loop is fine for understanding the rule. A larger game should use elapsed time so speed does not depend on frame rate. Escape exits the loop; the program can then release resources and finish.

Try all the rules together

Download the complete turns example. Compile it as a single source, as shown on the start page. It demonstrates If, Select Case, both counting directions, Exit Do, a Function, ByRef, optional parameters, and named arguments.

Check the expected output
Ready for adventure
You swing your sword.
Round score: 65
Health: 20
Health: 10
Health: 0
Countdown: 3
Countdown: 2
Countdown: 1

Your mission: a bigger bonus

Change the default bonus from 5 to 20 by supplying a named argument at the call site. Keep the Sub's default unchanged. Predict the final score.

Reveal one solution
Call GiveBonus(Total:=Score, Amount:=20)

The three turn rewards are 10 + 20 + 30 = 60. This call adds 20, so the announced score becomes 80.

Next: organize heroes, states, and reusable modules →

Sources & version notes

Checked against the local SMILE 2.0 source on September 25, 2026. Examples target the native Windows toolchain unless stated otherwise. The linked repository may continue to evolve.