Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about Farm Heroes Saga game, Game development, HTML5 and Javascript.

Here we are with the 3rd step of the Farm Heroes Saga creation using any language. A brief recap:

In step 1 I showed you the variable and constants to use to create the game field, while in step 2 we discussed about the functions to use in order to populate the game field.

Now it’s time to see some action, and we are going to draw the game field using two popular HTML5 game frameworks, Phaser and Panda.

We are doing this with mobile development in mind, so we will create a 320×480 game which scales to fit the browser area.

Here it is what we are going to do:

Phaser 320×480 game scaled to 360×540 Panda 320×480 game scaled to 360×540

Since all game logic functions have already been defined, let’s jump straight to source code and see the interesting lines of both versions. Just keep in mind we will need three more constants:

TILESIZE: size of the tile, in pixels. We assume tiles have their registration point in the upper left corner

OFFSETX: horizontal distance from the upper left corner to the upper left corner of the first tile, in pixels

OFFSETY: vertical distance from the upper left corner to the upper left corner of the first tile, in pixels

We aare using the offsets to place our tiles anywhere on the game field. You may say I could create a layer and just position the layer with all tiles inside, but working with single offsets should assure more cross-language compatibility.

Source codes now:

PHASER

Phaser version uses a single file for everything:

<!doctype html>
<html>
	<head>
    		<script src="phaser.min.js"></script>
    		<style>
    			body{margin:0}
    		</style>
    		<script type="text/javascript">
    		
			window.onload = function() {
			
				function rowNumber(i){
			     	return Math.floor(i/FIELDSIZE);
				}
				 
				function colNumber(i){
				     return i%FIELDSIZE;
				}
				 
				function isHorizontalMatch(i){
				     return colNumber(i)>=2 && gameArray[i]==gameArray[i-1] && gameArray[i] == gameArray[i-2] && rowNumber(i)==rowNumber(i-2);
				}
				 
				function isVerticalMatch(i){
				     return rowNumber(i)>=2 && gameArray[i]==gameArray[i-FIELDSIZE] && gameArray[i] == gameArray[i-2*FIELDSIZE];
				}
				
				function createLevel(){
					for(i=0;i<FIELDSIZE*FIELDSIZE;i++){
					     do{
					          gameArray[i]=Math.ceil(Math.random()*TILETYPES);
					     }while (isHorizontalMatch(i) || isVerticalMatch(i));
					} 
				}
				
				function drawLevel(){
					for(i=0;i<FIELDSIZE*FIELDSIZE;i++){
						var tile = gameArray[i];
						var item = game.add.sprite(i%FIELDSIZE*TILESIZE+OFFSETX,Math.floor(i/FIELDSIZE)*TILESIZE+OFFSETY,"tile"+tile);    
					}
				}
			
				var game = new Phaser.Game(320,480,Phaser.CANVAS,"",{
					preload:onPreload,
					create:onCreate,
					update:onUpdate
				});
				
				var FIELDSIZE = 8;
				var TILETYPES = 8;
				var TILESIZE = 36;
				var OFFSETX = 16;
				var OFFSETY = 50;
				var gameArray = new Array(FIELDSIZE*FIELDSIZE);
            		
				function onPreload() {
					for(i=1;i<=TILETYPES;i++){
						game.load.image("tile"+i, "tile_"+i+".png");
					}
					createLevel();
				}
				
				function onCreate() {
					drawLevel();
					game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
					game.scale.setScreenSize();
				}
				
				function onUpdate() {
	    			}
	    		};
		</script>
    </head>
    <body>
    </body>
</html>

Lines 36-41: function drawLevel, which places items on the stage

Lines 43-47: configuring the game, setting its resolution and the functions to be called. At the moment onUpdate does not do anything, but we’ll find it useful next time

Lines 57-59: loading graphic assets

Lines 65-66: setting game scale mode

PANDA

Panda needs to edit both config and game files.

config.js

pandaConfig = {
    system: {
        rotateImg: "rotate.png",
        bgColor: "#000000",
        orientation: "portrait",
        width: 320,
        height: 480,
        scaleToFit:true
    },
    loader: {
        logo: "data:image/png;base64,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",
        logoTween: true
    }
};

Lines 5-8: defining game resolution and scaling

main.js

game.module(
     "game.main"
)
.body(function() {

     function rowNumber(i){
     	return Math.floor(i/FIELDSIZE);
     }
      
     function colNumber(i){
          return i%FIELDSIZE;
     }
      
     function isHorizontalMatch(i){
          return colNumber(i)>=2 && gameArray[i]==gameArray[i-1] && gameArray[i] == gameArray[i-2] && rowNumber(i)==rowNumber(i-2);
     }
      
     function isVerticalMatch(i){
          return rowNumber(i)>=2 && gameArray[i]==gameArray[i-FIELDSIZE] && gameArray[i] == gameArray[i-2*FIELDSIZE];
     }
     
     function createLevel(){
     	for(i=0;i<FIELDSIZE*FIELDSIZE;i++){
     	     do{
     	          gameArray[i]=Math.ceil(Math.random()*TILETYPES);
     	     }while (isHorizontalMatch(i) || isVerticalMatch(i));
     	} 
     }
     
     function drawLevel(){
     	for(i=0;i<FIELDSIZE*FIELDSIZE;i++){
     		var tile = gameArray[i];
     		var item = new game.Sprite("tile"+tile);
               item.position.set(i%FIELDSIZE*TILESIZE+OFFSETX,Math.floor(i/FIELDSIZE)*TILESIZE+OFFSETY);
               game.scene.stage.addChild(item);                        
     	}                                  
     }

     var FIELDSIZE = 8;
     var TILETYPES = 8;
     var TILESIZE = 36;
     var OFFSETX = 16;
     var OFFSETY = 50;
     var gameArray = new Array(FIELDSIZE*FIELDSIZE);

     for(i=1;i<=TILETYPES;i++){
     	game.addAsset("tile_"+i+".png","tile"+i);
     }

     createLevel();

     SceneGame = game.Scene.extend({
          backgroundColor: 0x000000,
          init: function() {
               console.log(gameArray);
               drawLevel();
          }
     });
     game.start();
});

Lines 30-37: function drawLevel, which places items on the stage

Lines 46-48: loading graphic assets

The rest of both scripts are just plain JavaSCript functions I explained in step 2. Things will get interesting when we’ll start to add user interaction, selecting items to swap, but we’ll see it next time, meanwhile download the source code.

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.