This week I am looking at interaction in p5. I wanted to code a simple ‘jump’ game. Something that could be done in less than an hour so: Flappy Bird.
Setup
I first declare some needed variables:
const speed = 3;
let score = 0;
let highscore = 0;
function setup() {
createCanvas(400, 400);
strokeWeight(0);
textAlign(CENTER,CENTER)
thefloor = height;
theceiling = 0;
}
Speed will be used to determine the difficulty of the game. Pipes will move at this speed. I set it as a constant but if I wanted to make the difficulty variable I could declare it using ‘let’.
player object
I first created the player object. I called it ‘frog’ because it jumps though I should have probably called it bird.
To create an object in JavaScript is simple. I simply need to declare it as a class and write the constructor method.
class freg{
constructor(){
this.x = width/2;
this.y = height/2;
this.yvel = 0;
this.pressed = false;
}
}
I am giving my player a position (x,y) and y-velocity. I am also setting a variable to determine whether an input was given.
I will next add a drawself() method
drawself(){
circle(this.x,this.y,32);
}
and a step() method. This will run every frame.
step(){
this.yvel -= 0.2; //gravity
if(keyIsPressed && !this.pressed){
this.pressed = true;
if(keyCode == 32){
this.yvel = 4;
}
}
if(!keyIsPressed){ this.pressed = false; }
this.y = (this.y - this.yvel) //apply movement
if(this.y < theceiling || this.y >= thefloor){
this.die();
};
this.drawself(); //draw
}
The step method includes gravity calculation and input handling. When a key is being pressed and the flag for already having pressed that key is not set, it will grant the player some upwards velocity.
The step method also handles crashing into the ceiling and floor.
The final thing it does is call the ‘die’ method.
die(){
score = 0;
this.y = height/2;
this.yvel = 0;
pipes.x = width;
pipes.hei = random(height);
pipes.cleared = false;
}
Dying will reset the score and position of the player/pipes.
Pipes
I’m defining pipes as a single object with height, width and gap. These will affect the pipe object as such:

class pipe{
constructor(hei,gap){
this.hei = hei;
this.gap = gap;
this.x = width;
this.wid = 64;
this.cleared = false;
}
}
The draw function is slightly more involved than drawing the player. It draws two rectangles for each pipe (top and bottom).
drawself(){
rect(this.x,0,this.wid,this.hei-this.gap/2);
rect(this.x,this.hei+this.gap/2,this.wid,height);
}
The step function handles collision checking and increasing the score when the player successfully flies through the gap. It also moves the pipe to the right of the canvas when it is fully off-screen to the left.
step(){
this.drawself(); //draw
this.x -= speed;
if(this.x < -64){
this.x = width;
this.hei = random(height);
this.cleared = false;
}
if(frog.x > this.x &&
frog.x < this.x + this.wid &&
frog.y > 0 &&
frog.y < this.hei-(this.gap/2)){
frog.die();
}
if(frog.x > this.x &&
frog.x < this.x + this.wid &&
frog.y > this.hei+this.gap/2 &&
frog.y < height){
frog.die();
}
if(this.x+this.wid < frog.x && this.cleared == false){
this.cleared = true;
score++;
}
}
Causing the pipes to wrap around means that there doesn’t need to be multiple pipe objects, just one which reduces memory usage and lag.
Final Steps
All that remains is to assign the two objects to variables in the setup function
function setup() {
...
frog = new freg();
pipes = new pipe(200,128);
}
And step them in the draw function. I will also add some logic to deal with scoring.
function draw() {
background(220);
highscore = max(score,highscore);
textSize(100);
text(score,width/2,64);
textSize(32);
text("HI: "+highscore,width/2,128)
frog.step();
pipes.step();
}
The game is complete.
