Reintroduce apps/arcade and the ten game crates that were ripped out of
the fork (assets, audio, blocks, coedit, gen, net, pkg, render, script,
session), from makepad-internal/dev. Reconcile against the fork's layout:
- makepad-game-sim/math come from the fork's existing libs/sim + sim/math;
the copied internal libs/game/{sim,math} are dropped and the kept game
crates plus arcade point at ../../sim and ../../sim/math.
- arcade AI is rewritten off the removed makepad-ai agent API onto the
makepad-ai-hub headless ChatProvider worker (example/cad pattern):
AiWorker{send,cancel,poll}, ai_worker_loop driving
ClaudeApiChatProvider(ClaudeCli), AiWorkerEvent availability/delta/
done/error mapped into the chat feed and authoring land_edit, with
main.rs send_message/cancel_request/event-drain rebuilt around it.
- the game-script sandbox is adapted to the fork's jailed splash storage:
every isolate gets mod.fs = splash_storage jail; splaes splash_storage
set_root_for_heap is now public so the ScriptHost (or Splash) can grant
a per-game jail root. ENT font: build.rs/dispatch.rs entities fill new
fork sim Entity/Part fields via ..Default::default(); world_raycast now
borrows mutably and returns the material id.
cargo check -p makepad-arcade and the game + arcade test suites pass.
151 lines
8.6 KiB
Text
151 lines
8.6 KiB
Text
// Makepad Arcade — the starting world.
|
|
//
|
|
// This is a TEMPLATE, not a demo: it is what a new world begins as, and it is
|
|
// meant to be edited. Everything here is a `game.*` verb, so the AI editing
|
|
// this file can change any of it — which is the whole point. Nothing about
|
|
// this world lives in Rust.
|
|
//
|
|
// It is deliberately readable top to bottom: sky, ground, town, cars, a
|
|
// player, something to climb. If you are adding to it, add a section.
|
|
|
|
// ---------------------------------------------------------------- sky & sun
|
|
game.sky({})
|
|
// A FIXED sun, given as a direction rather than a time of day. 38 degrees of
|
|
// elevation casts a shadow about 1.3x its caster's height: long enough to show
|
|
// what shape threw it and which way the ground slopes, short enough that the
|
|
// village does not disappear into its own shade. A moving sun re-bakes the
|
|
// world's shadows continuously and nothing on screen ever settles.
|
|
game.sun({dir: vec3(0.55, 0.62, 0.56)})
|
|
|
|
// ------------------------------------------------------------------ terrain
|
|
// `feature` is how far apart the hills are, in world units. `rim` grows the
|
|
// relief toward the edge of the map: a playable basin with a scenic horizon,
|
|
// which is the answer to terrain being either boring or unbuildable. The
|
|
// plaza keeps the town's ground genuinely flat — a road is one long box and a
|
|
// house has square feet, and neither can follow a slope.
|
|
game.terrain({
|
|
size: 260,
|
|
cells: 129,
|
|
smooth: true,
|
|
seed: 1466247766,
|
|
amp: 5,
|
|
feature: 90,
|
|
flatten: 1.25,
|
|
rim: 5,
|
|
rim_start: 0.34,
|
|
plaza: {r: 66, ramp: 26, h: 0},
|
|
color: #5a8f46
|
|
})
|
|
|
|
// -------------------------------------------------------------------- roads
|
|
// A crossroads, not a corridor. A junction is the smallest thing that makes a
|
|
// place feel like it has somewhere else to be. `collide: false` makes these
|
|
// surfaces rather than kerbs the car has to climb.
|
|
game.box({pos: vec3(0, 0.02, 0), size: vec3(116, 0.1, 14), color: #4d4d52, tag: "road", collide: false})
|
|
game.box({pos: vec3(0, 0.02, 0), size: vec3(14, 0.1, 104), color: #4d4d52, tag: "road", collide: false})
|
|
game.box({pos: vec3(-20, 0.02, 11), size: vec3(8, 0.1, 22), color: #52525a, tag: "road", collide: false})
|
|
|
|
// ------------------------------------------------------------------- houses
|
|
// `find_model` returns DISTINCT models. Ask for several and place a different
|
|
// one at each lot — five identical houses read as wallpaper however good the
|
|
// model is. Four, not more: this kit runs out of houses and starts returning
|
|
// lot pieces, one of which is a swimming pool.
|
|
let houses = game.find_model("suburban house building", {count: 4, spread: "variants"})
|
|
|
|
game.model(houses[0], {pos: vec3(-30, 0, -10), yaw: 0, scale: 4.2, tag: "house"})
|
|
game.model(houses[1], {pos: vec3(-19, 0, -10), yaw: 0, scale: 4.5, tag: "house"})
|
|
game.model(houses[2], {pos: vec3(-10, 0, -10), yaw: 0, scale: 4.2, tag: "house"})
|
|
game.model(houses[3], {pos: vec3(0.5, 0, -10), yaw: 0, scale: 4.5, tag: "house"})
|
|
game.model(houses[0], {pos: vec3(10, 0, -10), yaw: 0, scale: 4.2, tag: "house"})
|
|
game.model(houses[1], {pos: vec3(19, 0, -10), yaw: 0, scale: 4.5, tag: "house"})
|
|
game.model(houses[2], {pos: vec3(30, 0, -10), yaw: 0, scale: 4.2, tag: "house"})
|
|
// North side, set well back: the third-person camera sits about 9 units behind
|
|
// you, so a row any closer is in the shot rather than behind it.
|
|
game.model(houses[3], {pos: vec3(-25, 0, 26), yaw: 3.14159, scale: 4.0, tag: "house"})
|
|
game.model(houses[0], {pos: vec3(-14.5, 0, 26), yaw: 3.14159, scale: 4.4, tag: "house"})
|
|
game.model(houses[1], {pos: vec3(14.5, 0, 26), yaw: 3.14159, scale: 4.0, tag: "house"})
|
|
game.model(houses[2], {pos: vec3(25, 0, 26), yaw: 3.14159, scale: 4.4, tag: "house"})
|
|
|
|
// ------------------------------------------------------------------ scenery
|
|
let trees = game.find_model("tree pine", {count: 4, spread: "kinds"})
|
|
game.model(trees[0], {pos: vec3(-34, 0, -26), scale: 7, tag: "tree"})
|
|
game.model(trees[1], {pos: vec3(-24, 0, -30), scale: 6, tag: "tree"})
|
|
game.model(trees[2], {pos: vec3(12, 0, -28), scale: 7, tag: "tree"})
|
|
game.model(trees[3], {pos: vec3(28, 0, -24), scale: 6, tag: "tree"})
|
|
game.model(trees[0], {pos: vec3(38, 0, 8), scale: 7, tag: "tree"})
|
|
|
|
// --------------------------------------------------------------------- cars
|
|
// `spread: "kinds"` gives one model per FAMILY — one of each type. "variants"
|
|
// would give six of the same kind, which is right for a terrace of houses and
|
|
// wrong for traffic.
|
|
//
|
|
// Every one of these is a real vehicle: walk up to any of them and the engine
|
|
// offers to let you in. Cars need no `game.interactable` — the prompt is
|
|
// derived from the car itself.
|
|
let cars = game.find_model("ambulance delivery taxi police sedan hatchback", {count: 6, spread: "kinds"})
|
|
|
|
game.car({pos: vec3(-6, 1.2, 1.6), model: cars[0], player: true})
|
|
game.car({pos: vec3(-24, 1.2, 5.2), model: cars[1]})
|
|
game.car({pos: vec3(-13, 1.2, 5.2), model: cars[2]})
|
|
game.car({pos: vec3(7.5, 1.2, 5.2), model: cars[3]})
|
|
game.car({pos: vec3(22, 1.2, 5.2), model: cars[4]})
|
|
game.car({pos: vec3(16.5, 1.2, -4.5), model: cars[5], rot_y: 3.14159})
|
|
|
|
// ------------------------------------------------------------------- people
|
|
// A bearded hero on the full hero rig. `player_character` is the whole
|
|
// third-person binding — walker, follow camera, and getting in and out of
|
|
// cars — with crafted defaults you never have to name.
|
|
let heroes = game.find_model("barbarian", {count: 1, rigged: true})
|
|
let me = game.player_character({pos: vec3(-6, 2, 9.5), model: heroes[0]})
|
|
game.label(me, "You")
|
|
|
|
// Townsfolk who wander their own patch.
|
|
let folk = game.find_model("character person", {count: 4, spread: "kinds", rigged: true})
|
|
let a = game.character({pos: vec3(-14, 2, 8), model: folk[0], tag: "villager"})
|
|
game.wander(a, {home: vec3(-14, 0, 8), range: 14, speed: 2.0})
|
|
let b = game.character({pos: vec3(4, 2, 10), model: folk[1], tag: "villager"})
|
|
game.wander(b, {home: vec3(4, 0, 10), range: 14, speed: 2.2})
|
|
let c = game.character({pos: vec3(18, 2, 6), model: folk[2], tag: "villager"})
|
|
game.wander(c, {home: vec3(18, 0, 6), range: 12, speed: 1.9})
|
|
let d = game.character({pos: vec3(-26, 2, 2), model: folk[3], tag: "villager"})
|
|
game.wander(d, {home: vec3(-26, 0, 2), range: 12, speed: 2.1})
|
|
|
|
// -------------------------------------------------------------------- climb
|
|
// A tower you spiral around rather than a line of pads: the thing you are
|
|
// climbing stays in view, so your progress is legible from the ground.
|
|
//
|
|
// Three rules make a course feel fair rather than fiddly — every jump is
|
|
// survivable from a standstill, the whole route is visible from the bottom,
|
|
// and falling costs height rather than a life.
|
|
game.box({pos: vec3(-36, 8, 34), size: vec3(6, 16, 6), color: #857569, tag: "tower"})
|
|
|
|
// Nine ledges, easing outward as they rise so the last steps are the boldest.
|
|
game.box({pos: vec3(-30.1, 1.6, 36.5), size: vec3(4.2, 0.7, 4.2), color: #99855c, tag: "ledge"})
|
|
game.box({pos: vec3(-31.3, 3.35, 40.4), size: vec3(4.2, 0.7, 4.2), color: #99855c, tag: "ledge"})
|
|
game.box({pos: vec3(-35.6, 5.1, 42.3), size: vec3(4.2, 0.7, 4.2), color: #99855c, tag: "ledge"})
|
|
game.box({pos: vec3(-40.4, 6.85, 41.1), size: vec3(4.2, 0.7, 4.2), color: #99855c, tag: "ledge"})
|
|
game.box({pos: vec3(-43.6, 8.6, 37.2), size: vec3(4.2, 0.7, 4.2), color: #99855c, tag: "ledge"})
|
|
game.box({pos: vec3(-44.0, 10.35, 32.1), size: vec3(4.2, 0.7, 4.2), color: #99855c, tag: "ledge"})
|
|
game.box({pos: vec3(-41.4, 12.1, 27.6), size: vec3(4.2, 0.7, 4.2), color: #99855c, tag: "ledge"})
|
|
game.box({pos: vec3(-36.6, 13.85, 25.4), size: vec3(4.2, 0.7, 4.2), color: #99855c, tag: "ledge"})
|
|
game.box({pos: vec3(-31.4, 15.6, 26.5), size: vec3(4.2, 0.7, 4.2), color: #99855c, tag: "ledge"})
|
|
|
|
// Two gaps are bridged by moving platforms instead — the timing beats.
|
|
let plat_x = game.box({pos: vec3(-25, 6.5, 32), size: vec3(4.6, 0.7, 4.6), color: #5999cc, tag: "lift", body: "kinematic"})
|
|
let plat_y = game.box({pos: vec3(-39, 11, 45), size: vec3(4.6, 0.7, 4.6), color: #6bb385, tag: "lift", body: "kinematic"})
|
|
|
|
// The summit: wide, still, and obviously the end.
|
|
game.box({pos: vec3(-36, 16.8, 34), size: vec3(8, 1, 8), color: #d9b34d, tag: "goal"})
|
|
|
|
// A ramp at the base, so the climb starts from the ground rather than from a
|
|
// jump you have to already know is there.
|
|
game.box({pos: vec3(-28, 1, 25), size: vec3(6, 2, 10), color: #b89a6b, tag: "ramp", shape: "wedge"})
|
|
|
|
// The lifts. Different periods, so they are never the same crossing twice.
|
|
game.on_tick(|dt| {
|
|
let t = game.time()
|
|
game.set_vel(plat_x, vec3(cos(t * 0.55) * 4.2, 0, 0))
|
|
game.set_vel(plat_y, vec3(0, cos(t * 0.42) * 2.6, 0))
|
|
})
|
|
|
|
game.text("hint", "WASD move · mouse look · space jump", {anchor: "top_left"})
|