Skip to main content

Game engine

TextToScratch ships with a game engine written in TextToScratch. Import a module and call it from any sprite:

import * as Physics from "tts/physics";
import * as Input from "tts/input";
import * as Camera from "tts/camera";

whenFlag(() => {
forever(() => {
Physics.push(Input.axisX() * 1.2, 0);
if (Input.jumpPressed()) Physics.jump(12);
Physics.step("Level");
});
});

Sky Run, the engine demo: a scrolling platformer

Try the demos

Open them in Scratch with File โ†’ Load from your computer, then click Text Code to read the source: Sky Run (scrolling platformer) ยท 3D demo ยท Multiplayer demo (share it, or use TurboWarp, to play online)

Modulesโ€‹

ImportWhat it gives you
tts/physicsgravity, friction, pixel-perfect platformer and top-down collision
tts/inputmovement axes, "pressed this frame" keys, mouse clicks
tts/camerascrolling worlds, follow/shake/zoom, big levels from tiles
tts/animcostume animations (walk1, walk2, ...) as calls or objects
tts/3dperspective projection, pen-drawn wireframes and filled triangles, 3D sprites
tts/netonline multiplayer over cloud variables (6 players + chat)
tts/mathclamp, lerp, atan2, direction, easing, box overlap
tts/datasplit/join, slices, search & replace, sorting, save codes
tts/timecooldowns, countdowns, frame delta time
tts/scenegame states (menu, playing, game over)
tts/drawpen rectangles, outlines, circles, health bars
tts/particlesclone-based particle bursts

Your own code can be organised the same way: write classes, and put shared code in src/lib/.

How it worksโ€‹

Scratch has no shared functions: every custom block belongs to one sprite. So the compiler copies each library function you use into each sprite that uses it, as a custom block named after its module (physics.step, math.clamp). Only what you use is included, so an unused module adds nothing to your project.

In a library moduleBecomes
export function f()a custom block, copied into each sprite that calls it
let x = 0 / export let x = 0a variable for this sprite only, so each sprite (and clone) has its own copy (physics.vx)
export const state = { ... }global variables, shared by every sprite (camera.view.cameraX)
const N = 5inlined constant
export class Ca class; each object created with new gets its own variables

That's why Physics.vx belongs to the sprite that calls Physics.step(): every sprite (and every clone) has its own physics body.

Your own librariesโ€‹

Put shared code in src/lib/. Files there aren't sprites; any sprite can import them:

src/lib/combat.ts
export const DAMAGE = 10;

export function knockback(fromX: number) {
me.x += me.x > fromX ? 20 : -20;
}
src/Player.ts
import { knockback } from "./lib/combat";
onMessage("hit", () => knockback(0));

Library files can contain declarations only: functions, classes, variables and types. Events like whenFlag belong in sprite files.