Before you go, check out these stories!

0
Hackernoon logoDrawing on the screen — Introduction to Creative Coding Part 2 by@radarboy3000

Drawing on the screen — Introduction to Creative Coding Part 2

Author profile picture

@radarboy3000George Gally

Drawing and creating animation with Javascript

This part 2 of Creative Coding basics — my guide to the things I’ve learnt coding every day for a year.

Download the files you need to follow long here: https://github.com/GeorgeGally/creative_coding

So last article was a little boring. Just creating a canvas. So let’s make something cool...

Once we’ve created a canvas, we want to start drawing onto it. we do this, like in Processing, with the draw loop:

var ctx = createCanvas(“canvas1”);
function draw(){
// do some stuff
}

Like Processing, the draw function, where all the action happens. This is really just a fancy requestAnimationFrame call that’s looping all the time and looking for a draw function in the window. And honestly, you really don’t even need to know what’s going on here, except that this gets repeated at 60fps (and is adjustable by setting the global variable frameRate, eg: frameRate = 120; ).

As mentioned before, many of the things I use for my coding are based off the Processing way of doing things, and often are just slightly modified to work the way I prefer. The great thing about this, is as you progress and build your library, the syntax is easier and easier to remember and you get to go to more interesting places in your code quicker.

Ok, so let’s get to the fun. Here’s a basic html file that we can continually use as a template:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>mouseTest</title>
<link rel="stylesheet" href="css/reset.css" type="text/css" media="screen" />
<link rel="stylesheet" href="css/style.css" type="text/css" media="screen" />
<script language="javascript" src="js/canvas.js"></script>
<script language="javascript" src="js/creative_coding.js"></script>
</head>
<body>
<script type="text/javascript">
var ctx = createCanvas(“canvas1”);
function draw(){
console.log("mouseX:" + mouseX + "mouseY: " + mouseY);
}
</script>
</body>
</html>

Nothing fancy here, a standard HTML5 document setup. And like everything else I’ve shown you so far, you’ll never really need to write this code again. But let me quickly explain (and then get to the fun stuff)…

In your browser let’s view our developer tools console. From the dropdown menu in Chrome go: View->Developer->Javascript Console( or Cmd-Alt-J on a mac or Control-Alt-I on a PC), and up pops our Javascript console, something like this:

Press Cmd-Alt-i for developer tools, and you should seeing the log of your mouse position.

The console is your best friend in creative coding and will give you a clue to the line number where your errors are.

So in the above code the draw functions executes continually and we can see our mouse position.

The mouse position is defined by some more global variables: mouseX and mouseY, which comes from an event listener. But for now, no need to even worry about that.

Now let’s get drawing! Change our draw function to this …

function draw(){
  // syntax: fillStyle can be colour, 
// or hash: ctx.fillStyle = "#cc0000";
// or an rgb value: ctx.fillStyle = rgb(red, green, blue);
// red, green and blue values are between 0 and 255
  ctx.fillStyle = "red";
  // syntax: ctx.fillEllipse(x, y, circle_width, circle_height)
ctx.fillEllipse(mouseX, mouseY, 20, 20);
}

And you should be able to draw something like this:

Look mom, it’s art .Drawing with mouse position.

Awesome.

ctx.fillEllipse draws a circle of a certain size at a certain position on the screen — in this case at position mouseX and mouseY and with a size of 20. (Remember from part 1 — ctx is just a variable referring to our canvas).

ctx.fillStyle adds a colour. You can use any standard html format, like #ff0000 or “red”. Or the special function: rgb (red, green, blue);

RGB values go from 0–255. We can also use rgba to have an alpha (or transparent) value from 0 to 1 to the colour:

// syntax: ctx.fillStyle = rgba(red, green, blue, alpha);
// alpha is a value between 0 and 1
ctx.fillStyle = rgba(255, 0, 0, 0.1);
Using rgba(255,0,0, 0.1) we’d get something like this. But is it art?

Let’s draw a filled square instead:

ctx.fillStyle = “#00aeef”;
// syntax: ctx.fillRect(x, y, rect_width, rect_height)
ctx.fillRect(mouseX, mouseY, 20, 20);
Drawing squares, I’m using fill of ctx.fillStyle = “#00aeef”;

What if we wanted to draw only when we pressed the mouse down? Well, I’ve done the hard work for you here too... We have a global variable called mousePressed… and all you need to know about for now is testing the condition with an if statement, which looks like this:

if(something) {
// do something
}

So our draw function would be modified to look like so:

function draw(){
if (mousePressed) {
ctx.fillStyle = "#00aeef";
ctx.fillRect(mouseX, mouseY, 20, 20);
}
}
Woop woop. We can draw.

We can also draw circles and squares with only outlines with strokeRect() and strokeEllipse() the following syntax:

// setup stroke colour
ctx.strokeStyle = rgb(255, 0, 0);
// draw stroked rectangle
ctx.strokeRect(mouseX, mouseY, 20, 20);
// draw stroked circle
ctx.strokeEllipse(mouseX, mouseY, 20, 20);

We’d get something like this:

Stroked circles and rectangles

So you probably would’ve noticed something annoying — which is that a circle and rectangle draw out from their centre points differently. Two simple ways to solve this…

By subtracting half the rectangle’s width and height:

// setup stroke colour
ctx.strokeStyle = rgb(255, 255, 0);
// draw stroked rectangle starting from half it's width and height
ctx.strokeRect(mouseX-10, mouseY-10, 20, 20);

…or by using functions I made: centreFillRect() or centreStrokeRect() (remember I mentioned my rule of if I need to do something three times, I need to make a function, well this is such a case…)

// setup stroke colour
ctx.strokeStyle = rgb(255, 255, 0);
// draw stroked rectangle starting from half it's width and height
ctx.centreStrokeRect(mouseX, mouseY, 20, 20);
Ok, that’s better. Circles inside squares

We can also adjust the width of the line with for eg. ctx.lineWidth = 4;

Ok, so drawings all very well and good. But let’s get more fancy and get the machine to do the work…

So let’s make a ball. First we’ll need to add some variables to save the position of the ball. Let’s put our ball on the middle of the page (Remember, our canvas.js gives us access to the page’s width and height — either as width and height or w and h), so:

var ball_x = w/2;
var ball_y = h/2;

and let’s give our ball a random speed. We call a random() function so:

// syntax: random(min_value, max_value) 
var speed_x = random(-5, 5);
var speed_y = random(-5, 5);

We can also ask for a random integer (whole number) with randomInt() like so:

// syntax: randomInt(min_value, max_value)
var speed_x = randomInt(-5, 5);

To move our ball around we need to add it’s current position (ball_x and ball_y) to it’s speed (speed_x and speed_y), like so:

ball_x = ball_x + speed_x;
ball_y = ball_y + speed_y;

There’s a shortcut for this, when you add something to itself: +=

ball_x += speed_x;
ball_y += speed_y;

Likewise there’s a shortcut when subtracting something from itself (-=) and when multiplying (*=) and dividing by itself (/=).

Ok, so let’s put it all together:

var ctx = createCanvas("canvas1");
var ball_size = 20;
var ball_x = width/2;
var ball_x = height/2;
var speed_x = randomInt(-5, 5);
var speed_y = randomInt(-5, 5);
function draw(){
  ball_x += speed_x;
ball_y += speed_y;
  ctx.fillStyle = rgb(255,0,0);
ctx.fillEllipse(x, y, ball_size, ball_size);
} 

Awesome… but not…

Where’d the ball go?

Yup, the ball goes off the edge and disappears.

Let’s fix that with an if statement.

Often it’s easy if you just say the code aloud in plain English: “If the position ball over the side or bottom, let’s put the ball at the top or left of the page again… And if the ball is less than the top or left of the page (ie. is ball_x < 0 or ball_y < 0) let’s put it back at the right or bottom…”

In code we’d do it like this:

if (ball_x < 0) {
ball_x = w;
}
if (ball_y < 0) {
ball_y = h;
}
if (ball_x > w) {
ball_x = 0;
}
if (ball_y > h) {
ball_y = 0;
}
Look ma, robot stripes!

Awesome.

Now let’s rather make the ball bounce on the edges… we do this by just instead setting ball to travel from the other edge, we just reverse it’s speed… and we do this by just multiplying the speed by -1 (because, you know, maths).

// multiply speed by negative number to change direction
speed_x = speed_x * -1;

And we can also use the shorthand *=

if (ball_x < 0) {
// same as speed_x = speed_x *-1
speed_x *= -1;
}
if (ball_x > w) {
// same as speed_x = speed_x *-1
speed_x *= -1;
}
// then do same for ball_y...

But even that’s a bit repetitive… So let’s simplify by using “or” which in code is written like this: ||

So we can write:

// ball wall hittest
if (ball_x < 0 || ball_x > w) {
speed_x *= -1;
}
if (ball_y < 0 || ball_y > h) {
speed_y *= -1;
}
Boom! Robo art!

But we don’t want stripes, we want a ball. In Javascript you manually have to clear the screen on each loop, otherwise things just keep drawing on top of each other. This done by using the clearRect() function at the start of each loop…

// clears the whole screen
ctx.clearReact(0,0,w,h);

But because we’re pretty much always clearing the whole screen, I made shorthand a function:

// clear with a rgb
ctx.background(255,255,255);

You can also just pass one value, which will give you a grey value:

// same as going ctx.background(255,255,255);
ctx.background(255);

And now we have a bouncing ball…

We can also add an alpha value to the background to give a cool trail-like effect:

// same as ctx.background(255,255,255, 0.1);
ctx.background(255, 0.1);
Note that an alpha of 0.1 will always leave too much of a trail. There’s a technical reason for this, that makes kinda sense, but easiest just set alpha higher, like 0.2

One small thing we need to fix… because the ball x and y points are measured from the centre, you’ll notice that the ball actually goes a bit off the edge before it bounces… so we need to adjust for the half the ball size on each side.

Here’s the full code:

var ctx = createCanvas("canvas1");
var ball_size = 20;
var ball_x = width/2;
var ball_y = height/2;
var speed_x = randomInt(-5, 5);
var speed_y = randomInt(-5, 5);
function draw(){
  ctx.background(255, 0.2);
  ball_x = ball_x + speed_x;
ball_y = ball_y + speed_y;
  if (ball_x < ball_size/2 || ball_x > w - ball_size/2) {
speed_x *= -1;
}
if (ball_y < ball_size/2 || ball_y > h - ball_size/2) {
speed_y *= -1;
}
  ctx.fillStyle = rgb(255,0,0);
ctx.fillEllipse(ball_x, ball_y, ball_size, ball_size);
}

and boom we have our ball…

But again, this bit of code is a bit repetitive for me… So, yes, I made a function… called bounce()

// syntax: bounce(pos, min, max, size)
if (bounce(ball_x, 0, w, ball_size) {
speed_x *=-1;
}

I actually use an even more condensed version of that… which I’ll get to in a bit when we talk about vectors)…

Here’s the final code:

var ctx = createCanvas("canvas1");
var ball_size = 20;
var ball_x = width/2;
var ball_y = height/2;
var speed_x = randomInt(-5, 5);
var speed_y = randomInt(-5, 5);
function draw(){
  ctx.background(255, 0.2);
  ball_x = ball_x + speed_x;
ball_y = ball_y + speed_y;
  if (bounce(ball_x, 0, w, ball_size)) {
speed_x *=-1;
}
  if (bounce(ball_y, 0 ,h, ball_size)) {
speed_y *=-1;
}
  ctx.fillStyle = rgb(255,0,0);
ctx.fillEllipse(ball_x, ball_y, ball_size, ball_size);
}

And now we get a proper bouncing ball…

A simple bouncing ball, the humble start to a particle system…

So that’s it for part 2. Hope you enjoyed it. Have play around with changing the ball size and colour when it hits the wall, like the picture at the top, and see if you can solve the few issues it presents…

Here’s part 3…

(You can follow me and my #code365 progress here: https://www.instagram.com/radarboy3000/)

All the code and libraries for these tutorials can be found here: https://github.com/GeorgeGally/creative_coding (be sure to do a git pull for each new tutorial, because I’m updating these all the time).

Side note: A large portion of my library was nicked/adapted from Seb Lee Delisle.

Also please let me know how the pace is, if I’m going too slowly…

Tags

The Noonification banner

Subscribe to get your daily round-up of top tech stories!