This is also posted on Code Koalas's site.
If you're anything like me a couple years ago, you probably have avoided doing animations in Canvas because it's crazy complicated and you're just a person who can make websites, not a real programmer who can make games and things. But here's the thing: you're wrong. Making animations and games in Canvas is very easy and fun, I'd argue it's easier than writing JavaScript for sites. If you can make a mobile menu, a carousel, or even just an alert()
you can make a small animation in Canvas. I've taught this to children and very drunk people who know nothing about coding at Code Koalas First Friday events we host.
First off, what are we building?
You will be building a ball bouncing around the screen, just like the old DVD screen saver. If you have no coding experience this will take about 30 minutes, if you have used JavaScript or other languages before you can probably tackle this in 15 minutes or less.
See the Pen Learning Canvas Teaching 2017 by Josh Fabean (@fabean) on CodePen.
Getting Started
I have created a starter pen with all boilerplate code required to get started. It has lots of comments explaining what everything is if you're not familiar with coding at all.
See the Pen Learning Canvas Teaching 2017 Starter by Josh Fabean (@fabean) on CodePen.
From here if you aren't familiar with programming or JavaScript you'll continue reading as normal and head to the Quick JavaScript Brush up section, but if you think you're good enough to just jump straight into the Time to Code section, go for it.
Quick JavaScript Brush up
As you probably noticed that starter Pen I gave you comes with a lot of code already. At the time of publishing this it's 49 lines of JavaScript and 1 line of HTML. Don't worry, it will all make sense soon enough - or not, but it's okay! You'll still be able to make a ball bounce over the screen even if you don't totally understand how it works.
HTML
(HyperText Markup Language) is the most basic building block of the Web. It describes and defines the content of a webpage.
HTML is in every website you go to everyday. It's what defines what is a big header, a navigation link, an image or a paragraph. It's the backbone of websites. Since it's a markup language and not a programming language it's pretty easy to wrap your head around the basic concepts of this and it's not super important for what we're working on here.
In the starter code you have you'll see you only have one HTML tag.
<canvas id="canvas"></canvas>
What you have there is a HTML tag of canvas
with an id
of canvas. The canvas
element was added in HTML5 in late 2014 and can be used to draw graphics, you can learn more about canvas on MDN
JavaScript
JavaScript is a cross-platform, object-oriented scripting language. It is a small and lightweight language. Inside a host environment (for example, a web browser), JavaScript can be connected to the objects of its environment to provide programmatic control over them.
Variables
Anytime you want to use the same bit of information multiple times through your program, you'll use a variable. In JavaScript variables are defined with let
, var
, or const
. In our code you'll see right at the top the following lines:
let c;
let ctx;
const fps = 60;
The first two lines we're declaring variables named c
and ctx
but we're not setting their value to anything. On the third line we are using const
to define fps
to 60 for 60 frames per second. We're using cost
instead of let
because this is a constant meaning - we're not ever going to change that value.
Functions
Just like variables are anytime you want to access the same bit of information multiple times, functions are anytime you want to run the same couple lines of code multiple times. Functions are sort of like paragraphs, they contain a lot of different words and sentences but generally do a single cohesive thing when put together.
In JavaScript you create functions with the following syntax
let functionName = (variablesPassedIn) => {
// code you want to run
}
You can see it's similar to how we define a variable starting with let
and the variable/function name. But then we add () =>
to make it a function and {}
wraps all the code that belongs to that function.
In our code we first define the following function:
// if you want to draw lots of circles you'll use this function
let drawCircle = (circle) => {
ctx.fillStyle = circle.color; // set the color
ctx.beginPath(); // telling canvas we're about to define a path.
ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2, true);
// x&y coordinates, the size, ..?, pi*2 for radius, true? defines we are drawing a cirlce. You can draw all sorts of curves with .arc
ctx.fill(); // fill defines it's colored in, instead of just an outline or something like that.
}
This function is important to know because it shows what Canvas actually needs to render circles onto the page. In the function drawCircle
we first pass in the object of circle
. The circle object will need to look like the following:
let myCoolCircle = {
color: '#FFF',
x: 100,
y: 100,
radius: 20,
};
The circle object has 4 properties we care about for drawing on that screen, color
, x
, y
, and radius
. We pass those into the drawCircle
function and then that function draws it. The first line of the function is ctx.fillStyle = circle.color
which tells the ctx
we created earlier in the code that we are setting the current fillStyle to be the color of the circle object, in this example thats #FFF
or white. The next line is ctx.beginPath()
which simply tells ctx
we will be drawing a path which you can learn more about .beginPath
on MDN like always. With beginPath
you can draw any type of path including a straight line or in our case a circle. The following line ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2, true);
tells canvas what we're doing with that path we just started, learn about .arc
on MDN. That line says where to start drawing with the circle.x
and circle.y
then defines how large of a circle we're drawing with the circle.radius
. The next parts are the start angle of 0
then the end angle of Math.PI*2
.
If Statements
The if statement executes a statement if a specified condition is true. If the condition is false, another statement can be executed.
If statements are one of the main building blocks of programming. This is what allows programs to respond to situations and "think". They're very simple: if something is true we do one thing, if it's not true we do another. The syntax for an if statement is as follows:
if (your condition goes here) {
// run code on true
}
else {
// run code on false
}
Inside the ()
is where we put our conditional statement. A very simple example would be (1 > 2)
which of course would be false and run the else
, or we can do (1 < 2)
which would be true and run the code in the if
. We can also have or
or and
statements in our conditions. A condition with an or
looks like (1 > 2 || 3 < 4)
that would return true since one of those statements are true even though one is false. A condition with an and
looks like (1 < 2 && 4 < 5)
that would also return true since both conditions are true.
Time to Code!
Draw the background
The first thing we need to do is draw our background. With canvas each frame you draw over what already existed so if we don't redraw that background every frame over time we'll have a line instead of a ball. We will create our background inside of our render function, it will look like the following:
let background = {
color: '#000',
x: 0,
y: 0,
width: c.width,
height: c.height
};
All rectangles have a color, x & y starting coordinates, width & height of the rectangle. A few things worth noting: on canvas x & y start on the top left of your element so 0,0 is the top left of the screen. That height & width we're pulling off of previous code used to set the canvas element to the full width & height of the screen.
Once you have that background defined we just now need to tell our program to draw it on the page by putting the following below it.
drawRect(background);
If everything was done correctly you should now have a black background on your screen (you can replace that color with any HEX value or most color names instead of black if you'd like, you can find a full list of colors available on MDN) and it should look like the following:
See the Pen Learning Canvas Teaching 2017: Background Done by Josh Fabean (@fabean) on CodePen.
Draw the circle
Drawing the circle is very similar to the background, but this time it's a circle instead of a rectangle so we change just a few things. Also since we will be wanting to move this circle we need it's values always available. This means we will need to define ball
up on the top of our file next to where c
& ctx
are defined. It should look like the following:
let ball = {
color: '#FFF',
x: 20,
y: 20,
radius: 10
}
That's very similar to the rectangle with a couple of difference. We use radius to describe circles instead of height & width, and in Canvas they draw circles from the center so we didn't want to start x
& y
at 0 or it'd be mostly off screen.
But that doesn't do anything yet, we now need to tell Canvas to render that object onto the page. To do that go down to the render
function right below where you put the drawRect(background)
and add the line drawCircle(ball)
. If done right you should get a white ball. If everything worked right you'll have the following:
See the Pen
Learning Canvas Teaching 2017: Circle Done by Josh Fabean (@fabean)
on CodePen.
Move the circle
Now that you have a circle, making it move is just a couple more lines of code. The first thing I do is update the ball
object on the top of the file to define the speed at which we will move it both on the x & y values. To do that your object will now look like this:
let ball = {
color: '#FFF',
x: 20,
y: 20,
radius: 10,
speedX: 10,
speedY: 4
}
You'll notice we just added two lines. Those two lines are speedX
& speedY
the letters Y & X being capitalized is called camel case and is how people write things in JavaScript to be readable. You can set your values to something else if you'd like, but we are defining how many pixels the ball will move per frame so if you go much higher than 10 it will fly across the screen really fast.
Now that you have defined how it should move, we need to actually make it move. The logic for this will go in our render function. What we'll tell it to do is every frame take what the X & Y values are, and add the speed to them. It will look like the following:
ball.x = ball.x + ball.speedX;
ball.y = ball.y + ball.speedY;
drawCircle(ball);
Now your ball should start moving and eventually fly off the screen like the following: (Very likely it's been off the screen for a long time in this example)
See the Pen
Learning Canvas Teaching 2017: Circle Moves by Josh Fabean (@fabean)
on CodePen.
Make the circle bounce
Fix flying off right side of screen
Great! The ball moves, but now it disappears because we aren't yet stopping it from flying off of the screen. We will handle this by adding checks before we move the ball to see if it's at a wall, if it is we will reverse the direction it's going. In my example it flies of off the right side of the screen first. To fix that it will look like the following:
if (ball.x > c.width) {
ball.speedX = - ball.speedX;
}
That will if ball.x
is greater than c.width
the canvas's width take the ball.speedX
value of 10
and make it -10
which reverses it to the left. In action it looks like this:
See the Pen
Learning Canvas Teaching 2017: Bounce Right Side by Josh Fabean (@fabean)
on CodePen.
Fix flying off bottom of screen
Now it falls off of the bottom of the screen, so how do we fix that? (It might not fall off the bottom based on your values and screen size and dimensions but for me it's the bottom next). We can do almost the same thing as before but this time on the y
value of our ball.
if (ball.y > c.height) {
ball.speedY = - ball.speedY;
}
Now when it hits the bottom it bounces back up like this:
See the Pen
Learning Canvas Teaching 2017: Bounce Bottom by Josh Fabean (@fabean)
on CodePen.
Finally get it bouncing off all sides of the screen
Now we run into the issue where the same thing happens but for the left & top. We can just modify our already existing if statements to allow them to also check the left & top sides like this:
if (ball.x > c.width || ball.x < 0) {
ball.speedX = - ball.speedX;
}
if (ball.y > c.height || ball.y < 0) {
ball.speedY = - ball.speedY;
}
The ||
means OR so now our statement says, if ball.x
is greater than c.width
OR ball.x
is less than 0
reverse the direction of ball.speedX
and the same thing for the y
value. When all put together you have a fully bouncing ball!
See the Pen
Learning Canvas Teaching 2017: Bounce All Sides by Josh Fabean (@fabean)
on CodePen.
Bonus
There are a lot of cool things you can do from here:
- Change color on bounce
- Add extra balls when clicked
- Have ball change size on bounce
- Add extra balls on bounce (dangerous as this gets out of hand quick and can crash your browser)
I recently gave this talk at Drupal Camp and you can watch the video for step by steps for all of this and some of the fun bonuses.