import { emptyProject, entity, activeScene, type Asset } from "./schema.ts"; import { sliceImage } from "./two-d.ts"; /** Small original pixel-art sheet for the runnable 2D example; no external assets. */ const sheet = "iVBORw0KGgoAAAANSUhEUgAAAGAAAAAQCAYAAADpunr5AAAAw0lEQVR4nGNgGOGgeHPBf0rw0nQHijCGg74d7f+PDxPy0FDTPxoBwyQCLs0KJwmTFAGSaqZgTG4ADGb9MU6O/ynBoxEwyCJgWrQjXkxWBAzmIoRS/aMRMBoBmI733HgVKyYUCENRPywgS4I9UPBoBIxGwNAIQGpFwGgRNBoBhD0Awrg8P1T1D6oIAAF8jicUAENRP7EB7WBoBcf4IoDijpiqVdx/GMYnhg8gq6dELz3sH42AAbafWkUQ1QbjRiOAvhEAAD+44yBoQmIqAAAAAElFTkSuQmCC"; export function project2D(example = false) { const p = emptyProject(); p.name = example ? "2D Platformer" : "2D Project"; const scene = activeScene(p); scene.name = "2D Scene"; scene.mode = "2d"; p.settings.background = "#233546"; p.settings.physics2d = { gravity: [0, -9.81] }; if (!example) return p; const a: Asset = { id: "sprites_2d", kind: "image", name: "platformer.png", uri: "data:image/png;base64," + sheet, image: { width: 96, height: 16, pixelsPerUnit: 16, filter: "nearest", frames: sliceImage(96, 16, 16, 16), }, }; p.assets = [a]; const sprite = (frame: number, size = [1, 1]) => ({ assetId: a.id, frame, size, }); const player = entity( "Player", { sprite: sprite(0, [1, 1.5]), spriteAnimator: { autoplay: "idle", autoStates: true, clips: [ { name: "idle", frames: [0], fps: 4, loop: true }, { name: "run", frames: [1, 2], fps: 10, loop: true }, { name: "jump", frames: [3], fps: 1, loop: true }, ], }, collider2d: { shape: "capsule", radius: 0.3, height: 1.4 }, rigidbody2d: { type: "kinematic", lockRotation: true }, character2d: { mode: "platformer", controls: true, speed: 5, jumpSpeed: 9, gravity: 20, autostep: 0.15, }, }, [3, 2, 0], "player_2d", ); const ground = entity( "Tilemap", { tilemap: { assetId: a.id, width: 26, height: 10, tileSize: [1, 1], cells: [ ...Array.from({ length: 26 }, (_, x) => ({ x, y: 0, frame: 4 })), ...Array.from({ length: 4 }, (_, x) => ({ x: x + 7, y: 2, frame: 4, })), ...Array.from({ length: 4 }, (_, x) => ({ x: x + 18, y: 3, frame: 4, })), ], collisions: true, layer: -1, }, }, [0, -1, 0], "tilemap_2d", ); const platform = entity( "One-way platform", { sprite: { ...sprite(4, [3, 0.3]), color: "#90bdc8" }, collider2d: { shape: "box", size: [3, 0.3], oneWay: true }, rigidbody2d: { type: "fixed" }, }, [14, 3, 0], "platform_2d", ); const crate = entity( "Dynamic crate", { sprite: sprite(5), collider2d: { shape: "box", size: [1, 1] }, rigidbody2d: { type: "dynamic", mass: 1, lockRotation: false }, }, [5, 4, 0], "crate_2d", ); const camera = entity( "Camera 2D", { camera: { mode: "2d", orthoWidth: 22, targetId: player.id, offset: [5, 3, 0], bounds: [11, 4, 15, 4], }, }, [11, 4, 20], "camera_2d", ); const background = entity( "3D object in the same scene", { mesh: { type: "box", size: [2, 2, 2] }, material: { color: "#45647c", roughness: 1 }, }, [20, 5, -4], "background_3d", ); background.transform.rotation = [0.3, 0.4, 0.2]; scene.entities = [ground, player, platform, crate, camera, background]; return p; }