Making a Simple “Platform” Game
Part 1 – platform “landscape” with horizontal scrolling
platforms
is an array of simple objects with x
, y
and w
(width) fields. All platforms are 10 pixels thick (see draw()
). Platforms are “shifted” by offset
when we draw them. When new platforms are needed (as the offset increases), we create new platform
s. Old platform objects are removed as they scroll off the left edge of the canvas.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
// Game example // A platform game, horizontal scrolling // first, let's make a generative "landscape" with platforms // each platform will be an object with an x, y, and w parameter var platforms = []; // to scroll, we will increment offset. Everything is shifted left by offset var offset = 0; function newPlatform(px, py, pw) { return {x: px, y: py, w: pw}; } function setup() { createCanvas(600, 300); platforms.push(newPlatform(600, 200, 200)); } // compute the location of the right end of a platform function platRight(p) { return p.x + p.w; } // return the last platform object function platLast() { return platforms[platforms.length - 1]; } function draw() { background("lightblue"); fill("green"); stroke("green"); rect(0, height - 50, width, 50); // the ground fill(0); stroke(0); for (var i = 0; i < platforms.length; i++) { var p = platforms[i]; rect(p.x - offset, p.y, p.w, 10); } // if first platform is offscreen to left, remove it if (platforms.length > 0 && platRight(platforms[0]) < offset) { platforms.shift(); } // if last platform is totally within canvas, make a new one if (platRight(platLast()) - offset < width) { var p = newPlatform(platRight(platLast()), // start location random(50, 225), // height of new platform 200); // all platforms have width 200 for now platforms.push(p); // add to our array of platforms } text(platforms.length.toString() + " platforms", 10, 30); // move the "landscape" offset += 1; } function mousePressed() { } function keyPressed() { } |
Part 2 – adding a “mario” character
We always draw the character in the middle of the canvas, so we only worry about the vertical (Y) coordinate. We need to find which platform is currently in the middle of the screen, so we do a linear search to find it. Then we move the “mario” based on whether it is above, on, or below the relevant platform. The character automatically “wraps around” when it falls, which means we need no interaction to do some testing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
// Game example, part 2, see comments starting with //2 // A platform game, horizontal scrolling // first, let's make a generative "landscape" with platforms // each platform will be an object with an x, y, and w parameter //2 in part 2, we add a "mario" var platforms = []; var marioY = 0; //2 the height of our "mario" // to scroll, we will increment offset. Everything is shifted left by offset var offset = 0; function newPlatform(px, py, pw) { return {x: px, y: py, w: pw}; } function setup() { createCanvas(600, 300); platforms.push(newPlatform(600, 200, 200)); } // compute the location of the right end of a platform function platRight(p) { return p.x + p.w; } // return the last platform object function platLast() { return platforms[platforms.length - 1]; } function draw() { background("lightblue"); fill("green"); stroke("green"); rect(0, height - 50, width, 50); // the ground fill(0); stroke(0); for (var i = 0; i < platforms.length; i++) { var p = platforms[i]; rect(p.x - offset, p.y, p.w, 10); } // if first platform is offscreen to left, remove it if (platforms.length > 0 && platRight(platforms[0]) < offset) { platforms.shift(); } // if last platform is totally within canvas, make a new one if (platRight(platLast()) - offset < width) { var p = newPlatform(platRight(platLast()), // start location random(50, 225), // height of new platform 200); // all platforms have width 200 for now platforms.push(p); // add to our array of platforms } text(platforms.length.toString() + " platforms", 10, 30); //2 move and draw the "mario" //2 which platform is current? linear search (!) through platforms var pindex = 0; var marioX = width / 2; while (platRight(platforms[pindex]) - offset < marioX) { pindex += 1; } //2 now pindex is index of the platform in the middle of canvas //2 find the platform height var py = platforms[pindex].y; //2 show some debugging information for now text("pindex " + pindex + " py " + py, 10, 50); //2 if we are above it, fall toward it, but do not go past it if (marioY <= py) { marioY = min(py, marioY + 1); } else { //2 if we are below it, fall to ground marioY = min(height, marioY + 1); } //2 wrap around, "fall from sky" again if we "die" if (marioY >= height) { marioY = 0; } //2 draw the "mario" fill("brown"); stroke("brown"); rect(marioX, marioY - 20, 20, 20); // move the "landscape" offset += 1; } function mousePressed() { } function keyPressed() { } |
Part 3 – Adding “jump” command and simple physics for falling
To implement jumping, we start by adding marioDy
, which is the velocity of the “mario” character. We have to add more logic for controlling position, but now the “jump” command is simply setting marioDy
to -10 to give it an upward velocity. (See line 113.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
// Game example, part 3, see comments starting with //3 // A platform game, horizontal scrolling // first, let's make a generative "landscape" with platforms // each platform will be an object with an x, y, and w parameter //2 in part 2, we add a "mario" //3 in part 3, we add a "jump" command. The jump will give "mario" a //3 vertical velocity. var platforms = []; var marioY = 0; //2 the height of our "mario" var marioDy = 0; //3 the vertical velocity of "mario" // to scroll, we will increment offset. Everything is shifted left by offset var offset = 0; function newPlatform(px, py, pw) { return {x: px, y: py, w: pw}; } function setup() { createCanvas(600, 300); platforms.push(newPlatform(600, 200, 200)); } // compute the location of the right end of a platform function platRight(p) { return p.x + p.w; } // return the last platform object function platLast() { return platforms[platforms.length - 1]; } function draw() { background("lightblue"); fill("green"); stroke("green"); rect(0, height - 50, width, 50); // the ground fill(0); stroke(0); for (var i = 0; i < platforms.length; i++) { var p = platforms[i]; rect(p.x - offset, p.y, p.w, 10); } // if first platform is offscreen to left, remove it if (platforms.length > 0 && platRight(platforms[0]) < offset) { platforms.shift(); } // if last platform is totally within canvas, make a new one if (platRight(platLast()) - offset < width) { var p = newPlatform(platRight(platLast()), // start location random(50, 225), // height of new platform 200); // all platforms have width 200 for now platforms.push(p); // add to our array of platforms } text(platforms.length.toString() + " platforms", 10, 30); //2 move and draw the "mario" //2 which platform is current? linear search (!) through platforms var pindex = 0; var marioX = width / 2; while (platRight(platforms[pindex]) - offset < marioX) { pindex += 1; } //2 now pindex is index of the platform in the middle of canvas //2 find the platform height var py = platforms[pindex].y; //3 show some debugging information for now text("pindex " + pindex + " py " + py + " Dy " + marioDy, 10, 50); //2 if we are above it, fall toward it, but do not go past it if (marioY <= py) { marioY = min(py, marioY + marioDy); //3 change Y by Dy } else { //2 if we are below it, fall to ground //3 if dY is negative, we could "punch through" a platform from below //3 to avoid this, once we are below a platform, force Dy non-negative if (marioDy < 0) { marioDy = 0; } marioY = min(height, marioY + marioDy); } //2 wrap around, "fall from sky" again if we "die" if (marioY >= height) { marioY = 0; marioDy = 0; } //2 draw the "mario" fill("brown"); stroke("brown"); rect(marioX, marioY - 20, 20, 20); // move the "landscape" offset += 1; //3 accelerate "mario" with gravity marioDy = marioDy + 1; } function mousePressed() { } function keyPressed() { marioDy = -10; //3 velocity set to up when key is pressed } |
Here is the sketch so far
Note that Dy (marioDy) continues to increase when the character is on a platform, and the character does not fall in a plausible way from the platform, so there is more work to do here.