My “Hundreds” tutorial series is dated back to 2013, a previous gaming era with Flash still on the run on desktop computers.
Time passed, Flash died and hyper casual games now are mostly played in portrait mode.
So I kept the original concept of making circles grow while avoiding collisions, but I changed some rules:
1 – Circles do not collide, they tun on their own and simply overlap. Having circles colliding and bounce would make the game too unpredictable.
2 – Each circle is bound to a button with the same number.
3 – Tap and hold a button to make corresponding circle grow.
4 – Release the button to stop circle growth.
5 – If a growing circle overlaps any other circle, both circles get halved
6- You can make a circle grow only once.
Does it sound complicate? Have a try:
Tap and hold a button to make the corresponding circle grow. Release before it overlaps another circle.
What’s your best score?
The source code is a bit more than 100 lines, still uncommented because I need to add a couple more features, but easy to understand:
let game; let gameOptions = { ballSpeed: 300, balls: 8, ballRadius: 50, growRate: 1 } window.onload = function() { let gameConfig = { type: Phaser.AUTO, scale: { mode: Phaser.Scale.FIT, autoCenter: Phaser.Scale.CENTER_BOTH, parent: "thegame", width: 750, height: 1334 }, physics: { default: "arcade", }, scene: playGame } game = new Phaser.Game(gameConfig); window.focus(); } class playGame extends Phaser.Scene{ constructor(){ super("PlayGame"); } preload(){ this.load.image("ball", "ball.png"); this.load.image("button", "button.png"); } create(){ this.physics.world.setBounds(0, 0, game.config.width, game.config.width); this.ballGroup = this.physics.add.group(); this.ballArray = []; this.textArray = []; this.score = 0; let gameArea = new Phaser.Geom.Rectangle(0, 0, game.config.width, game.config.width); let buttonsPerRow = gameOptions.balls / 2; let buttonWidth = game.config.width / buttonsPerRow; this.buttonGroup = this.add.group(); for(let i = 0; i < gameOptions.balls; i++){ let randomPosition = Phaser.Geom.Rectangle.Random(gameArea); let directionVector = Phaser.Math.RandomXY(new Phaser.Math.Vector2, gameOptions.ballSpeed); let ball = this.ballGroup.create(randomPosition.x, randomPosition.y, "ball"); this.ballArray.push(ball); ball.setCircle(256); ball.displayHeight = gameOptions.ballRadius; ball.displayWidth = gameOptions.ballRadius; ball.index = i; ball.setCollideWorldBounds(true); ball.setVelocity(directionVector.x, directionVector.y); ball.setBounce(1); let ballText = this.add.text(randomPosition.x, randomPosition.y, i, { fontFamily: "Arial", fontSize: 24, color: "#000000" }); ballText.setOrigin(0.5, 0.5) this.textArray.push(ballText); let button = this.add.sprite(buttonWidth * (i % (gameOptions.balls / 2)), game.config.width + buttonWidth * Math.floor(i / (gameOptions.balls / 2)), "button"); button.setOrigin(0, 0); button.index = i; button.displayWidth = buttonWidth; button.displayHeight = buttonWidth; this.buttonGroup.add(button); let buttonText = this.add.text(button.getBounds().centerX, button.getBounds().centerY, i, { fontFamily: "Arial", fontSize: 64, color: "#000000" }); buttonText.setOrigin(0.5, 0.5) } this.ballToGrow = null this.scoreText = this.add.text(0, game.config.height, "Score: 0", { fontFamily: "Arial", fontSize: 64 }); this.scoreText.setOrigin(0, 1); this.input.on("pointerdown", this.startGrowing, this); this.input.on("pointerup", this.stopGrowing, this); this.physics.add.overlap(this.ballGroup, this.ballGroup, this.handleOverlap, null, this); } startGrowing(pointer){ this.buttonGroup.getChildren().forEach(function(button){ if(Phaser.Geom.Rectangle.Contains(button.getBounds(), pointer.x, pointer.y) && button.alpha == 1){ button.alpha = 0.5; this.ballToGrow = button.index; this.ballArray[this.ballToGrow].body.onOverlap = true; } }, this); } stopGrowing(){ this.ballToGrow = null; } handleOverlap(ball1, ball2){ if(this.ballToGrow != null && (ball1.index == this.ballToGrow || ball2.index == this.ballToGrow)){ this.cameras.main.flash(); ball1.displayWidth = Math.max(ball1.displayWidth / 2, gameOptions.ballRadius); ball2.displayWidth = Math.max(ball1.displayWidth / 2, gameOptions.ballRadius) ball1.displayHeight = ball1.displayWidth ; ball2.displayHeight = ball2.displayWidth ; this.ballToGrow = null; } } update(){ this.score = 0; for(let i = 0; i < gameOptions.balls; i++){ this.textArray[i].x = this.ballArray[i].x; this.textArray[i].y = this.ballArray[i].y; this.score += this.ballArray[i].displayWidth - gameOptions.ballRadius; } this.scoreText.text = this.score; if(this.ballToGrow != null){ console.log("grow") this.ballArray[this.ballToGrow].displayWidth += gameOptions.growRate; this.ballArray[this.ballToGrow].displayHeight += gameOptions.growRate; } } }
This is actually a pretty new concept as there isn’t that much of the original “Hundreds” game, but I can see some potential in it, especially if you consider you can play with one thumb.