--- title: "Tutorial" type: docs --- # A Tutorial Introduction This tutorial walks through building a simple game from scratch. By the end, you'll understand modules, programs, rendering, and input. ## How Prosperon Starts Prosperon runs a `.ce` program file as the root actor. This is your game's entry point. There is no `config.js` or `main.js` — everything is modules you import with `use()`. ## Step 1: A Window Create `game.ce`: ```javascript var core = use('core') core.start({ title: "My Game", width: 1280, height: 720 }) ``` Run it with `prosperon game.ce`. You get a window. `core.start()` initializes the GPU backend, opens the window, and starts the main loop. ## Step 2: Drawing a Sprite Sprites are the fundamental drawable. Create one and it appears on screen — you don't issue draw calls. ```javascript var core = use('core') var sprite = use('sprite') var compositor = use('compositor') var camera = use('camera') var cam = camera.make({ pos: {x: 0, y: 0}, width: 320, height: 240 }) var player = sprite({ image: "player.png", pos: {x: 0, y: 0}, width: 32, layer: 5 }) var plan = compositor.compile({ planes: [{ name: 'game', plane: 'default', resolution: {width: 320, height: 240}, camera: cam, presentation: 'integer_scale' }] }) core.start({ title: "Sprite Test", width: 1280, height: 720, render: function() { return compositor.execute(plan) } }) ``` Key ideas: - `sprite()` creates a sprite and registers it with the engine automatically - The **compositor** describes how to render the scene: which planes, at what resolution, with what camera - Your `render` callback returns the compositor result — the engine sends it to the GPU ## Step 3: Moving the Sprite Add an `update` callback to move things each frame: ```javascript core.start({ title: "Moving Sprite", width: 1280, height: 720, update: function(dt) { player.pos.x += 60 * dt }, render: function() { return compositor.execute(plan) } }) ``` `dt` is the time elapsed since the last frame, in seconds. Multiply speeds by `dt` for frame-rate-independent movement. ## Step 4: Handling Input Use the `input` module to map physical keys to named actions, then route those actions to your game objects: ```javascript var input = use('input') input.configure({ action_map: { move_left: ['a', 'left'], move_right: ['d', 'right'], jump: ['space'] } }) var player_entity = { on_input: function(action, data) { if (action == 'move_left' && data.pressed) { player.pos.x -= 16 } if (action == 'move_right' && data.pressed) { player.pos.x += 16 } } } var p1 = input.player1() p1.possess(player_entity) ``` The input system handles keyboard, gamepad, and touch. You define actions once and bind them to any physical input. ## Step 5: Adding Sound ```javascript var sound = use('sound') sound.play("jump.wav") ``` Sounds are loaded by path. The engine caches audio data so loading the same sound twice reuses the existing data. ## Step 6: Multiple Planes Real games often need separate rendering layers — pixel art at low res, HUD at native res: ```javascript var plan = compositor.compile({ clear: {r: 0.1, g: 0.1, b: 0.2, a: 1}, planes: [ { name: 'game', plane: 'default', resolution: {width: 320, height: 240}, camera: cam, layer_sort: {'5': 'y'}, presentation: 'integer_scale' }, { name: 'hud', plane: 'hud', resolution: {width: 1280, height: 720}, camera: hud_cam, presentation: 'stretch' } ] }) ``` Sprites belong to a plane via their `plane` property. Each plane renders at its own resolution with its own camera, then composites onto the screen in order. ## Step 7: Entities For anything more than a few sprites, use the entity system. Define entity types as modules, create instances with overrides: ```javascript // entities/coin.cm var sprite = use('sprite') return { value: 1, image: "coin.png", init: function() { this.sprite = sprite({ image: this.image, pos: this.pos, width: 16, layer: 3 }) }, on_destroy: function() { this.sprite.destroy() } } ``` ```javascript // In your game program var world = use('world') var coin_proto = use('entities/coin') var c = world.add_entity(coin_proto, { pos: {x: 50, y: 80}, value: 5 }) ``` The entity's `init()` runs after overrides are applied. The prototype defines every valid field with a default — it is the schema. ## Putting It Together A complete minimal game has: 1. A `.ce` program that imports modules and calls `core.start()` 2. Sprite and entity modules (`.cm`) that define game objects 3. A compositor config that describes the rendering setup 4. Input configuration that maps keys to actions The engine does the rest: batching sprites, sorting layers, managing GPU resources, polling events, scheduling frames. ## Next Steps - [Graphics](../graphics/) — Sprites, text, shapes, tilemaps - [Compositor](../ops/) — Planes, effects, presentation modes - [Input](../input/) — Actions, players, control stacks - [Entities](../entities/) — The entity model and world system