Advanced

Difficulty as data, and the curve it produces

Difficulty belongs in a curve, not in scattered conditionals. A function of progress that returns the parameters makes the whole game's challenge describable in one graph, and that graph is what tells you whether the game is too hard.

What you will see

Identical. A different result means the curve reads something besides progress.

About 1 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

Write the curve and read it

1

Write the curve

printf 'function at(p) { return { speed: 120 + 260 * p, count: Math.round(2 + 8 * p), gap: Math.max(180 - 90 * p, 60) }; } ' | tee game/diff.js

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Three values from one progress number. No conditionals per feature.
2

Print ten points

node -e 'for (let i=0;i<=10;i++){ const p=i/10; console.log(p.toFixed(1), JSON.stringify(require("./game/diff.js").at(p))); }' 2>/dev/null || echo 'print at() for p = 0 .. 1'

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Ten lines. Read them as a curve and look for the spike.
3

Check the top is runnable

print the count at p = 1 and multiply by the cost per object

Before you run it, say out loud what it will print. Then open the answer.

What it prints
A number the frame budget can hold. If the count at p = 1 is huge, the curve needs a cap.
4

Check it depends only on progress

call at(0.5) twice and compare the results

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Identical. A different result means the curve reads something besides progress.
Do not hide difficulty in if-statements about the score. The curve is the only version of difficulty you can show someone.

Data Flow

Progress to parameters
1 Read the progress from zero to one
↓
2 Evaluate the curve
↓
3 Clamp to the maximum the game can run
↓
4 Return the parameter object
Why this works
How to read the graph

The steep parts are where the game stops being learnable. Flatten a steep part before adding a new mechanic, or the new mechanic is untestable.

Where the curve is wrong

If it depends on anything but progress, the same point in the game is harder on some runs. That is a bug unless it is a named choice.

Examples

One function, many outputs

Given the progress from zero to one, return speed, count, and spacing. Every rule reads that object and nothing decides difficulty itself.

Plot the curve

Print the value at ten points. A curve that spikes at the seventh point is a wall the player cannot pass, and the print shows it.

Cap the top of the curve

The curve must stop rising at a value the game can still run. An uncapped curve eventually asks for a thousand objects and the frame time is the limit.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Finding collisions without testing every pair
Previous Lesson
Finding collisions without testing every pair
Next Lesson
Recording and replaying a run
Recording and replaying a run →