Skip to content

Commit 23f3899

Browse files
authored
Fix gameplay tests (#1041)
1 parent 392eaa6 commit 23f3899

4 files changed

Lines changed: 109 additions & 35 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@
66
# Artefacts written next to a game by the gameplay test runner.
77
gameplay-test-results.json
88
gameplay-test-screenshots/
9+
/gameplay-tests-artifacts
10+
/gameplay-tests-results

__tests__/post-build/__snapshots__/exampleShortHeaders.json.spec.js.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ Object {
209209
"Mathematical tools",
210210
"Objects",
211211
"Scene",
212+
"Timers and time",
212213
"Variables",
213214
"Debugger Tools",
214215
"Objects with effects",

examples/starting-platformer-pixel/starting-platformer-pixel.json

Lines changed: 88 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,12 +1259,13 @@
12591259
]
12601260
},
12611261
{
1262-
"description": "The player runs to the ledge holding the coins, jumps onto it, and collects every coin it touches.",
1262+
"description": "The player drops off its starting platform onto the row of coins on the ground, then runs right and jumps onto the ledge to collect the rest.",
12631263
"name": "Collecting the coins by running into them",
12641264
"type": "gameplay",
12651265
"source": [
1266-
"// Coins are picked up by touching them. They sit on a ledge above the ground",
1267-
"// the player starts on: it has to run there and jump onto it.",
1266+
"// Coins are picked up by touching them. They come in two rows: one on the",
1267+
"// ground below the platform the player starts on, and one on a ledge above",
1268+
"// the ground, further right.",
12681269
"await harness.goToScene('Game Scene');",
12691270
"harness.watch('Coins');",
12701271
"",
@@ -1290,34 +1291,102 @@
12901291
" 'Standing still collects no coin.'",
12911292
");",
12921293
"",
1293-
"// Run right, jumping while the coins ahead are out of reach above.",
1294+
"// The two rows are told apart by their height: the ground row is well below",
1295+
"// the player's starting platform, the ledge row only a little (the ledge is",
1296+
"// lower than the platform).",
1297+
"const groundCoinIds = harness",
1298+
" .getObjects('Coins')",
1299+
" .filter((coin) => coin.centerY > startY + 60)",
1300+
" .map((coin) => coin.id);",
1301+
"const groundRowIsCollected = () => {",
1302+
" const remaining = coinIds();",
1303+
" return groundCoinIds.every((id) => !remaining.includes(id));",
1304+
"};",
1305+
"harness.assert(",
1306+
" groundCoinIds.length > 0,",
1307+
" 'There is a row of coins on the ground below the starting platform.'",
1308+
");",
1309+
"",
1310+
"// The player cannot reach the ground row from up there: it first drops off",
1311+
"// the right edge of the platform and runs back left over the coins.",
1312+
"harness.setKeyPressed('Right', true);",
1313+
"const fell = await harness.stepUntil(() => !isOnFloor(), { maxFrames: 120 });",
1314+
"harness.assert(fell, 'Running right takes the player off the edge of the platform.');",
1315+
"const landedBelow = await harness.stepUntil(isOnFloor, { maxFrames: 120 });",
1316+
"harness.releaseAllInputs();",
1317+
"await harness.stepFrames(5);",
1318+
"harness.assert(landedBelow, 'The player lands on the ground below.');",
1319+
"",
1320+
"// Run back left, over the row of coins on the ground. Leaving the floor",
1321+
"// would mean the player missed them and ran off the level, so stop there.",
1322+
"harness.setKeyPressed('Left', true);",
1323+
"await harness.stepUntil(() => groundRowIsCollected() || !isOnFloor(), {",
1324+
" maxFrames: 240,",
1325+
"});",
1326+
"// Brake with the opposite key: the level ends right after the last coin of",
1327+
"// the row, and just letting go would let the player slide off it.",
1328+
"harness.setKeyPressed('Left', false);",
1329+
"harness.setKeyPressed('Right', true);",
1330+
"await harness.stepFrames(10);",
1331+
"harness.releaseAllInputs();",
1332+
"",
1333+
"const playerAfterGroundRow = getPlayer();",
1334+
"console.log(",
1335+
" 'afterGroundRow playerX=' + Math.round(playerAfterGroundRow.centerX) +",
1336+
" ' playerY=' + Math.round(playerAfterGroundRow.centerY) +",
1337+
" ' coinsLeft=' + coinIds().length",
1338+
");",
1339+
"harness.assert(",
1340+
" groundRowIsCollected(),",
1341+
" 'Running over the row of coins on the ground collects every one of them (' +",
1342+
" coinIds().filter((id) => groundCoinIds.includes(id)).length +",
1343+
" ' were left behind, the player ended at x=' +",
1344+
" Math.round(playerAfterGroundRow.centerX) + ').'",
1345+
");",
1346+
"",
1347+
"// Run right toward the remaining coins. They sit on a ledge overhanging the",
1348+
"// end of the ground, so the player jumps while running well before reaching",
1349+
"// it, rises above it, and stops moving forward once past the start of the",
1350+
"// row of coins: it comes down onto the first coin of the row instead of",
1351+
"// flying over the whole ledge. Falling well below the ground would mean the",
1352+
"// player ran out of the level, so stop there.",
1353+
"const rowStartX = Math.min(",
1354+
" ...harness.getObjects('Coins').map((coin) => coin.centerX)",
1355+
");",
12941356
"let jumpFramesLeft = 0;",
1357+
"let hasJumped = false;",
12951358
"harness.setKeyPressed('Right', true);",
12961359
"const collectedThemAll = await harness.stepUntil(",
1297-
" () => coinIds().length === 0,",
1360+
" () => coinIds().length === 0 || getPlayer().centerY > startY + 300,",
12981361
" {",
12991362
" maxFrames: 400,",
13001363
" onFrame: () => {",
13011364
" const player = getPlayer();",
13021365
" const onFloor =",
13031366
" player.behaviors.PlatformerObject.state.IsOnFloor === true;",
1304-
" const nextCoin = harness.getNearby('Coins', 'Player', 5000)[0];",
13051367
"",
13061368
" if (jumpFramesLeft > 0) {",
13071369
" jumpFramesLeft--;",
13081370
" if (jumpFramesLeft === 0) harness.setKeyPressed('Space', false);",
1309-
" return;",
13101371
" }",
1311-
" if (!onFloor || !nextCoin) return;",
1312-
" const isAhead = nextCoin.centerX > player.centerX;",
1313-
" const isAbove = player.centerY - nextCoin.centerY > 30;",
1314-
" if (isAhead && isAbove) {",
1315-
" harness.setKeyPressed('Space', true);",
1316-
" jumpFramesLeft = 14;",
1372+
" if (onFloor) {",
1373+
" harness.setKeyPressed('Right', true);",
1374+
" if (!hasJumped && rowStartX - player.centerX <= 100) {",
1375+
" harness.setKeyPressed('Space', true);",
1376+
" jumpFramesLeft = 20;",
1377+
" hasJumped = true;",
1378+
" }",
1379+
" } else if (player.centerX >= rowStartX - 16) {",
1380+
" harness.setKeyPressed('Right', false);",
13171381
" }",
13181382
" },",
13191383
" }",
13201384
");",
1385+
"// Brake with the opposite key here too: the ledge ends right after the last",
1386+
"// coin of its row.",
1387+
"harness.setKeyPressed('Right', false);",
1388+
"harness.setKeyPressed('Left', true);",
1389+
"await harness.stepFrames(10);",
13211390
"harness.releaseAllInputs();",
13221391
"await harness.stepFrames(5);",
13231392
"",
@@ -1334,11 +1403,15 @@
13341403
" Math.round(player.centerY) + ', it started at y=' + Math.round(startY) + ').'",
13351404
");",
13361405
"harness.assert(",
1337-
" collectedThemAll,",
1406+
" collectedThemAll && coinIds().length === 0,",
13381407
" 'Running and jumping to the coins collects every one of them (' +",
13391408
" coinIds().length + ' were left behind, the player ended at x=' +",
13401409
" Math.round(player.centerX) + ').'",
1341-
");"
1410+
");",
1411+
"",
1412+
"// A picture of what the game looks like once this has happened, kept with",
1413+
"// the test results.",
1414+
"await harness.takeScreenshot('the level once every coin has been collected');"
13421415
]
13431416
}
13441417
],

examples/starting-point-and-click-adventure/starting-point-and-click-adventure.json

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,12 +1894,12 @@
18941894
]
18951895
},
18961896
{
1897-
"description": "Clicking an NPC next to the player opens the dialog, and saying yes makes that NPC leave.",
1897+
"description": "Clicking an NPC sends the player walking to it, reaching it opens the dialog, and saying yes makes the NPC leave.",
18981898
"name": "Talking to an NPC and saying yes",
18991899
"type": "gameplay",
19001900
"source": [
1901-
"// Talking to an NPC: clicking one picks it, walking into it opens the",
1902-
"// dialog, and saying yes makes it leave.",
1901+
"// Talking to an NPC: clicking one picks it and sends the player walking",
1902+
"// there, walking into it opens the dialog, and saying yes makes it leave.",
19031903
"await harness.goToScene('Game Scene');",
19041904
"harness.watch('NPC');",
19051905
"",
@@ -1926,30 +1926,28 @@
19261926
"const npcsBefore = harness.getObjects('NPC').length;",
19271927
"harness.assert(npcsBefore > 0, 'There are NPCs to talk to.');",
19281928
"",
1929-
"// Click on an NPC the player is standing next to: clicking is what picks the",
1930-
"// NPC to talk to, and being next to it is what opens the dialog. The player",
1931-
"// is wide enough to touch two of the NPCs from where it spawns, so one of",
1932-
"// those is used and the dialog depends on the click alone.",
1933-
"const player = getPlayer();",
1934-
"const isWithinReach = (npc) =>",
1935-
" Math.abs(npc.centerX - player.centerX) < (npc.width + player.width) / 2 &&",
1936-
" Math.abs(npc.centerY - player.centerY) < (npc.height + player.height) / 2;",
1937-
"const npc = harness",
1938-
" .getNearby('NPC', 'Player', 9000)",
1939-
" .find((one) => isWithinReach(one));",
1940-
"harness.assert(!!npc, 'There is an NPC within reach to talk to.');",
1929+
"// Click on the nearest NPC. The characters' origins sit at their feet, so the",
1930+
"// NPC's own position is both a point on it (clicking there picks it as the",
1931+
"// one to talk to) and a walkable spot on the floor (where the same click",
1932+
"// sends the player).",
1933+
"const npc = harness.getNearby('NPC', 'Player', 9000)[0];",
1934+
"harness.assert(!!npc, 'There is an NPC to walk to.');",
19411935
"console.log(",
1942-
" 'npc=' + npc.id + ' at ' + Math.round(npc.centerX) + ',' + Math.round(npc.centerY) +",
1936+
" 'npc=' + npc.id + ' feet at ' + Math.round(npc.x) + ',' + Math.round(npc.y) +",
19431937
" ' npcsBefore=' + npcsBefore",
19441938
");",
1945-
"await clickAt(npc.centerX, npc.centerY, npc.layer);",
1939+
"await clickAt(npc.x, npc.y, npc.layer);",
19461940
"",
1947-
"const opened = await harness.stepUntil(isDialogOpen, { maxFrames: 60 });",
1941+
"// The dialog only opens once the player has walked all the way to the NPC.",
1942+
"const opened = await harness.stepUntil(isDialogOpen, { maxFrames: 300 });",
19481943
"console.log(",
19491944
" 'dialogOpened=' + opened +",
1950-
" ' playerAt=' + Math.round(getPlayer().centerX) + ',' + Math.round(getPlayer().centerY)",
1945+
" ' playerAt=' + Math.round(getPlayer().x) + ',' + Math.round(getPlayer().y)",
1946+
");",
1947+
"harness.assert(",
1948+
" opened,",
1949+
" 'Clicking an NPC sends the player to it, and the dialog opens when it gets there.'",
19511950
");",
1952-
"harness.assert(opened, 'Clicking the NPC the player stands next to opens the dialog.');",
19531951
"harness.assert(",
19541952
" harness.getObjects('NPC').length === npcsBefore,",
19551953
" 'Opening the dialog does not make the NPC leave on its own.'",

0 commit comments

Comments
 (0)