136 lines
3.6 KiB
TypeScript
136 lines
3.6 KiB
TypeScript
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;
|
|
}
|