rusting_engine 2.2.0

Vulkan 3D game engine with GPU-accelerated physics for massive physics-heavy scenes
{
  "kind": "feature",
  "template": "puzzle",
  "request": "Add an undo to this box-pushing puzzle. A new input action `undo`, on a key of your choice, takes back the player's last move: the player returns to the cell they came from, a box that move pushed returns too, and the `boxes` counter follows. Undo before any move does nothing. One step of undo is enough. Keep the existing test passing.",
  "seed": [],
  "remove": [],
  "reference": [
    {
      "file": "src/main.rs",
      "find": "pub fn update(scene: &mut GameScene<'_>, _time: &FrameTime) {\n",
      "replace": "pub fn update(scene: &mut GameScene<'_>, _time: &FrameTime) {\n    if scene.pressed(\"undo\") {\n        undo(scene);\n        return;\n    }\n"
    },
    {
      "file": "src/main.rs",
      "find": "    let player = scene.object(\"Player\").position();\n    let (x, z) = cell(player);\n    let next = (x + dx, z + dz);\n    if on_cell(scene, \"wall\", next).is_some() {\n        return;\n    }\n    if let Some(pushed) = on_cell(scene, \"box\", next) {\n        let beyond = (next.0 + dx, next.1 + dz);\n        if on_cell(scene, \"wall\", beyond).is_some()\n            || on_cell(scene, \"box\", beyond).is_some()\n        {\n            return;\n        }\n        let y = scene.object(&pushed).position()[1];\n        scene.object(&pushed).set_position([\n            beyond.0 as f32,\n            y,\n            beyond.1 as f32,\n        ]);\n    }\n    scene.object(\"Player\").set_position([\n        next.0 as f32,\n        player[1],\n        next.1 as f32,\n    ]);\n    let goals: Vec<_> = scene\n        .in_class(\"goal\")\n        .into_iter()\n        .map(|goal| cell(scene.object(&goal).position()))\n        .collect();\n    let solved = scene\n        .in_class(\"box\")\n        .into_iter()\n        .filter(|name| goals.contains(&cell(scene.object(name).position())))\n        .count();\n    scene.set_counter(\"boxes\", solved as i32);\n}\n\n",
      "replace": "    let player = scene.object(\"Player\").position();\n    let (x, z) = cell(player);\n    let next = (x + dx, z + dz);\n    if on_cell(scene, \"wall\", next).is_some() {\n        return;\n    }\n    let mut pushed_box = 0;\n    if let Some(pushed) = on_cell(scene, \"box\", next) {\n        let beyond = (next.0 + dx, next.1 + dz);\n        if on_cell(scene, \"wall\", beyond).is_some()\n            || on_cell(scene, \"box\", beyond).is_some()\n        {\n            return;\n        }\n        let y = scene.object(&pushed).position()[1];\n        scene.object(&pushed).set_position([\n            beyond.0 as f32,\n            y,\n            beyond.1 as f32,\n        ]);\n        pushed_box = 1;\n    }\n    scene.object(\"Player\").set_position([\n        next.0 as f32,\n        player[1],\n        next.1 as f32,\n    ]);\n    scene.set_counter(\"last_dx\", dx);\n    scene.set_counter(\"last_dz\", dz);\n    scene.set_counter(\"last_push\", pushed_box);\n    count_boxes(scene);\n}\n\n/// Takes back the last move, once.\nfn undo(scene: &mut GameScene<'_>) {\n    let (dx, dz) = (scene.counter_or(\"last_dx\", 0), scene.counter_or(\"last_dz\", 0));\n    if (dx, dz) == (0, 0) {\n        return;\n    }\n    let player = scene.object(\"Player\").position();\n    let (x, z) = cell(player);\n    if scene.counter_or(\"last_push\", 0) == 1 {\n        if let Some(pushed) = on_cell(scene, \"box\", (x + dx, z + dz)) {\n            let y = scene.object(&pushed).position()[1];\n            scene.object(&pushed).set_position([x as f32, y, z as f32]);\n        }\n    }\n    scene.object(\"Player\").set_position([\n        (x - dx) as f32,\n        player[1],\n        (z - dz) as f32,\n    ]);\n    scene.set_counter(\"last_dx\", 0);\n    scene.set_counter(\"last_dz\", 0);\n    count_boxes(scene);\n}\n\nfn count_boxes(scene: &mut GameScene<'_>) {\n    let goals: Vec<_> = scene\n        .in_class(\"goal\")\n        .into_iter()\n        .map(|goal| cell(scene.object(&goal).position()))\n        .collect();\n    let solved = scene\n        .in_class(\"box\")\n        .into_iter()\n        .filter(|name| goals.contains(&cell(scene.object(name).position())))\n        .count();\n    scene.set_counter(\"boxes\", solved as i32);\n}\n\n"
    }
  ],
  "reference_patches": [
    "reference/scene.json"
  ],
  "hidden": [
    "../../../src/templates/puzzle_solve.json",
    "hidden/undo.json"
  ]
}