Simulating Dominos
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.
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.
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.
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.
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.
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.
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.)