karismatic-megafauna / p5_scaffold

Basic p5 setup for workshop

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Lets make some stuff!

Get a text editor

Use Atom or VSCode, they are both great editors! Vim is cool too, but has a really steep learning curve.

How the code is wired together

Open the ./index.html file and see what is going on!

  • line 4 adds p5.js library
  • line 5 adds your sketch.js

Where the magic happens

Open ./sketch.js, this is where we do our coding!

It has two main functions, setup() and draw():

  • setup runs once when the page first loads
  • draw runs on a loop and happens many times

Let's Write some Code

In that setup function, add this line: line(15, 25, 60, 60);

It should look like this:

function setup() {
  line(15, 25, 60, 60);
}

Now, open the index.html file in chrome:

  • open file explorer
  • find project
  • find file, click it, open it in chrome

How did that work?

Here is the Application Programming Interface (API) for line: https://p5js.org/reference/#/p5/line

line(x1, y1, x2, y2) Draw a line from (x1,y1) to (x2, y2)

Now make a box!

Hard way, using line

You could do a line from:

  • top left to top right
  • top right to bottom right
  • bottom right to bottom left
  • bottom left to top left

But that is really not fun... There must be a better way

Let's consult the documentation!

https://p5js.org/reference/

Square -> Rectangle -> Rect

Easy way, using rect

We found the right function in the p5 API, rect(). Let's use it: rect(60, 60, 80, 80)

function setup() {
  line(15, 25, 60, 60);
  rect(60, 60, 80, 80);
}

Uh oh... why do i just have a stick figures legs?

You all might be like this right now:

That's not a rect! You lied to us Michael, you LIED!

I swear, I didn't lie, there is a rect there, we just can't see it! The problem is our canvas is too small! Lets make it bigger:

createCanvas(800, 800);

function setup() {
  createCanvas(800, 800);
  line(15, 25, 60, 60);
  rect(60, 60, 80, 80);
}

And so we don't run into this problem again, let's make our background a different color

background(50, 100, 50);

function setup() {
  createCanvas(800, 800);
  background(50, 100, 50);
  line(15, 25, 60, 60);
  rect(60, 60, 80, 80);
}

Ok, how bout a circle?

Back to the documentation!

Can't find circle :( what is another name for a circle?

An ellipse! https://p5js.org/reference/#/p5/ellipse

ellipse(60, 60, 80, 80);

function setup() {
  createCanvas(800, 800);
  background(50, 100, 50);
  line(15, 25, 60, 60);
  rect(60, 60, 80, 80);
  ellipse(60, 60, 80, 80);
}

It's curious that we gave the same coordinates to both rect and ellipse but they rendered in different spots...or did they?

Remove the fill

To see more clearly what is going on, let's remove that fill:

https://p5js.org/reference/#/p5/noFill

noFill();

function setup() {
  nofill();
  createCanvas(800, 800);
  background(50, 100, 50);
  line(15, 25, 60, 60);
  rect(60, 60, 80, 80);
  ellipse(60, 60, 80, 80);
}

Ah! The center of the circle is the top left corner of the square...

This is a good thing to know, different object have different origins!

Let's Make an Interactive Thing!

Ok this is cool and all but, honestly, I can do this in ms paint... why is art in JS better?

The Draw Function

This is hooked up to something called the animation frame, which is responsible for keeping your app running at 60 frames per second.

Lets get a circle to go through the middle of the screen!

Drawing a circle

In our draw function, let's add a circle:

  • with a radius of 20
  • vertically centered
  • all the way to the left

ellipse(0, height/2, 20);

function draw() {
  ellipse(0, height/2, 20);
}

That's great!

But where did that height come from? Magic?

No! The API! https://p5js.org/reference/#/p5/height

height is part of the environment provided to us by p5.

That's great but the bigger question here is this:

  • How do we get that to move to the right?
  • What do we need to change?

Moving the circle to the right

This is a big step for us, so pay close attention!

Using a global variable, introducing "State"

At the top of our file, let's add a variable:

var x = 0;

We will use this to keep track of our position, what "state" it is in.

Now let's use that in our draw function:

function draw() {
  ellipse(x, height/2, 20);
}

...Fantastic?

Why didn't that work?

Incrementing 'x'

We never made x bigger, we should do that, but how!!?!?!

function draw() {
  ellipse(x, height/2, 20);
  console.log(x);
}

The draw function is being called by p5, we should use this to make our x increase!

function draw() {
  ellipse(x, height/2, 20);
  x = x + 5;
  console.log(x);
}

HOLY. CATS.

That worked...THAT WORKED!!!!!

But it is working too well...let's make it wrap!

Making our circle wrap

When the circle hits the end of the screen, let's make it go down a line and move from the left to right again.

Let's decode this request to something that is easier to understand...

When our x variable is larger than the width of our canvas, increase the y position of the ellipse and reset our x to 0;

This tells us two things:

  1. We need more state to describe our system, y being that state
  2. We need to have some sort of conditional logic

Adding y

At the top of our file, let's add y

var x = 0;
var y = 0;

And let's make our ellipse use it:

function draw() {
  ellipse(x, y, 20);
  x = x + 5;
  console.log(x);
  console.log(y);
}

And lets see what that changed?

Now our circle runs across the top of the screen!

Let's get it to update y when the position of the circle is at the right of the canvas

Adding an 'if' statement

A big part of programming is something called conditional logic, and here is a perfect place to use it.

Let's think about it in English: If we get to the right of the screen, go to a new line.

Right?

Let's make it more programmery

if ( weAreAtTheRightSideOfTheScreen ) {
  y = y + 50;
}

but what is weAreAtTheRightSideOfTheScreen?

How can we figure that out?

Comparing values

We can tell we are at the full width by using a comparison operator https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators

These are really useful and are the building blocks of all programming languages.

What do we compare? That x is greater than 800!

or in code: x > 800;

Let's use this!

if ( x > 800) {
  y = y + 50;
}

Let's make it read more like English:

var weAreAtTheRightSideOfTheScreen = x > 800;
if ( weAreAtTheRightSideOfTheScreen ) {
  y = y + 50;
}

And since we are using 800 twice, let's pull that into a variable as well;

var x = 0;
var y = 0;
var myCanvasWidth = 800;
var myCanvasHeight= 800;

Woo! Ok, so what did we do?

Our code should look like this now:

var x = 0;
var y = 0;
var myCanvasWidth = 800;
var myCanvasHeight = 800;

function setup() {
  noFill();
  createCanvas(myCanvasWidth, myCanvasHeight);
  background(50, 100, 50);
  line(15, 25, 60, 60);
  rect(60, 60, 80, 80);
  ellipse(60, 60, 80, 80);
}

function draw() {
  ellipse(x, y, 20, 20);
  x = x + 5;

  var weAreAtTheRightSideOfTheScreen = x > myCanvasWidth;
  if (weAreAtTheRightSideOfTheScreen) {
    y = y + 100;
  }
  console.log(x);
  console.log(y);
}

Why didn't that work?

Let's look at our requirement again: When our x variable is larger than the width of our canvas, increase the y position of the ellipse and reset our x to 0;

Also, check out the conosle, that should also give you a hint as to what is going on :)

Doh! We never reset x to 0! x = 0;

function draw() {
  ellipse(x, y, 20, 20);
  x = x + 5;

  var weAreAtTheRightSideOfTheScreen = x > myCanvasWidth;
  if (weAreAtTheRightSideOfTheScreen) {
    y = y + 100;
    x = 0;
  }
  console.log(x);
  console.log(y);
}

How cool is this?!?!?!? We got ourselves a bonafide movin n groovin web thingy!

Stopping the loop

An important part of programming (and life) is knowing when to stop

In this case, it is when we get to the bottom of the page. Let's write our requirement!

When we get to the bottom of the page, stop calling the draw function.

...hummm....

The first part of that seems fine, we can deal with that:

if ( y > myCanvasHeight ){
  // do something
}

but that second part seems like it is outside of our control...or is it...?

To the docs!

Whenever something seems out of your control, look at the docs and see what you can find!

Since we are really smart and lucky, we guess that it starts with no just like noFill did: https://p5js.org/reference/#/p5/noLoop

noLoop();

if ( y > myCanvasHeight ){
  noLoop();
}

Cleanup the Setup

Remove the line, rect and ellipse from the setup() function Your code should look like this:

var x = 0;
var y = 0;
var myCanvasWidth = 800;
var myCanvasHeight = 800;

function setup() {
  noFill();
  createCanvas(myCanvasWidth, myCanvasHeight);
  background(50, 100, 50);
}

function draw() {
  ellipse(x, y, 20, 20);
  x = x + 5;

  var weAreAtTheRightSideOfTheScreen = x > myCanvasWidth;
  if (weAreAtTheRightSideOfTheScreen) {
    y = y + 100;
    x = 0;
  }

  if ( y > myCanvasHeight ) {
    noLoop();
  }
}

It's crazy how simple our code is for what it is doing!

But it's gonna get EVEN better!!! Let's add some user interaction!

Adding Some Interaction

The interaction I want to add is basically making a storm stopper:

Try and click the circle as it is moving!

As we always should, look at the documentation and see if p5 has anything that can help us with this!

It sure does! https://p5js.org/reference/#/p5/mousePressed

Let's give that function some directions!

Implementing the mousePressed function

This mousePressed function is provided to us by p5. We can make it whatever we would like, but it the commands in this function only happen when the mouse is pressed.

Let's do something simple, like display an ellipse when the mouse is pressed:

function mousePressed() {
  ellipse(myCanvasWidth/2, myCanvasHeight/2, 40, 40);
}

Drawing the circle under your mouse

Just like with height we can get the X and Y position of our mouse at any time through p5.

Let's use those built in Environment variables to our advantage and draw our ellipse where our mouse is!

ellipse(mouseX, mouseY, 40, 40);

function mousePressed() {
  ellipse(mouseX, mouseY, 40, 40);
}

That's great but I only want one circle at a time, how do I clear our the screen?

Clearing out the Screen

A very important function is the clear function: https://p5js.org/reference/#/p5/clear

It allows us to clear out the canvas; clear();

function mousePressed() {
  clear();
  ellipse(mouseX, mouseY, 40, 40);
}

Well that works, kind of...

Where did the background go?!?!

Adding the background again

We can make a function that fills our background for us!

function makeBackground() {
  background(50, 100, 50);
}

and we can call it in mousePressed and setUp to keep the background green!

function mousePressed() {
  clear();
  makeBackground();
  ellipse(mouseX, mouseY, 40, 40);
}

Coloring our new circle

Let's add some color, a nice blue, to our new circle using the fill() function https://p5js.org/reference/#/p5/fill

function mousePressed() {
  clear();
  makeBackground();
  fill(0, 0, 200);
  ellipse(mouseX, mouseY, 40, 40);
}

Detecting if we clicked the circle snake thing

Here is our requirement: Is the mouseX and mouseY coordinate of my mouse within 20 pixels of the origin of the latest known x and y coordinates?

It is much easier to think about this problem in terms of our two directions, X and Y:

  • is mouseX within 40 of x
  • is mouseY within 40 of y

In code this might look like this:

var bottomBoundaryX = x - 20;
var topBoundaryX = x + 20;
var isNearX = ( mouseX > bottomBoundaryX ) && ( mouseX < topBoundaryX );

var bottomBoundaryY = y - 20;
var topBoundaryY = y + 20;
var isNearY = ( mouseY > bottomBoundaryY ) && ( mouseY < topBoundaryY );

Determining if we should show the "success" message

Our requirement: If it is near the x origin and near the y origin print out the text

if(isNearX && isNearY) {
  textSize(32);
  fill(200, 0, 0);
  text("success! ", 20, 200);
}

We need to establish a text size and color before we call text

And that is it!

Here is our super duper mvp!

Finished Game!

var x = 0;
var y = 0;
var myCanvasWidth = 800;
var myCanvasHeight = 800;

function setup() {
  noFill();
  createCanvas(myCanvasWidth, myCanvasHeight);
  makeBackground();
}

function makeBackground() {
  background(50, 100, 50);
}

function draw() {
  noFill();
  ellipse(x, y, 20, 20);
  x = x + 5;

  var weAreAtTheRightSideOfTheScreen = x > myCanvasWidth;
  if (weAreAtTheRightSideOfTheScreen) {
    y = y + 100;
    x = 0;
  }

  if ( y > myCanvasHeight ) {
    noLoop();
  }
}


function mousePressed() {
  clear();
  makeBackground();
  fill(0, 0, 200);
  ellipse(mouseX, mouseY, 40, 40);
  textSize(32);
  fill(0, 102, 153);

  var bottomBoundaryX = x - 20;
  var topBoundaryX = x + 20;
  var isNearX = ( mouseX > bottomBoundaryX ) && ( mouseX < topBoundaryX );

  var bottomBoundaryY = y - 20;
  var topBoundaryY = y + 20;
  var isNearY = ( mouseY > bottomBoundaryY ) && ( mouseY < topBoundaryY );

  if (isNearX && isNearY) {
    textSize(32);
    fill(200, 0, 0);
    text("success! ", 20, 200);
  }
}

Additional Features

  • Make the snake go in a circle
    • oscillate the radius
    • increase / decrease the speed
  • keep a score
  • Make the snake go in a random direction
  • track longest combo
  • increase the difficulty

About

Basic p5 setup for workshop


Languages

Language:JavaScript 100.0%Language:HTML 0.0%