var enablePWA = false; if(enablePWA) { // SERVICE WORKER if('serviceWorker' in navigator) { navigator.serviceWorker.register('./js/sw.js'); }; // NOTIFICATIONS TEMPLATE Notification.requestPermission().then(function(result) { if(result === 'granted') { exampleNotification(); } }); function exampleNotification() { var notifTitle = 'MERGE FRUIT'; var notifBody = 'Created by the Francis Davidson Paul.'; //var notifImg = 'img/icons/icon-512.png'; var options = { body: notifBody, icon: notifImg } var notif = new Notification(notifTitle, options); setTimeout(exampleNotification, 30000); } } let game; // global game options let gameOptions = { // falling player fruit range, 0 to 4 playerFruitsRange: 4, // localStorage string name localStorageName: "samegame" } window.onload = function() { // object containing configuration options let gameConfig = { type: Phaser.AUTO, backgroundColor:0xFFE5EC, scale: { mode: Phaser.Scale.FIT, autoCenter: Phaser.Scale.CENTER_BOTH, parent: "thegame", width: 750, height: 1334 }, // physics settings physics: { default: "matter", matter: { gravity: { y: 1 }, debug: false } }, scene: playGame } game = new Phaser.Game(gameConfig); window.focus(); } class playGame extends Phaser.Scene{ constructor(){ super("PlayGame"); } preload(){ //preload bitmap font this.load.bitmapFont("font", "assets/fonts/font.png", "assets/fonts/font.fnt"); //preload bitmap images, spritesheet and sounds var resources = { 'image': [ ["tittle", "assets/sprites/tittle.png"], ["borderLine", "assets/sprites/borderLine.png"], ["x", "assets/sprites/x.png"], ["best", "assets/sprites/best.png"], ["best", "assets/sprites/best.png"] ], 'spritesheet': [ ["particle", "assets/sprites/particle.png", {frameWidth: 20,frameHeight: 20}], ["furits", "assets/sprites/furits.png", {frameWidth: 200,frameHeight: 200}] ], 'audio': [ ['boom', ['assets/audio/boom.mp3','assets/audio/boom.ogg']], ['knock', ['assets/audio/knock.mp3','assets/audio/knock.ogg']], ['water', ['assets/audio/water.mp3','assets/audio/water.ogg']], ['alert', ['assets/audio/alert.mp3','assets/audio/alert.ogg']], ['newLevel', ['assets/audio/newLevel.mp3','assets/audio/newLevel.ogg']], ['gameOver', ['assets/audio/gameOver.mp3','assets/audio/gameOver.ogg']] ] } for(var method in resources) { resources[method].forEach(function(args) { var loader = this.load[method]; loader && loader.apply(this.load, args); }, this); }; } create(){ //sounds decleration this.boom = this.sound.add('boom'); this.knock = this.sound.add('knock'); this.water = this.sound.add('water'); this.alert = this.sound.add('alert'); this.newLevel = this.sound.add('newLevel'); this.gameOver = this.sound.add('gameOver'); // creation of the physics world which will contain all fruits this.matter.world.update60Hz(); // seting bounds physics world this.matter.world.setBounds(); // listener for collision between fruits in physics world this.matter.world.on("collisionstart", this.handleCollisionStart, this); // adding the game tittle sprite "FRUITRIS'; this.tittle = this.add.sprite(game.config.width / 2, game.config.height/2, "tittle"); // group with all active fruits. this.furitGroup = this.add.group(); // adding the player fruit spritesheet; this.playerFruit = this.add.sprite(game.config.width / 2, game.config.height - 1220, "furits"); this.nextFruitNum = Phaser.Math.Between(0, gameOptions.playerFruitsRange); // setup player fruit this.setFurit(); // listener for input, calls "launchFurit" method this.input.on("pointerdown", this.launchFurit, this); // score stats at zero this.score = 0; // text object to display the score this.scoreText = this.add.bitmapText(10, 15, "font", "ccc", 60); this.scoreText.setTint(0xff00ff, 0xffff00, 0x00ff00, 0xff0000); // updateScore will add current score and display it this.updateScore(); // waterMelon stats at zero //this.waterMelon = 0; // text object to display the waterMelon count; //this.waterMelonText = this.add.bitmapText(640, 15, "font", "ccc", 60).setLeftAlign(); //this.waterMelonText.setTint(0xff00ff, 0xffff00, 0x00ff00, 0xff0000); // updateWarterMelon method will add current watermelon count and display it //this.updateWateMelon(); // adding the fruit spritesheet and setting frame to 11/scale 0.25; this.nextFruit = this.add.sprite(game.config.width - 35, 35, "furits"); this.nextFruit.setFrame(Phaser.Math.Between(0, gameOptions.playerFruitsRange)); this.nextFruit.setScale(0.30); this.nextFruitNum = this.nextFruit.frame.name; // adding the borderline sprite and set visible "false"; this.borderLine = this.add.sprite(game.config.width / 2, game.config.height - 1134, "borderLine"); this.borderLine.setVisible(false); // adding the final score sprite and set visible "false"; this.scoreFinal = this.add.sprite(game.config.width / 2, game.config.height/2, "score"); this.scoreFinal.setVisible(false); // adding the best score sprite and set alpha "0"; this.best = this.add.sprite((game.config.width/2) + 5 , 350, "best"); this.best.setAlpha(0); //getting saved score from local storge and display it; this.savedData = localStorage.getItem(gameOptions.localStorageName) == null ? { score: 0 } : JSON.parse(localStorage.getItem(gameOptions.localStorageName)); if(this.savedData.score != 0){ this.best.setAlpha(1); this.bestScoreText = this.add.bitmapText(game.config.width/2, 400, "font", "Best : " + this.savedData.score.toString(), 60).setCenterAlign().setOrigin(0.5, 0); this.bestScoreText.y = this.bestScoreText.y + 50; this.bestScoreText.setTint(0xff00ff, 0xffff00, 0x00ff00, 0xff0000); this.tweens.add({targets: this.bestScoreText, y: this.bestScoreText.y - 50, duration: 275, ease: 'Back.easeOut'}); } //---------------------------particle emitter-------------------------------\\ this.emitter = this.add.particles("particle").createEmitter({ frame: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], scale: { start: 4, end: 0 }, speed: { min: 50, max: 200 }, active: false, lifespan: 300, quantity: 200, alpha: { min: 30, max: 100 } }); this.emitter.setPosition(game.config.width / 2, game.config.height/2) this.emitter.active = true; this.emitter.setEmitZone({ type: 'random', quantity: 200, source: new Phaser.Geom.Circle(0, 0, 250) }); this.emitter.explode(); //-------------------------------------------------------------------------------\\ } // method to add score to current score and display it updateScore(){ this.scoreText.text = this.score; } // method to add watermelon count //updateWateMelon(){ //this.waterMelonText.text = 'fbjdsfj'+this.waterMelon; //} // method to setup player fruit setFurit(){ // player fruit is ready to drop this.playerFruitReady = true; // player fruit visible is true this.playerFruit.setVisible(true); // player fruit 'fruits' sprite sheet frame(random 0 to 4); this.playerFruit.setFrame(this.nextFruitNum); // setting player fruit width and hight this.playerFruit.displayWidth = this.playerFruit.displayHeight = 50 + (this.playerFruit.frame.name * (this.playerFruit.frame.name + 21)); let tween = this.tweens.add({ targets: this.playerFruit, scale: { start: 0, to: this.playerFruit.scale}, ease: 'Back.easeOut', duration: 100 }); // plays knock sound this.knock.play(); } setNextFurit(){ this.nextFruitNum = Phaser.Math.Between(0, gameOptions.playerFruitsRange); this.nextFruit.setFrame(this.nextFruitNum); } // method to hide tittle, best score and call "dropFruit" // called when the pointer is pressed launchFurit(event){ // hide tittle this.tittle.setVisible(false); // hide best score if its there if( this.bestScoreText){ this.bestScoreText.setAlpha(0); this.best.setAlpha(0); } // player fruit is ready to drop if(this.playerFruitReady){ // temporarily make the player fruit is not ready to fall // because its not added to the physic world this.playerFruitReady = false; // temporarily hide the player fruit and this.playerFruit.setVisible(false); // now adding player fruit to physic world to fall // with parameters(pressed pointer x, y, fruits sprite sheet frame number) this.dropFurit(event.x, this.playerFruit.y, this.playerFruit.frame.name) // again setup new player fruit by calling "setFruit" with delat of 5 sec this.time.addEvent({ delay: 500, callbackScope: this, callback: this.setFurit }); this.time.addEvent({ delay: 600, callbackScope: this, callback: this.setNextFurit }); } } // method to drop the player fruit, called when the pointer is pressed dropFurit(posX, posY, frameNum){ // adding the fruit to physic world (pointer x and y) let furit = this.matter.add.sprite(posX, posY, "furits"); // setting 'fruits' sprite sheet frame number furit.setFrame(frameNum); // set restitution to player fruits furit.setBounce(0.4); // set circle size to 100% furit.setCircle(100); // set vertical velocity to player fruits furit.setVelocityY(30); // set width and height to player fruit furit.displayWidth = furit.displayHeight = 50 + (frameNum * (frameNum + 21)); // add player fruit to the fruit group this.furitGroup.add(furit); } // setting collisions between all fruits in physic world handleCollisionStart(event, bodyA, bodyB){ // check collisions between each pair in physic world(bodyA & bodyB) event.pairs.forEach(pair => { const { bodyA, bodyB } = pair; if(bodyA.gameObject && bodyB.gameObject){ // check for game over if fruit reach the border line this.checkGameOver(bodyA.gameObject, bodyB.gameObject); // check both fruits that collide are same, call 'handleInclusion' if(bodyA.gameObject.frame.name == bodyB.gameObject.frame.name){ // check both fruit speed to determine the x and y if(bodyA.speed < bodyB.speed){ this.handleInclusion(bodyA.gameObject, bodyB.gameObject); } else{ this.handleInclusion(bodyB.gameObject, bodyA.gameObject); } } else{ // check both fruits that collide are not same, call 'handleBounce' if(bodyA.speed < bodyB.speed){ this.handleBounce(bodyA.gameObject, bodyB.gameObject); } else{ this.handleBounce(bodyB.gameObject, bodyA.gameObject); } } } }); } // method to add next fruit when the same fruit merge handleInclusion(bodyA, bodyB){ // get x and y pos of the fruit let saveX = bodyA.x; let saveY = bodyA.y; // get frame number of the 'fruits' sprite sheet let frame = bodyA.frame.name + 1; // remove two merged fruits bodyA.destroy(); bodyB.destroy(); // check for the last fruit to merge add big watermelon if(frame === 11){ // add watermelon this.addWaterMelon(game.config.width/2, game.config.height/2, frame, false); }else{ // or add next fruit this.addFurit(saveX, saveY, frame); } // update score + frame number(fruit number)and call 'updateScore' this.score += frame; this.updateScore(); // play spalsh sound effect this.boom.play(); this.water.play(); } // method to bounce back if both fruit are not same handleBounce(bodyA, bodyB){ bodyB.mirrorMovement = bodyA; } // method to add the new fruit when same fruit got merged addFurit(posX, posY, frameNum){ // adding the fruit to physic world (merged fruits x and y) let furit = this.matter.add.sprite(posX, posY, "furits"); // setting 'fruits' sprite sheet frame number furit.setFrame(frameNum); // set restitution to player fruits furit.setBounce(0.4); // set circle size to 100% furit.setCircle(100); // set velocity to player fruits furit.setVelocity(furit.body.velocity.x / 2, furit.body.velocity.y / 2); // set width and height to player fruit furit.displayWidth = furit.displayHeight = 50 + (frameNum * (frameNum + 21)); // add player fruit to the fruit group this.furitGroup.add(furit); // emitte when two same fruits merge //---------------------------particle emitter-------------------------------\\ this.emitter = this.add.particles("particle").createEmitter({ frame: [frameNum, frameNum - 1], scale: { start: frameNum, end: 0 }, speed: { min: 50, max: 200 }, active: false, lifespan: 300, quantity: 50 + (frameNum * frameNum ), alpha: { min: 30, max: 100 } }); this.emitter.setPosition(posX , posY) this.emitter.active = true; this.emitter.setEmitZone({ type: 'random', quantity: 30, source: new Phaser.Geom.Circle(0, 0, 25 + (frameNum * (frameNum + 21))) }); this.emitter.explode(); //-------------------------------------------------------------------------------\\ let tween = this.tweens.add({ targets: furit, delay: 100, scale: { start: 0, to: furit.scale}, ease: 'Back.easeOut', duration: 100 }); } //method to add watermelon(final big fruit) and update watermelon addWaterMelon(posX, posY, frameNum, isMoving){ // play new level sound effect this.newLevel.play(); let waterMelon = this.add.sprite(posX, posY, "furits"); waterMelon.setFrame(11); waterMelon.displayWidth = waterMelon.displayHeight = 50 + (11 * (11 + 21)); let tween = this.tweens.add({ targets: waterMelon, delay: 3000, x: game.config.width - 35, y: 35, scale: { start: waterMelon.scale, to: 0.25}, ease: 'Linear', duration: 1000 }); // this.waterMelon += 1; //this.updateWateMelon(); } // check if the fruits reached the finish line checkGameOver(bodyA, bodyB){ //condition to the finish line if(bodyA.y - bodyA.displayWidth <= 100 || bodyB.y - bodyB.displayWidth<= 100){ // call game over function this.gameEnd(); // play game over sound effect this.gameOver.play(); //condition to alert and show the finish line }else if(bodyA.y - bodyA.displayWidth <= 250 || bodyB.y - bodyB.displayWidth<= 250){ // set finish line visible this.borderLine.setVisible(true); // play alert sound effect this.alert.play(); } } //method to remove all touch inputs and fruits gameEnd(){ // disable all touch inputs this.input.enabled = false; // timer to remove all fruits one by one with a interval this.removeEvent = this.time.addEvent({ delay: 250, callback: this.removeFruits, callbackScope: this, loop: true }) } //method to remove all the fruits and restart the game removeFruits(){ console.log('sdfsdf'); //condition to check if any fruits remain before restart the game if(this.furitGroup.getChildren().length > 0){ //get which fruit by its frame number var frameNumber = this.furitGroup.getFirstAlive().frame.name; // emitte on each fruits when game over //---------------------------particle emitter-------------------------------\\ this.emitter = this.add.particles("particle").createEmitter({ frame: frameNumber, scale: { start: frameNumber, end: 0 }, speed: { min: 50, max: 200 }, active: false, lifespan: 300, quantity: 50 + (frameNumber * frameNumber ), alpha: { min: 30, max: 100 }, }); this.emitter.setPosition(this.furitGroup.getFirstAlive().x , this.furitGroup.getFirstAlive().y) this.emitter.active = true; this.emitter.setEmitZone({ type: 'random', quantity: 30, source: new Phaser.Geom.Circle(0, 0, 25 + (frameNumber * (frameNumber + 21))), }); this.emitter.explode(); //remove each from fruit from screen after emitte explode this.furitGroup.getFirstAlive().destroy(); //---------------------------------------------------------------------------- } //restarting the game else{ //compare the score with the best score saved in local storage //and update the best score to display let bestScore = Math.max(this.score, this.savedData.score); localStorage.setItem(gameOptions.localStorageName,JSON.stringify({ score: bestScore })); //removing the timer event this.removeEvent.remove(); //restarting the game by stating the scene again this.scene.start("PlayGame"); } } //use any where inside a method to pause the game //this.scene.pause("PlayGame"); //use any where inside a method to resume the game //this.scene.resume("PlayGame"); }