Introduction to Objects¶
JavaScript supports object-oriented programming (OOP)
OOP is a way to combine multiple variables (and functions) into a single value
this greatly simplifies many programs, and is a standard technique for creating large programs
we’ll only introduce a few basic features of objects here; there is much more to learn!
as a concrete example, lets re-write this program using objects:
'use strict';
let x, y; // position of the ball
let dx, dy; // velocity of the ball
function setup() {
createCanvas(500, 500).parent('p5canvas');
// set the initial value of the ball's position and velocity
x = 250;
y = 250;
dx = -1.5; // try setting these
dy = 1.1; // randomly
}
function draw() {
background(220);
fill(255, 0, 0);
noStroke();
ellipse(x, y, 100, 100);
// update the position of the ball
x += dx;
y += dy;
}
to start, we’ll now think of the bouncing ball as a single object that consists of multiple variables
the ball variables are things like this:
- the (x, y) position of the ball
- the velocity of the ball, i.e. dx and dy
- the diameter of the ball
- the fill-color of the ball
- ... any other property you want your ball to have ...
here’s a version of the bouncing-ball program that uses an object named
ball1
:
'use strict';
let ball1; // global variable
function setup() {
createCanvas(500, 500).parent('p5canvas');
ball1 = {
x: 250,
y: 250,
dx: 3,
dy: 1,
diam: 50,
fillColor: color(255, 0, 0)
}
}
function draw() {
background(200);
fill(ball1.fillColor);
noStroke();
ellipse(ball1.x, ball1.y, ball1.diam, ball1.diam);
ball1.x += ball1.dx;
ball1.y += ball1.dy;
// off right?
if (ball1.x >= 500) {
ball1.dx = -ball1.dx;
}
// off bottom?
if (ball1.y >= 500) {
ball1.dy = -ball1.dy;
}
// off left?
if (ball1.x < 0) {
ball1.dx = -ball1.dx;
}
// off top?
if (ball1.y < 0) {
ball1.dy = -ball1.dy;
}
}
some things to note:
ball1
is declared as a global variable outside of any functions so that it can be accessed inside both thesetup()
anddraw()
functionsball1
is initialized inside ofsetup()
as follows:ball1 = { x: 250, y: 250, dx: 3, dy: 1, diam: 50, fillColor: color(255, 0, 0) }
the code in the
{
and}
is an example of an object literalthis object consists of property:value pairs
for example,
x
is one property ofball1
, and it’s value is 250we can access property values of an object using dot-notation, e.g.
ball1.x
is refers to thex
property ofball1
we can use
ball1.x
just like a regular variable, as you can see in the rest if the codeJavaScript’s notation for objects has become an extremely popular format for sending data across the Internet, and it is referred to as JSON, which stands for JavaScript object notation
practically all programming languages now have libraries of code for reading and writing JSON
and so even if you don’t use JavaScript, you might run into JSON in other situations
for instance, Minecraft uses JSON for some commands, e.g.:
/tellraw @a {"text":"Hello","color":"red","italic":true}
More than One Ball¶
the program above is a little longer and a little more complicated than the original non-object-oriented version
and so if this is all you want to do, there’s not much value in uses objects
but where really start to shine is when your program gets bigger and more complicated
so now lets make 3 balls bounce around the screen
to do this, we’re first going to make a simple change to the one-ball program
by moving most of the the code in draw()
into its own function:
'use strict';
let ball1;
function setup() {
createCanvas(500, 500).parent('p5canvas');
ball1 = {
x: 250,
y: 250,
dx: 3,
dy: 1,
diam: 50,
fillColor: color(255, 0, 0)
}
}
function draw() {
background(200);
handleBall1();
}
function handleBall1() {
fill(ball1.fillColor);
noStroke();
ellipse(ball1.x, ball1.y, ball1.diam, ball1.diam);
ball1.x += ball1.dx;
ball1.y += ball1.dy;
// off right?
if (ball1.x >= 500) {
ball1.dx = -ball1.dx;
}
// off bottom?
if (ball1.y >= 500) {
ball1.dy = -ball1.dy;
}
// off left?
if (ball1.x < 0) {
ball1.dx = -ball1.dx;
}
// off top?
if (ball1.y < 0) {
ball1.dy = -ball1.dy;
}
}
now you can see how we could add another ball: we create a new object called
ball2
, and corresponding function called handleBall2
that draws and
moves it:
'use strict';
let ball1;
let ball2;
function setup() {
createCanvas(500, 500).parent('p5canvas');
ball1 = {
x: 250,
y: 250,
dx: 3,
dy: 1,
diam: 50,
fillColor: color(255, 0, 0)
}
ball2 = {
x: 150,
y: 250,
dx: -1,
dy: 2,
diam: 50,
fillColor: color(0, 255, 0)
}
}
function draw() {
background(200);
handleBall1();
handleBall2();
}
function handleBall1() {
fill(ball1.fillColor);
noStroke();
ellipse(ball1.x, ball1.y, ball1.diam, ball1.diam);
ball1.x += ball1.dx;
ball1.y += ball1.dy;
// off right?
if (ball1.x >= 500) {
ball1.dx = -ball1.dx;
}
// off bottom?
if (ball1.y >= 500) {
ball1.dy = -ball1.dy;
}
// off left?
if (ball1.x < 0) {
ball1.dx = -ball1.dx;
}
// off top?
if (ball1.y < 0) {
ball1.dy = -ball1.dy;
}
}
function handleBall2() {
fill(ball2.fillColor);
noStroke();
ellipse(ball2.x, ball2.y, ball2.diam, ball2.diam);
ball2.x += ball2.dx;
ball2.y += ball2.dy;
// off right?
if (ball2.x >= 500) {
ball2.dx = -ball2.dx;
}
// off bottom?
if (ball2.y >= 500) {
ball2.dy = -ball2.dy;
}
// off left?
if (ball2.x < 0) {
ball2.dx = -ball2.dx;
}
// off top?
if (ball2.y < 0) {
ball2.dy = -ball2.dy;
}
}
the handleBall2
function is simply a copy of handleBall1
, but with
every occurrence of ball1
replace by ball2
(which is easy to do in a
text editor)
adding a 3rd (or 4th or 5th) ball an be done in the same way
Simplifying the Code with Functions¶
there’s a lot of repeated code in the above program, and we shorten it quite a bit by using functions, e.g.:
let ball1;
let ball2;
let ball3;
// creates and returns a newly created random ball object
function makeRandomBall() {
return {
x: random(500),
y: random(500),
dx: random(-5, 5),
dy: random(-5, 5),
diam: random(10, 100),
fillColor: color(random(256), random(256), random(256))
}
}
function setup() {
createCanvas(500, 500).parent('p5canvas');
ball1 = makeRandomBall();
ball2 = makeRandomBall();
ball3 = makeRandomBall();
}
function draw() {
background(200);
handleBall(ball1);
handleBall(ball2);
handleBall(ball3);
}
function handleBall(ball) {
fill(ball.fillColor);
noStroke();
ellipse(ball.x, ball.y, ball.diam, ball.diam);
ball.x += ball.dx;
ball.y += ball.dy;
// off right?
if (ball.x >= 500) {
ball.dx = -ball.dx;
}
// off bottom?
if (ball.y >= 500) {
ball.dy = -ball.dy;
}
// off left?
if (ball.x < 0) {
ball.dx = -ball.dx;
}
// off top?
if (ball.y < 0) {
ball.dy = -ball.dy;
}
}
things to note:
the
makeRandomBall
function creates a brand new ball object (with random values), and returns that value to wherever it gets called in the programa function that creates an object is sometimes called a constructor
we have only one
handleBall(ball)
function now; it takes the ball we want to handle as its input parameterit is now very easy to add more balls
however, if we wanted to have, say, 100 different balls, we’d have a program consisting of more then 300 lines of code, including:
100
let
statements:let ball1; let ball2; let ball3; // ... let ball100;
100
makeRandomBall
statements:ball1 = makeRandomBall(); ball2 = makeRandomBall(); ball3 = makeRandomBall(); // ... ball100 = makeRandomBall();
100
handleBall
statements:handleBall(ball1); handleBall(ball2); handleBall(ball3); // ... handleBall(ball100);
this is clearly impractical!
to do better, we need to more programming concepts: loops and arrays