Simulating Dominos

Level: Beginner (7+) Duration: 1 Hour Download Teacher's Guide

In this lesson we will simulate falling dominos using JavaScript. Along the way we will learn about variables, functions, loops, mouse events and knocking things over!

This lesson uses the Kid.js JavaScript framework. To get started with Kid.js, create an account on kidjs.app or import the framework into your own project.

Part 1: Create a Domino 10 Minutes

Functions

We program a computer by giving it a series of commands, also known as functions. To run a command or function in JavaScript, type the name of the function followed by parentheses.

Many functions need parameters. For example, if you were to command someone to walk, you may also need to tell them how many steps or which direction. The parameters go inside of the parentheses.

We'll use the rect() function to create a domino.

rect(200, 200, 20, 100)

The parameters are (in order) the x coordinate, y coordinate, width and height. Try different values and see the result.

Variables

Variables are used to keep track of things. Think of a variable as a box with a label you can put things in. There are many things we may need to keep track of in an app, such as high score or health. Take a moment to brainstorm other items you may need to keep track of.

Variables are also useful for assigning names to things. Let's give the domino a name. This will allow us to reference it later.

let domino = rect(200, 200, 20, 100)

Properties

Properties describe something. You have properties, such as your age and height. Objects in JavaScript can have properties too.

Our domino is stuck floating in mid-air. For physics to apply, we'll set its "anchored" property to false.

let domino = rect(200, 200, 20, 100) domino.anchored = false

Of course, our domino shouldn't be quite so bouncy. In fact, it shouldn't be bouncy at all. Set its "bounciness" property to 0.

let domino = rect(200, 200, 20, 100) domino.anchored = false domino.bounciness = 0

Part 2: Line 'em Up 25 Minutes

Instead of repeating this code for each domino, we'll create our own custom function. Functions are useful for organzing code into reusable blocks. Ideally functions should perform a single action, and its name should describe that action.

function placeDomino() { let domino = rect(200, 200, 20, 100) domino.anchored = false domino.bounciness = 0 }

Where did our domino go? While we created a function to place a domino, we did not run (or execute) it. To do this, type the function name followed by parentheses.

function placeDomino() { let domino = rect(200, 200, 20, 100) domino.anchored = false domino.bounciness = 0 } placeDomino()

Next, modify the function to accept x and y parameters. This will allow us to not just place a domino, but specify where we want to place it.

function placeDomino(x, y) { let domino = rect(x, y, 20, 100) domino.anchored = false domino.bounciness = 0 }

We can now run the function multiple times passing different x and y values to place more dominos.

function placeDomino(x, y) { let domino = rect(x, y, 20, 100) domino.anchored = false domino.bounciness = 0 } placeDomino(200, 200) placeDomino(260, 200) placeDomino(320, 200)

It's going to take a lot of lines of code to fill the screen with dominos. Luckily there is a better way. We'll use a piece of code called a for loop.

The For Loop

A for loop is used to repeat a block of code. It's broken into three parts. Code that runs before the loop starts; a condition to check if we should continue; and code that runs after each pass through the loop.

In the first part, we'll create a new variable x to keep track of the horizontal position of the domino. Let's start it at 200.

For the second part, we check to see if x is less than the width of the screen (minus 200 pixels.) If yes, then the loop continues.

For the third part, we add 60 pixels to x. This moves the position of the next domino to the right.

function placeDomino(x, y) { let domino = rect(x, y, 20, 100) domino.anchored = false domino.bounciness = 0 } for (let x = 200; x < width - 200; x = x + 60) { placeDomino(x, 200) }

Part 3A: Knock 'em Down 25 Minutes

Now for the fun part! To knock the dominos down, we'll place a marble where the user clicks and launch it towards the dominos.

Events

Events are "things" that happen while our app is running, like a mouse click, or key press. We can write code that runs when that event occurs.

The first step is to write a function that is intended to run when the event occurs. These types of functions are referred to as Event Handlers.

Our function will create a new marble and give it a push. We'll use the circle() function to create a marble, and push() to set it in motion. The parameters for the circle function are the x and y position and diameter. The parameters for push are the amount of horiztonal and vertical force to apply. Kid.js provides two global variables, mouseX and mouseY that contain the current mouse coordinates.

function launchMarble() { let marble = circle(mouseX, mouseY, 50) marble.push(20, 0) }

Then connect the function to the "click" event.

on('click', launchMarble)

And voilĂ , our domino simulation is complete.

function placeDomino(x, y) { let domino = rect(x, y, 20, 100) domino.anchored = false domino.bounciness = 0 } for (let x = 200; x < width - 200; x = x + 60) { placeDomino(x, 200) } function launchMarble() { let marble = circle(mouseX, mouseY, 50) marble.push(20, 0) } on('click', launchMarble)

Part 3B: Sling Shot 25 Minutes (Optional)

Let's take it further. Instead of placing the marble on click, let's allow the user to click and drag to aim and "sling-shot" the marble towards the dominos. It will go something like this:

  • On mouse down, save the mouse position in a varible and create the marble.
  • On mouse move (while pressed) move the marble to the current mouse position.
  • On mouse up, launch the marble towards where we first clicked.

Scope

Before we go much further, we need to talk about variable scope. Variables only live inside of the block of code they are defined in. If we define a variable inside of a function, it only exists inside that function. It cannot be accessed by code outside of the function.

We're going to need three variables to launch our marble. Two variables to store the x and y location where we started dragging and another variable for the marble itself. Several functions will need to use these variables, so we define them outside of any function.

let startX let startY let marble

Start

When the user presses down on the mouse button, we save the current mouse position in startX and startY and add a circle to the stage which will be the marble.

We'll write this code in a function and attach it to the "mousedown" event.

function start() { startX = mouseX startY = mouseY marble = circle(startX, startY, 50) } on('mousedown', start)

Drag

When the user moves the mouse, we'll update the position of the marble. We only do this while the mouse button is pressed, otherwise the marble will follow the mouse event after it is launched.

We'll write this code in a function and attach it to the "mousemove" event. We can check if the mouse button is pressed by looking at the global mouseButton variable.

function dragging() { if (mouseButton) { marble.x = mouseX marble.y = mouseY } } on('mousemove', dragging)

And Release!

Finally, when the mouse button is released, we launch our marble. We'll do a little geometry to figure out the direction we want to push the marble by subtracting the starting coordinates from the current mouse coordinates.

function release() { marble.push(startX - mouseX, startY - mouseY) } on('mouseup', release)

Putting It All Together

Let's put it all together. We have placeDomino() and a for loop to line up all the dominos, and can click and drag to launch a marble to knock them down.

function placeDomino(x, y) { let domino = rect(x, y, 20, 100) domino.anchored = false domino.bounciness = 0 } for (let x = 200; x < width - 200; x = x + 60) { placeDomino(x, 200) } let startX let startY let marble function start() { startX = mouseX startY = mouseY marble = circle(startX, startY, 50) } function dragging() { if (mouseButton) { marble.x = mouseX marble.y = mouseY } } function release() { marble.push(startX - mouseX, startY - mouseY) } on('mousedown', start) on('mousemove', dragging) on('mouseup', release)

Part 4: Taking it Further

  • Add rectangles and other shapes to act as platforms or barriers. Line up even more dominos!
  • Use the mouse click event to place dominos. Use a modifier key, such as shift, to change to launch mode.
  • Play around with the various physics properties (gravity, bounciness, etc.)