Skip to content

Class System

ScaffScript provides a class syntax that compiles to GML struct constructors. Classes can also be extended across multiple files using impl.

export class <name> {
constructor([<args>])
<field> = <value>;
<method>() { ... }
}

The constructor(...) line defines the parameters of the GML constructor function.


Plain assignments, become direct assignments inside the constructor body:

index.ss
// --- snip ---
name = _name;
age = _age;
// --- snip ---

All three forms of functions compile to <name> = function( ... ) { ... }:

index.ss
// --- snip ---
print = function() {
show_debug_message($"Name: {name}");
}
show_name(_name?) {
show_debug_message(_name ?? name);
}
show_age = (age, test = false) => {
show_debug_message(age);
show_debug_message(test);
}
// --- snip ---
index.ss
// --- snip ---
// function expression, unchanged
print = function() {
show_debug_message($"Name: {name}");
}
// shorthand, converted to function expression
show_name(_name?) {
show_name = function(_name = undefined) {
show_debug_message(_name ?? name);
}
// arrow function, converted to function expression
show_age = (age, test = false) => {
show_age = function(age, test = false) {
show_debug_message(age);
show_debug_message(test);
}
// --- snip ---

Add static keyword before the field / method name.

index.ss
// --- snip ---
static created_cnt = 0;
static print = function() {
show_debug_message($"Name: {name}");
}
static show_name(_name?) {
show_debug_message(_name ?? name);
}
static show_age = (age, test = false) => {
show_debug_message(age);
show_debug_message(test);
}
// --- snip ---
index.ss
// --- snip ---
static created_cnt = 0;
static print = function() {
show_debug_message($"Name: {name}");
}
static show_name(_name?) {
static show_name = function(_name = undefined) {
show_debug_message(_name ?? name);
}
static show_age = (age, test = false) => {
static show_age = function(age, test = false) {
show_debug_message(age);
show_debug_message(test);
}
// --- snip ---
index.ss
export class MyClass {
constructor(_name, _age = 0, _is_active?)
static created_cnt = 0;
name = _name;
age = _age;
is_active = _is_active ?? false;
print = function() {
show_debug_message($"Name: {name}");
}
static show_name(_name?) {
show_debug_message(_name ?? "Unknown");
}
show_age = (_age, _test = false) => {
show_debug_message(_age);
show_debug_message(_test);
}
}
index.gml
function MyClass(_name, _age = 0, _is_active = undefined) constructor {
static created_cnt = 0;
name = _name;
age = _age;
is_active = _is_active ?? false;
print = function() {
show_debug_message($"Name: {name}");
}
static show_name = function(_name = undefined) {
show_debug_message(_name ?? "Unknown");
}
show_age = function(_age, _test = false) {
show_debug_message(_age);
show_debug_message(_test);
}
}

Use impl to adds properties or methods to an existing class from a separate file. Useful for splitting large classes, or managing class logic in a more organized way.

impl <ClassName> {
<field> = <value>;
<method>() { ... }
}

We’ll use this structure for this example:

  • Directorysrc/
    • Directorymy-class/
      • MyClass.ss
      • print.ss
    • index.ss
my-class/MyClass.ss
export class MyClass {
constructor(_name, _age = 0, _is_active?)
name = _name;
age = _age;
is_active = _is_active ?? false;
}
my-class/print.ss
impl MyClass {
print_cnt = 0;
print_name() {
show_debug_message($"Name: {name}");
print_cnt++;
}
print_age() {
show_debug_message($"Age: {age}");
print_cnt++;
}
}
index.gml
function MyClass(_name, _age = 0, _is_active = undefined) constructor {
name = _name;
age = _age;
is_active = _is_active ?? false;
print_cnt = 0;
print_name = function() {
show_debug_message($"Name: {name}");
print_cnt++;
}
print_age = function() {
show_debug_message($"Age: {age}");
print_cnt++;
}
}

  1. The class name must exist and match an export class in another file in the same scan.
    • So, you can’t implement a class that’s not defined.
  2. If no match is found:
    • Aborts if onNotFound: "error" (default).
    • Skips with a warning if onNotFound: "ignore".
  3. Methods defined inside impl follows the same conversion rules as regular class fields / methods.
  4. Multiple impl files for the same class are all merged in order.

  • Fields / methods redeclaration is not supported. You’ll have duplicated fields / methods if you do.

Here are some best practices to keep in mind when using classes in ScaffScript.

my-class.ss
export class MyClass {
constructor(name, score)
name = name; // already defined, so it's an undefined variable error
score = score; // also an undefined variable error
}

Using the same name for constructor parameter and field would cause an undefined variable error.

Keep impl files in the same directory as the export class file. It makes it easier to understand the class structure at a glance.

  • Directorysrc/
    • Directorymy-class/
      • MyClass.ss
    • Directorymy-class-impl/
      • Directoryfs/
        • input.ss
        • output.ss
      • logic.ss
      • print.ss
    • index.ss