Click to drop a shape Press R to rotate a shape Press S to shake the screen (costs coins) Press B to drop a bomb (costs coins)
xxxxxxxxxx
let blocks = []; // List of all blocks in the simulation, saved as Block type variables (see block tab for info ^)
const DROP_HEIGHT = 50; // Height shapes are dropped from, in pixels
const SIZE_SCALE = 20; // A scale factor for how big to draw the shapes
let nextNum = 0; // Size (number) of next shape to be dropped
let nextShape = 0; // The shape of the next block to be dropped; 0 for circle, 1 for square
let nextNextNum = 0; // The size (number) of next next shape to be dropped
let nextBlock; // A global variable that stores the next Block to be dropped. It's a temporary object with no collision.
let disable_act = false;// A variable that disables the player's ability to act
let dropTimer = 0; // Counts down until the player can drop another block
let DROP_TIMER_RESET = 20; // The number the timer gets reset to when you drop a block
let coins = 0; // Player's coins, goes up when you drop a shape and down when you use a power
let lose = false; // True/False, whether player has lost
const BOMB_COST = 50; // Coin cost for dropping a bomb
const DROP_COST = 10; // Coin cost for dropping a shape off the screen
const SHAKE_COST = 30; // Coin cost for shaking the screen
let shakeTimer = 0; // Global timer for shaking the screen, if the number is above 0 the screen will shake
const SHAKE_POWER = 6; // The power that the screen shakes with
// Global variables for world objects such as walls and floors
let rightWall; let leftWall; let floor;
function setup() {
new Canvas(400, windowHeight);
colorMode(HSB);
world.gravity.y = 10;
world.allowSleeping = false; // Makes sure objects that come to rest don't fall asleep, so they keep getting physics
// Create walls and floor for the game
let walls = new Group(); // A group lets me make multiple similar sprites that share properties
walls.collider = 'kinematic'; // For example, all the walls are unmovable
walls.w = height;
walls.h = 5;
walls.color = "black";
floor = new walls.Sprite();
floor.x = width/2;
floor.y = height-2;
leftWall = new walls.Sprite();
rightWall = new walls.Sprite();
leftWall.x = 0; rightWall.x = width;
leftWall.y = height/2; rightWall.y = height/2;
leftWall.rotation = 90; rightWall.rotation = 90;
// Generate the first block
nextBlock = new Block(mouseX, DROP_HEIGHT, 0, nextNum, nextShape, 'none');
}
function draw() {
clear(); // Clear the screen - delete this for hard mode!
background("rgb(199,231,242)")
// Check if you've lost
if (coins < 0) lose = true;
if (lose){
background("red")
text("YOU LOST!", width/2, DROP_HEIGHT - 20); // Insult the player
text("YOU ARE A LOSER!", width/2, DROP_HEIGHT);
if (nextBlock != 0) { // Delete the upcoming block if it hasn't already been deleted
nextBlock.s.remove();
nextBlock = 0;
}
return; // Ends the draw loop prematurely so that blocks don't update
}
if (keyIsDown(82)) nextBlock.s.rotation += 2; // Rotate next block if R key pressed
if (nextBlock.type == 'Block') nextBlock.s.x = mouseX; // Update position of next block to be dropped, if there is a next block
// Update all the blocks in the game
for (let i = 0; i < blocks.length; i++) { // This for loop selects each block in the list, once
if (blocks[i].s.y < 0) { // If a block goes above the top of the screen, lose and end the loop
lose = true;
return;
}
// If the bomb hits a block:
if (nextBlock.type == "Bomb"){
if (nextBlock.s.y > height - nextBlock.size) { // If the bomb hits the floor without hitting a block
nextBlock.s.remove(); // Delete the bomb sprite
disable_act = false; // Re-enable user control
nextBlock = new Block(mouseX, DROP_HEIGHT, 0, nextNum, nextShape, 'none'); // Generate a new block
} else if (blocks[i].s.collides(nextBlock.s)) {
blocks[i].s.remove(); // Delete the old Block (just the sprites right now)
nextBlock.s.remove(); // Delete the bomb sprite
blocks.splice(i, 1); // Now delete the 'dead' Block object from the list of all Blocks
disable_act = false; // Re-enable user control
nextBlock = new Block(mouseX, DROP_HEIGHT, 0, nextNum, nextShape, 'none'); // Generate a new block
}
}
// This for loop selects each block in the list that comes after the first one
// This allows me to compare every block to every other block, once, without comparing a block to itself or to another block twice
for (let j = i+1; j < blocks.length; j++) {
// Fetches the actual Sprite object stored in the Block object so I don't have to type as much later :)
let b1s = blocks[i].s;
let b2s = blocks[j].s;
if (blocks[i].number == blocks[j].number && b1s.collides(b2s)) { // If two blocks are the same number and touching
// Make a new block that's inbetween the two combining blocks
blocks.push(new Block((b1s.x+b2s.x)/2,
(b1s.y+b2s.y)/2,
(b1s.rotation+b2s.rotation)/2,
blocks[i].number+1,
round(random()),
'dynamic'));
b1s.remove(); // Delete the old Blocks (just the sprites right now)
b2s.remove();
blocks.splice(j, 1); // Now delete the 'dead' Block object from the list of all Blocks
blocks.splice(i, 1);
}
}
}
// Display Coins
fill("black")
noStroke();
textSize(20);
textAlign(CENTER);
text("COINS: " + coins + " Next Num: " + (nextNextNum+1), width/2, 20);
// Shake the screen if the timer still has time on it
if (shakeTimer) {
if (shakeTimer % 3 == 0) { // Modulus operator makes it so the screen doesn't shake too fast, bigger number = slower shake
rightWall.move(random(-5, 5), 'right', SHAKE_POWER); // Randomly move the walls
leftWall.move(random(-5, 5), 'right', SHAKE_POWER);
// floor.move(random(-5, 5), 'down', SHAKE_POWER)
} else {
rightWall.move(width-rightWall.x, 'right', SHAKE_POWER); // Put the walls back
leftWall.move(0-leftWall.x, 'right', SHAKE_POWER);
// floor.move(height-floor.y, 'down', SHAKE_POWER)
}
shakeTimer--; // Modulus operator doesn't affect the countdown though, it ticks down regardless
}
if (dropTimer) dropTimer--; // Decrease the drop timer if droptimer is > 0
}
function mouseReleased() { // MouseReleased is nice for touchscreen players, so they can plan their next shape drop with a hold tap
if (lose || disable_act || dropTimer) return; // Don't drop a piece if you've lost, or actions are disabled, or the drop timer is > 0
if (mouseX > width || mouseX < 0) { // If you drop a shape off the screen, spend coins
coins -= DROP_COST;
} else {
coins += nextNum+1; // If you drop a shape legally, add the size of the shape to your coins
}
blocks.push(new Block(mouseX, DROP_HEIGHT, nextBlock.s.rotation, nextNum, nextShape, 'dynamic')); // Remake the block to be dropped
nextBlock.s.remove(); // Delete the temporary block
nextNum = nextNextNum;
nextNextNum = int(random(5)); // Pick a new shape size
nextShape = round(random()); // Pick a new shape type
nextBlock = new Block(mouseX, DROP_HEIGHT, 0, nextNum, nextShape, 'none'); // Generate a new block
dropTimer = DROP_TIMER_RESET;
}
function keyPressed() {
if (disable_act) return; // Ignore the keypress if you're disabled from acting
if (keyCode == 83 && coins >= SHAKE_COST) { // If you press the S key, activate the screen shake timer and spend coins
coins -= SHAKE_COST;
shakeTimer = 100;
}
if (keyCode == 66 && coins >= BOMB_COST) { // If you press the B key, spawn a bomb and wait for it to drop
coins -= BOMB_COST;
nextBlock.s.remove();
nextBlock = new Bomb(mouseX, DROP_HEIGHT, 0, -1, 0, 'dynamic');
disable_act = true;
}
}