How to code Doodle Jump!

It’s been a little while seen I’ve done some game development so I thought I’d jump right in and code doodle jump. In this blog I’ll be going through the step-by-step process I took to code the game, it’s really not that difficult!

Let’s get started

In this blog I’ll be writing how I coded the game using JavaScript with the p5.js library, I used the https://editor.p5js.org/ to code it, so you can go ahead and code along with me!

Note: you can find all the code in this blog here

Let’s go ahead and create a brand new Doodler class where we’re going to store some information about our little man!

class Doodler {
   constructor() {
     this.x = width / 2;
     this.y = height / 2;
     this.height = 60;
     this.width = 60;
   }
   draw() {
     rect(this.x, this.y, this.width, this.height);
   }
}

then add the reference to the file in our html between the <body> tags:

<script src="Doodler.js"></script

Now in our main, let’s create the Doodler object and call the draw function.

let doodler;
function setup() {
  createCanvas(400, 600);
  doodler = new Doodler();
}
function draw() {
  background(100, 100, 255);
  doodler.draw();
}

And you should see something like this when you hit play:

It’s not exactly centred but let’s not worry about that just yet.

Adding gravity

So in doodle jump if you’re not busy jumping on platforms you’re busy falling to your death, so let’s add some gravity to do that.

class Doodler {
    constructor() {
        this.x = width / 2;
        this.y = height / 2;
        this.height = 60;
        this.width = 40;

        this.velocity = 0;
        this.gravity = 0.1;
    }

    draw() {
        rect(this.x, this.y, this.width, this.height);
    }

    update() {
        this.velocity += this.gravity;
        this.y += this.velocity;
    }
}

And call the update() function in our main draw function in sketch.js.

let doodler;
function setup() {
  createCanvas(400, 600);
  doodler = new Doodler();
}

function draw() {
  background(100, 100, 255);
  doodler.draw();
  doodler.update();
}

And thus, he falls.

Making the Doodler jump

Let’s add a jump function that we will trigger by clicking spacebar to begin with. Add this code to sketch.js:


function keyPressed () {
  if (key == ' ') {
    doodler.jump();
  } 
}

Of course, we haven’t implemented the jump function yet, so let’s do that.

We’re going to want something to denote how much force to apply when we jump, let’s call it jumpForce and set it to some arbitrary number, I’m going to go with 9!

class Doodler {
  constructor() {
    this.x = width / 2;
    this.y = height / 2;
    this.height = 60;
    this.width = 40;

    this.velocity = 0;
    this.gravity = 0.1;
    this.jumpForce = 9; // add this!
  }
  // .....
  // add the new jump function!
  jump() {
    this.velocity -= this.jumpForce;
  }
}

Woo, now we can jump!

Move left and right

In order to move left and right we can make use of the p5js keyIsDown function and pass it in the left and right arrow keys, so in our update function in Doodler add the following:

  update() {
    this.velocity += this.gravity;
    this.y += this.velocity;
    
      
    if (keyIsDown(LEFT_ARROW)) {
      this.x -= 4;
    } 
    
    if (keyIsDown(RIGHT_ARROW)) {
      this.x += 4;
    }
  }

And you should have something like this:

However, there’s an issue with this, when we go off too far to the left or right we lose our Doodler. In doodle jump if you go too far right you’ll end up on the left of the screen and when you go too far left you’ll end up on the right. Let’s implement this.

Add the following code to the top of your update function in Doodler.js.

  update() {
    if (this.x + this.width < 0) this.x = width;   // add this screen wrapping
    if (this.x > width) this.x = -this.width;
   // ...
  }

So remember the reference point for the Doodler is the very top left of the rectangle. So in the scenario where we’re going off the left of the screen we need to make sure the rest of the rectangle is off the screen too, not just the top left hence the this.x + this.width < 0. And when that condition is met we set the x position of the Doodler to the width which is the width of the screen.

Adding the platforms!

Let’s add a new file called Platform.js and add it to our index.html like we did above. This object is going to take an x and a y parameter, so that we can control where the platform spawns outside of the class.

class Platform {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    
    this.height = 15;
    this.width = 60;
  }
  
  draw() {
    fill(100, 255, 100);
    rect(this.x, this.y, this.width, this.height);
  }
}

Next, let’s create an array to store the platforms in sketch.js. We need some way to determine how many platforms are on the screen at a given time, opening up a game of Doodle jump it would seem there’s usually around 6 platforms on the screen.

So in our setup function let’s specify the platformCount of 6. We then need to determine the gap between each platform, which is constant too – let’s divide the height of the screen by the number of platforms, that’ll give us a nice even distribution. Then, let’s create the platforms and push them into our array.

Then in our draw() function loop through the platforms and draw them!

let doodler;

let gap;
let platforms = []; // create the empty platform array
function setup() {
  createCanvas(400, 600);
  doodler = new Doodler();
  
  // create the platforms
  let platformCount = 6;
  gap = height / platformCount;
  for (let i = 1; i < 6; i++) {
    platforms.push(new Platform(random(width), height - i*gap))
  }
  
}

function draw() {
  background(100, 100, 255);
  doodler.draw();
  doodler.update();
  
  
  // draw our new platforms
  for (let platform of platforms) {
    platform.draw();
  }
}


function keyPressed () {
  if (key == ' ') {
    doodler.jump();
  } 
}

You should see something like this:

Moving the screen with the doodler

So we want our Doodler to be at the centre of the screen, so if he moves up we want to move up with him!

Adding just one line of code in our sketch.js draw() function will do the trick here:

translate(0, width / 2 - doodler.y);

We are translating to the y position of the player. Translating is a very powerful tool in coding games and is used quite frequently, more information can be found here for other potential applications!

Making the platforms endless

So as you can see if I hit spacebar and jump a few times I get to a world with no platforms, which isn’t very good for our Doodler, let’s add some code that’ll generate them on the fly.

Add the following code to the draw() function in sketch.js

  // create more platforms as the doodler moves up the screen
  if (doodler.y < platforms[platforms.length-1].y + 200) {
    platforms.push(new Platform(random(width), platforms[platforms.length-1].y - gap));
  }

So as the player moves up the screen we will create more platforms.

We’ll also want some code to remove the blocks when they are off the screen but we’ll leave that for now.

Jumping on the platforms

Next let’s actually make our game playable and stop cheating by hitting spacebar all the time!

We need to check whether our Doodler is hitting the the platforms and when he does call our jump function.

Let’s pass in the platforms array created in sketch.js to our doodler.update() function like this:

doodler.update(platforms);

Now we can write the logic to determine if we have hit the platform.

Y hit detection:

So if the bottom of the Doodler (this.x + this.height) is between the top of the platform and the bottom of the platform then we can check if we have hit the platform horizontally.

X hit detection:

We can hit the platform between two points which are minX and maxX. minX is just the platform take away the width of the Doodler and maxX is the same but adding the width of the platform.

So in our update function we can add the following code.

    for (let platform of platforms) {
      if (this.y + this.height >= platform.y && this.y + this.height <= platform.y + platform.height) {
        
        let minX = platform.x - this.width;
        let maxX = platform.x + platform.width;
        
        if (this.x >= minX && this.x <= maxX) {
          this.jump();
        }
      }
    }

And you’ll end up with something like the following:

Well, hit detection is working, but the velocity get’s a little out of hand, let’s add a maximum velocity:

So also in the update() function of the Doodler class:

if (this.velocity < -9) this.velocity = -9;

And the game should play a little more as expected:

Adding a score

Next let’s add a score, in doodle jump you pretty much get a point every time you jump on a new platform, I’m just going to add a point every time we remove an item from the platforms array for it being off the screen. So in our update method add the following (Don’t forget to create let score = 0 at the top of the file)

  if (platforms[0].y > doodler.y + 400) {
    platforms.splice(0, 1);
    score++;
  }

So if the platform is far below the Doodler’s y position we will splice it meaning it gets removed from the array and we increment the score.

Let’s display the score (Also in the draw function)

  push();
  fill(255, 255, 255)
  textSize(30);
  textAlign(CENTER);
  text(score, width/2, doodler.y - 150);
  pop();

Notice the use of the push() and pop() functions, this prevents any styling, such as the fill colour cascading down onto other elements.

The game should look like this:

Prettying it up!

It might play a little bit like doodle jump but it certainly doesn’t look like it!

Let’s add this background:

Add the file to your project and then add it like the following:


let bg;
function setup() {
  // ...
  bg = loadImage('bg.png'); // add this to load the background
  
}

function draw() {
  image(bg, 0, 0); // at the very start of the draw function
  // ...
} 

Hopefully you have the following:

Next let’s add the Doodler images!

We want one for when he is going left and another for when he’s going right.

Much the same as before load those images by adding the following to your setup:

  doodlerLeft = loadImage('doodler-left.png');
  doodlerRight = loadImage('doodler-right.png');
  doodler = new Doodler(doodlerLeft, doodlerRight);

Notice how we’re passing these into the constructor of the Doodler class, we’ll need to set these in the class so we can use them when we’re drawing:

class Doodler {
  constructor(left, right) {
    // ...
    this.left = left;
    this.right = right;
    
    this.goingLeft = true;
  }

  draw() {
    // ...
    if (this.goingLeft) {
      image(this.left,this.x,this.y,this.width, this.height);
    } else {
      image(this.right,this.x,this.y, this.width, this.height);
    }
  }

  update(platforms) {
     // ...
    if (keyIsDown(LEFT_ARROW)) {
      this.x -= 4;
      this.goingLeft = true;
    } 
    
    if (keyIsDown(RIGHT_ARROW)) {
      this.x += 4;
      this.goingLeft = false;
    }
  }
}

So when we’re going left the Doodler changes image to the left image and the same for when we’re going right!

Next let’s add the platforms:

See if you can do this one yourself as a little test! If you get stuck then you can check out how I done it https://editor.p5js.org/codeheir/sketches/e5obaA_Ss

The finished game

There’s still quite a lot you can do here but I’ve definitely laid down the foundation, here’s some extra stuff you can do

  • Add a screen when you die and offer to restart
  • Store the high scores
  • Play around with the moving left/right, you could use lerp to make this a lot smoother
  • Fiddle with the jump force make it more responsive
  • Add in aliens!
  • Master the hit detection, the Doodler has a big nose which throws off the hit detection a little

As mentioned you can go and look at the code here, there’ll be a few extra tweaks on there that are not in this blog:

I hope you enjoyed this blog, If you did then please sign up to the newsletter below where I release exclusive content weekly!

2 comments

  1. Moving the screen with the doodler
    Youve got width written in the translate,

    Pretty sure it should be height.

    • Good spot, yeah should definitely be height. Guess this is one of those fortunate scenarios where writing the wrong code doesn’t really make much difference 🙂 (Although you may have to tweak the jumpForce in the doodler object) Thanks for pointing it out.

Leave a Reply