Adding and removing items
.push(item)adds to the end..pop()removes from the end.
const obstacles = ["spike", "pit"];
obstacles.push("wall"); // -> ["spike", "pit", "wall"]
obstacles.pop(); // -> ["spike", "pit"]
You actually used .push() without knowing it, you built strings with + in Group 2, and arrays with .push() here. Both accumulate by repetition. The finished game relies on .push() to grow the level and .filter() (Group 9) to shrink it.
Watch out: .push/.pop act on the end, which is fast. Adding or removing from the front with .unshift/.splice is slower, prefer keeping the end as the "active" side.
The build-then-use pattern
Almost every game in this tutorial follows the same two-phase rhythm:
// Phase 1, build: push items into an array
const entities = [];
entities.push(...);
entities.push(...);
// Phase 2, use: loop over the array
for (const item of entities) {
// draw it, collide with it, update it
}
The level factory builds a list of ground, spikes, walls, and coins. The render loop draws them. The collision loop checks them. The same array, read many different ways. Mastering this one pattern, build once, use many, is most of the way to thinking like a game programmer.