Basic

Functions

Reusable blocks of instructions you can call again and again. Learn the anatomy of a function, params, arguments, return, and write helpers the game actually ships.

What you will see

undefined

About 4 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

A function is a named block of instructions I can call many times with different inputs. Without them, a game would repeat every jump, every score, every screen draw by hand. I want to stop pasting the same lines over and over and instead define one helper once, then call it, and reproduce the exact clamp and lerp helpers the finished game ships in math.js.

1

A function is a named block of instructions I can call many times. I write greet(name) once, then call it twice with two different names. The name inside the parentheses is a parameter, a placeholder. The value I pass in when I call it, "Ada", is an argument.

function greet(name) { console.log("Hello, " + name + "!"); } greet("Ada"); greet("Grace");

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

What it prints
Hello, Ada! Hello, Grace!
The parentheses hold the parameter name; the call passes the actual argument. Change the name inside greet() to anything you like, the parameter is just a label for whatever value you hand in.
2

return hands a value back to whoever called the function AND stops the function immediately. I write a function that returns the bigger of two numbers and store its result in a variable. Without the return, the caller would get nothing useful at all, undefined, the value you almost never want.

function bigger(a, b) { return a > b ? a : b; } let maxNum = bigger(15, 30) console.log(maxNum)

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

What it prints
30
return does two things: it produces the value 30 for the caller, and it stops the function right there. Anything written after a return never runs, so the caller gets exactly one value back.
3

Now the clamp the game actually ships, taken verbatim from app1/js/utils/math.js. It holds a value between a floor and a ceiling. I call it three ways and watch it return the input when in range, the floor when too low, and the ceiling when too high.

function clamp(v, lo, hi) { return v < lo ? lo : v > hi ? hi : v; } console.log(clamp(15, 0, 10)) console.log(clamp(-3, 0, 10)) console.log(clamp(20, 0, 10))

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

What it prints
15 0 10
The ternary reads out loud as a sentence: if v is below the floor return the floor; else if it is above the ceiling return the ceiling; otherwise return v. This exact function exists in the game's math.js.
4

The game's math.js has several single-job helpers: lerp smooths from a to b, rand picks a number in a range, randInt rounds down to a whole number. Each does one small job well and is reused everywhere. I run them and see smooth interpolation and a bounded random value.

function lerp(a, b, t) { return a + (b - a) * t; } function rand(lo, hi) { return lo + Math.random() * (hi - lo); } function randInt(lo, hi) { return Math.floor(rand(lo, hi + 1)); } console.log(Math.round(lerp(0, 100, 0.5) * 100) / 100) console.log(Math.round(rand(1, 6) * 100) / 100)

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

What it prints
50
lerp(0, 100, 0.5) is exactly halfway, so it rounds to 50. rand(1, 6) gives a number between 1 and 6 that changes every run, the level generator uses this to place obstacles. Only the first line has a fixed output.
5

If a function forgets to return, it hands back undefined, an empty result that shows up as a silent bug. I write a function with no return and print its result to watch undefined appear. A function without return is why the lesson warns every helper should have a clear input and a clear output.

function noReturn(x) { let y = x + 1; } console.log(noReturn(5))

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

What it prints
undefined
The body runs but never sends a value back, so the caller gets undefined, the value you almost never want. This is exactly why a function without return is a bug waiting to happen: the caller assumes it got a number and crashes computing with it.

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

Arguments flow into parameters, the body computes a value, and return hands it back to the caller.
1 Call the function with arguments
↓
2 Each argument binds to a parameter
↓
3 The body runs, using the parameter values
↓
4 return produces a value and stops execution
↓
5 The caller receives the value and continues
Why this works
Why functions reduce bugs

If the "compute jump velocity" step were written in five places, fixing a bug meant fixing it in five spots, and you'd surely miss one. A function is defined once and called many.

function canJumpHere(ground) {
  return ground != null && Math.abs(ground - player.y) < 20;
}
// ...called from jump(), from landing(), from the collision pass...

When the jump feels slightly off, you fix it in one place and every caller benefits. This is the single biggest reason games stay maintainable as they grow to dozens of files.

The game's math.js file is exactly this philosophy: a handful of tiny, single-purpose, fully-reused functions.
Parameters as inputs, return as output

Think of a function as a small machine: parameters go in one end, the returned value comes out the other.

// The game maps a travelled distance to a scroll speed.
const speed = speedAt(distance);   // distance in -> speed out

The cleanest functions have a clear input and a clear output and do one thing. They're easy to test, easy to reuse, and easy to understand months later. Functions that do five things at once are hard to test and hard to trust.

A common pattern is the guard-clause function: return early when an input is invalid, so the rest of the body can assume it's valid.

function safeSqrt(x) {
  if (x < 0) return 0;   // guard: negative input
  return Math.sqrt(x);
}

The ground loop in Group 5 uses this exact pattern with continue inside a loop, early skip, then clean logic.

Examples

The anatomy of a function

A function is a named block of instructions you can call many times, each time with different inputs. Without them, a game repeats every step by hand.

function greet(name) {
  console.log("Hello, " + name + "!");
}

greet("Ada");      // Hello, Ada!
greet("Grace");    // Hello, Grace!

Four parts:

PartExampleRole
keywordfunctioncreates the function
namegreethow you'll call it later
params(name)inputs it can receive
block{ ... }the instructions it runs

Then call it by writing the name + parentheses with arguments: greet("Ada").

Params, arguments, and return

A parameter is the placeholder in the definition; an argument is the actual value you pass in when you call. return hands a value back and stops the function.

function clamp(v, lo, hi) {   // v, lo, hi are parameters
  return v < lo ? lo : v > hi ? hi : v;
}

console.log(clamp(15, 0, 10));  // 15
console.log(clamp(-3, 0, 10));  // 0

return does two things: it produces a value for the caller, and it stops the function immediately. Nothing after return runs, so the caller gets exactly one value back.

Watch out: a function without return gives back undefined: the value you almost never want.

Real game helpers in math.js

Every math helper the game uses is a small function like this. Here they are, verbatim from app1/js/utils/math.js:

export function clamp(v, lo, hi) { return v < lo ? lo : v > hi ? hi : v; }
export function lerp(a, b, t) { return a + (b - a) * t; }
export function rand(lo, hi) { return lo + Math.random() * (hi - lo); }
export function randInt(lo, hi) { return Math.floor(rand(lo, hi + 1)); }

Each one does a single job well:

  • lerp(a, b, t) moves from a to b by fraction t: used everywhere for smoothing and camera easing.
  • rand(lo, hi) picks a random number in a range, used by the level generator.
  • randInt rounds a random decimal down to a whole number.

Two functions, both reusable, both doing one job. That's the spirit of a well-built game.

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.

← Loops (Repetition)
Previous Lesson
Loops (Repetition)
Next Lesson
Arrays
Arrays →