HTML5 one-button minigame prototype made with Phaser

Read all posts about "" game

Today I am showing you an HTML5 minigame prototype made with Phaser. It was built over the concept of A strange way to move the player with Flash I published more than seven years ago (time passes on planet earth).

The aim of the game is simple: you control the green circle with the rotating arrow. Once you press/tap the screen, arrow will stop its rotation and your power starts charging. You can see your power in the upper left of the screen.

Once you release touch/click on the screen, the green circle will move along arrow direction, according to the power you set.

Collect yellow circles and avoid red circles or you will die

If you die, you can restart the game clicking here

And this is the fully commented source code.

<!doctype html>
<html>
	<head>
    		<script src="phaser.min.js"></script>
    		<style>
    			body{
			    margin:0;
			    background-color:#444444;
			}
    		</style>
    		<script type="text/javascript">
			window.onload = function() {
				
				var game = new Phaser.Game(320,480,Phaser.CANVAS,"",{preload:onPreload, create:onCreate, update:onUpdate});								
                    
				var ball; // the ball! Our hero
                    var arrow; // rotating arrow 
                    var rotateDirection = 1; // rotate direction: 1-clockwise, 2-counterclockwise
                    var power = 0; // power to fire the ball
                    var hudText; // text to display game info
                    var charging=false; // are we charging the power?
                    var degToRad=0.0174532925; // degrees-radians conversion
                    var score = 0; // the score
                    var coin; // the coin you have to collect
                    var deadlyArray = []; // an array which will be filled with enemies
                    var gameOver = false; // flag to know if the game is over
                    
				// these settings can be modified to change gameplay
				var friction = 0.99; // friction affects ball speed
				var ballRadius = 10; // radius of all elements
                    var rotateSpeed = 3; // arrow rotation speed
                    var minPower = 50; // minimum power applied to ball
                    var maxPower = 200; // maximum power applied to ball
                    
                    // when the game preloads, graphic assets are loaded
				function onPreload() {
					game.load.image("ball", "ball.png");
					game.load.image("deadly", "deadly.png");
					game.load.image("coin", "coin.png");
					game.load.image("arrow", "arrow.png");
				}
				
				// function to be executed when the game is created
				function onCreate() {
					
					// center and scale the stage
					game.scale.pageAlignHorizontally = true;
					game.scale.pageAlignVertically = true;
					game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
                    	game.scale.setScreenSize();
                    	
					// add the ball and set its anchor point in the center
					ball = game.add.sprite(game.world.centerX,game.world.centerY,"ball");
					ball.anchor.x = 0.5;
					ball.anchor.y = 0.5;
					
					// ball starting speed
					ball.xSpeed = 0;
					ball.ySpeed = 0;
					
					// the rotating arrow, look at its x registration point
					arrow = game.add.sprite(game.world.centerX,game.world.centerY,"arrow");
					arrow.anchor.x = -1;
					arrow.anchor.y = 0.5;
					
					// place an enemy
					placeDeadly();
					
					// create and place a coin 
					coin = game.add.sprite(Math.random()*400+40,Math.random()*240+40,"coin");
					coin.anchor.x = 0.5;
					coin.anchor.y = 0.5;
					placeCoin();
					
					// create and place the text showing speed and score
					hudText = game.add.text(5,0,"",{ 
						font: "11px Arial",
						fill: "#ffffff", 
						align: "left" 
					});
					
					// update text content
					updateHud();
					
					// listener for input down
					game.input.onDown.add(charge, this);       
				}
				
				// place an enemy
				function placeDeadly(){
					
					// first, create the enemy and set its anchor point in the center
					var deadly = game.add.sprite(0,0,"deadly");
					deadly.anchor.x = 0.5;
					deadly.anchor.y = 0.5;
					
					// add the newly created enemy in the enemy array
					deadlyArray.push(deadly);
					
					// assign it a random position until such position is legal
					do{
						var randomX=Math.random()*(game.width-2*ballRadius)+ballRadius;
						var randomY=Math.random()*(game.height-2*ballRadius)+ballRadius;
						deadlyArray[deadlyArray.length-1].x=randomX;
						deadlyArray[deadlyArray.length-1].y=randomY;
					} while (illegalDeadly());
				}
				
				// determine if an enemy position is illegal
				function illegalDeadly(){
					
					// if the distance between the enemy and the ball is less than three times the radius, it's NOT legal
					if(getDistance(ball,deadlyArray[deadlyArray.length-1])<(ballRadius*3)*(ballRadius*3)){
						return true;
					}
					
					// if the distance between the enemy and any other enemy is less than two times the radius, it's NOT legal
					for(i=0;i<deadlyArray.length-1;i++){
						if(getDistance(deadlyArray[i],deadlyArray[deadlyArray.length-1])<(ballRadius*2)*(ballRadius*2)){
							return true
						}
					}
					
					// otherwise it's legal	
					return false;
				}
				
				// the function to place a coin is similar to the one which places the enemy, but this time we don't need
				// to place it in an array because there's only one coin on the stage
				function placeCoin(){
				
					// assign the coin a random position until such position is legal
					do{
						coin.x=Math.random()*(game.width-2*ballRadius)+ballRadius;
						coin.y=Math.random()*(game.height-2*ballRadius)+ballRadius;
					} while (illegalCoin());
				}
				
				// determine if a coin position is illegal
				function illegalCoin(){
				
					// if the distance between the coin and any ball is less than 2.5 times the radius, it's NOT legal
					if(getDistance(ball,coin)<(ballRadius*2.5)*(ballRadius*2.5)){
						return true;
					}
					
					// if the distance between the coin and any enemy is less than three times the radius, it's NOT legal
					for(i=0;i<deadlyArray.length;i++){
						if(getDistance(deadlyArray[i],coin)<(ballRadius*3)*(ballRadius*3)){
							return true
						}
					}
					
					// otherwise it's legal
					return false;	
				}
				
				// function to be executed each time the game is updated
				function onUpdate() {
				
					// the game is update only if it's not game over
					if(!gameOver){
						
						// when the player is charging the power, this is increased until it reaches the maximum allowed
						if(charging){
							power++;
							power = Math.min(power,maxPower)    
							// then game text is updated
							updateHud();		
						}
						
						// if the player is not charging, keep rotating the arrow
						else{
							arrow.angle+=rotateSpeed*rotateDirection;
						}
						
						// update ball position according to its speed
						ball.x+=ball.xSpeed;
						ball.y+=ball.ySpeed;
						
						// handle wall bounce
						wallBounce();
						
						// reduce ball speed using friction
						ball.xSpeed*=friction;
						ball.ySpeed*=friction;
						
						// update arrow position
						arrow.x=ball.x;
						arrow.y=ball.y;
						
						// if the player picked a coin, then update score and text, change coin position and add an enemy
						if(getDistance(ball,coin)<(ballRadius*2)*(ballRadius*2)){
							score += 1;
							placeDeadly();
							placeCoin();
							updateHud();	
						}
						
						// if the player hits an enemy, it's game over
						for(i=0;i<deadlyArray.length;i++){
							if(getDistance(ball,deadlyArray[i])<(ballRadius*2)*(ballRadius*2)){
								gameOver = true;
							}	
						}
					}
	    			}
	    			
	    			// function to handle bounces. Just check for game boundary collision
	    			function wallBounce(){
					if(ball.x<ballRadius){
						ball.x=ballRadius;
						ball.xSpeed*=-1
					}
					if(ball.y<ballRadius){
						ball.y=ballRadius;
						ball.ySpeed*=-1
					}
					if(ball.x>game.width-ballRadius){
						ball.x=game.width-ballRadius;
						ball.xSpeed*=-1
					}
					if(ball.y>game.height-ballRadius){
						ball.y=game.height-ballRadius;
						ball.ySpeed*=-1
					}    
				}
	    			
	    			// simple function to get the distance between two sprites
	    			// does not use sqrt to save CPU
	    			function getDistance(from,to){
					var xDist = from.x-to.x
					var yDist = from.y-to.y;
					return xDist*xDist+yDist*yDist;
				}
	    			
	    			// when the player is charging, set the power to min power allowed
	    			// and wait the player to release the input to fire the ball
	    			function charge(){
	    				power = minPower;
	    				game.input.onDown.remove(charge, this); 
					game.input.onUp.add(fire, this);  
					charging=true;
				}
				
				// FIRE!!
				// update ball speed according to arrow direction
				// invert arrow rotation
				// reset power and update game text
				// wait for the player to fire again
				function fire(){
					game.input.onUp.remove(fire, this); 
					game.input.onDown.add(charge, this);
					ball.xSpeed += Math.cos(arrow.angle*degToRad)*power/20;
					ball.ySpeed += Math.sin(arrow.angle*degToRad)*power/20;
					power = 0;
					updateHud();
					charging=false; 
					rotateDirection*=-1;
				}
				
				// function to update game text
				function updateHud(){
					hudText.text = "Power: "+power+" * Score: "+score	
				}
				
	    		};
		</script>
    </head>
    <body>
    </body>
</html>

You can also download the entire project, but I would like to know how would you expand the gameplay and what’s your best score.

My best score is 17.

Get the most popular Phaser 3 book

Through 202 pages, 32 source code examples and an Android Studio project you will learn how to build cross platform HTML5 games and create a complete game along the way.

Get the book

214 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 100 rounds
// 10000000
// 2 Cars
// 2048
// A Blocky Christmas
// A Jumping Block
// A Life of Logic
// Angry Birds
// Angry Birds Space
// Artillery
// Astro-PANIC!
// Avoider
// Back to Square One
// Ball Game
// Ball vs Ball
// Ball: Revamped
// Balloon Invasion
// BallPusher
// Ballz
// Bar Balance
// Bejeweled
// Biggification
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Boom Dots
// Bouncing Ball
// Bouncing Ball 2
// Bouncy Light
// BoxHead
// Breakout
// Bricks
// Bubble Chaos
// Bubbles 2
// Card Game
// Castle Ramble
// Chronotron
// Circle Chain
// Circle Path
// Circle Race
// Circular endless runner
// Cirplosion
// CLOCKS - The Game
// Color Hit
// Color Jump
// ColorFill
// Columns
// Concentration
// Crossy Road
// Crush the Castle
// Cube Jump
// CubesOut
// Dash N Blast
// Dashy Panda
// Deflection
// Diamond Digger Saga
// Don't touch the spikes
// Dots
// Down The Mountain
// Drag and Match
// Draw Game
// Drop Wizard
// DROP'd
// Dudeski
// Dungeon Raid
// Educational Game
// Elasticity
// Endless Runner
// Erase Box
// Eskiv
// Farm Heroes Saga
// Filler
// Flappy Bird
// Fling
// Flipping Legend
// Floaty Light
// Fuse Ballz
// GearTaker
// Gem Sweeper
// Globe
// Goat Rider
// Gold Miner
// Grindstone
// GuessNext
// Helicopter
// Hero Emblems
// Hero Slide
// Hexagonal Tiles
// HookPod
// Hop Hop Hop Underwater
// Horizontal Endless Runner
// Hundreds
// Hungry Hero
// Hurry it's Christmas
// InkTd
// Iromeku
// Jet Set Willy
// Jigsaw Game
// Knife Hit
// Knightfall
// Legends of Runeterra
// Lep's World
// Line Rider
// Lumines
// Magick
// MagOrMin
// Mass Attack
// Math Game
// Maze
// Meeblings
// Memdot
// Metro Siberia Underground
// Mike Dangers
// Mikey Hooks
// Nano War
// Nodes
// o:anquan
// One Button Game
// One Tap RPG
// Ononmin
// Pacco
// Perfect Square!
// Perfectionism
// Phyballs
// Pixel Purge
// PixelField
// Planet Revenge
// Plants Vs Zombies
// Platform
// Platform game
// Plus+Plus
// Pocket Snap
// Poker
// Pool
// Pop the Lock
// Pop to Save
// Poux
// Pudi
// Pumpkin Story
// Puppet Bird
// Pyramids of Ra
// qomp
// Quick Switch
// Racing
// Radical
// Rebuild Chile
// Renju
// Rise Above
// Risky Road
// Roguelike
// Roly Poly
// Run Around
// Rush Hour
// SameGame
// SamePhysics
// Save the Totem
// Security
// Serious Scramblers
// Shrink it
// Sling
// Slingy
// Snowflakes
// Sokoban
// Space Checkers
// Space is Key
// Spellfall
// Spinny Gun
// Splitter
// Spring Ninja
// Sproing
// Stabilize!
// Stack
// Stick Hero
// String Avoider
// Stringy
// Sudoku
// Super Mario Bros
// Surfingers
// Survival Horror
// Talesworth Adventure
// Tetris
// The Impossible Line
// The Moops - Combos of Joy
// The Next Arrow
// Threes
// Tic Tac Toe
// Timberman
// Tiny Wings
// Tipsy Tower
// Toony
// Totem Destroyer
// Tower Defense
// Trick Shot
// Tunnelball
// Turn
// Turnellio
// TwinSpin
// vvvvvv
// Warp Shift
// Way of an Idea
// Whack a Creep
// Wheel of Fortune
// Where's my Water
// Wish Upon a Star
// Word Game
// Wordle
// Worms
// Yanga
// Yeah Bunny
// Zhed
// zNumbers