📜 ⬆️ ⬇️

When the programmer has nothing to do, we write the games ourselves. Part 1

Recently, there was an article on Habré “When a programmer has nothing to do ...” , and here I have such a situation, but I do not just want to give a link to the Colored Lines , but tell me how to make it myself. Everyone who is interested in welcome under the cat

What am i talking about


This game, many people know, it is from distant childhood called "Colored Lines". To whom it is not known, I remember the rules of the game, balls of different colors are thrown on a square field, after each move, except when the balls are burned. It is necessary to move the balls to build lines of the same color horizontally, vertically or diagonally. At what move the balls can only be to the point to which they can pass. When lining up lines of 5 or more balls, they are destroyed.

Training


The page template for the game will be very simple, and contain two fields. One for the field of the game, the second to display the accumulated points. Cell fields will be generated using a script.
Index.html file
< html >
< head >
< meta HTTP-EQUIV ="Content-Type" CONTENT ="text/html; charset=utf-8" />
< title > ColorLines </ title >
< script type ="text/javascript" src ="jsfw.js" ></ script >
<script type= "text/javascript" src= "main.js" ></script>
<script type= "text/javascript" src= "lines.js" > </ script >
< link href ="style.css" rel ="stylesheet" type ="text/css" />
</ head >
< body >
< a href ="/" > </ a >
< h1 > - Color Lines </ h1 >
< table >
< tr >
< td >
< div class ="gamepole" >
< div id ="pole" >
</ div >
< div class ="gameOver" id ="gameover" style ="display:none" >
< div class ="bg" ></ div >
< div class ="block" >
< h4 > </ h4 >
</ div >
</ div >
</ div >
</ td >
< td class ="menu" >
< p > : < span id ="score" > 0 </ span ></ p >
< input type ="button" onclick ="game.start()" value =" " />
</ td >
</ tr >
</ table >
</ body >
</ html >


* This source code was highlighted with Source Code Highlighter .
< html >
< head >
< meta HTTP-EQUIV ="Content-Type" CONTENT ="text/html; charset=utf-8" />
< title > ColorLines </ title >
< script type ="text/javascript" src ="jsfw.js" ></ script >
<script type= "text/javascript" src= "main.js" ></script>
<script type= "text/javascript" src= "lines.js" > </ script >
< link href ="style.css" rel ="stylesheet" type ="text/css" />
</ head >
< body >
< a href ="/" > </ a >
< h1 > - Color Lines </ h1 >
< table >
< tr >
< td >
< div class ="gamepole" >
< div id ="pole" >
</ div >
< div class ="gameOver" id ="gameover" style ="display:none" >
< div class ="bg" ></ div >
< div class ="block" >
< h4 > </ h4 >
</ div >
</ div >
</ div >
</ td >
< td class ="menu" >
< p > : < span id ="score" > 0 </ span ></ p >
< input type ="button" onclick ="game.start()" value =" " />
</ td >
</ tr >
</ table >
</ body >
</ html >


* This source code was highlighted with Source Code Highlighter .
< html >
< head >
< meta HTTP-EQUIV ="Content-Type" CONTENT ="text/html; charset=utf-8" />
< title > ColorLines </ title >
< script type ="text/javascript" src ="jsfw.js" ></ script >
<script type= "text/javascript" src= "main.js" ></script>
<script type= "text/javascript" src= "lines.js" > </ script >
< link href ="style.css" rel ="stylesheet" type ="text/css" />
</ head >
< body >
< a href ="/" > </ a >
< h1 > - Color Lines </ h1 >
< table >
< tr >
< td >
< div class ="gamepole" >
< div id ="pole" >
</ div >
< div class ="gameOver" id ="gameover" style ="display:none" >
< div class ="bg" ></ div >
< div class ="block" >
< h4 > </ h4 >
</ div >
</ div >
</ div >
</ td >
< td class ="menu" >
< p > : < span id ="score" > 0 </ span ></ p >
< input type ="button" onclick ="game.start()" value =" " />
</ td >
</ tr >
</ table >
</ body >
</ html >


* This source code was highlighted with Source Code Highlighter .


File style.css
.gamepole {position:relative;}
.Pole {width:414px;}
.Cell {width:30px;height:30px;background:#333;float:left;margin:1px;color:#FFF}
.Ball {width:26px;height:26px;margin:2px;position:relative;}
.Ball1 {background:#F00;}
.Ball2 {background:#0F0;}
.Ball3 {background:#00F;}
.Ball4 {background:#0FF;}
.Ball5 {background:#F0F;}
.Ball6 {background:#FF0;}
.gameOver {position:absolute;top:0;left:0;width:384px;padding-top:75px;text-align:center;}
.gameOver .bg {z-index:1;position:absolute;top:0;left:0;width:384px;height:384px;background:#C78BA3; filter:alpha(opacity=60);-moz-opacity:.6;opacity:.6;}
.gameOver h4{font-size:30px;}
.gameOver .block{position:relative;z-index:2;background:#FFF;padding:30px;width:300px;margin:0 auto;}
td.menu {vertical-align:top;background:#333;color:#FFF;width:260px;padding:10px;}

Let's start


In the implementation, I use my js bike, which I don’t cite, of course, but I will comment on the functions that can be found in the source code. Ask why not jquery, prototype, and others, but because I feel so comfortable.
There will be only three classes in the game:
Game - the main class of the game
Cell - class cell
Ball - ball class

Create a main.js file that will create and link the game with the template.
jsfw.ready( function ()
{
game = new Game( 'pole' );
game.addEvent( 'onchangescore' , function (score){
$( 'score' ).innerHTML = score;
});
game.addEvent( 'onstart' , function (score){
$( 'gameover' ).style.display = 'none' ;
});
game.addEvent( 'ongameover' , function (score){
$( 'gameover' ).style.display = '' ;
});
game.start();
});


* This source code was highlighted with Source Code Highlighter .

The game will be built on the event system. So let's create a Game object and subscribe to its events. He will have only three of them:
onchangescore- account change;
onstart - the beginning of the game;
ongameover - the end of the game;
At the first, we will catch the change of accumulated points, and display them on the screen. With the other two we will hide or show a message about the end of the game.
')
I put the rest of the code in the lines.js file
Game class

var Game = jsfw.Class( function (){
/**

*/
function setScore(score)
{
this .score = score;
this .callEvent( 'onchangescore' ,[ this .score]); //
}
return {
width:12, //
height:12, //
speed:30, //
minline:5, //
countNewBall:3, //
costBall:1, //
costBonus:5, //
/**
*
* @param ID
*/
__constructor: function (el)
{
this .dom = $(el); //
this .score = 0; //
this .cell = []; //
/*
$d
*/
this .dSelectBall = $d( this , this .selectBall); //
this .dSelectCell = $d( this , this .selectCell);
this .countCell = this .width* this .height; //
},
/**
*
*/
start: function ()
{
setScore.call( this ,0); //
this .createCell(); //
this .callEvent( 'onstart' ); //
},
/**
*
*/
gameOver: function ()
{
//
this .callEvent( 'ongameover' );
},
/**
*
*/
createCell: function ()
{
/* */
}
}},
jsfw.Object //
)


* This source code was highlighted with Source Code Highlighter .

It seems to have described everything in the comments, I can only explain the function jsfw.Class (Object | Function, baseClass) implements inheritance and takes either the prototype of the object or the function that returns the prototype as the first parameter (To implement private methods). These are the main methods that are visible from the outside, you can even try to run :). The createCell method we implement after creating a cell class
Cell class

The cell will be able to only be able to contain the ball and react to it by clicking on it. We implement the methods of adding, deleting the ball and the onclick event.
var Cell = jsfw.Class({
__constructor: function (x,y)
{
//
this .x = x;
this .y = y;
/*
$.create DOM , , DOM
*/
this .dom = $.create( 'div' ,{
className: 'Cell' , //
onclick:$d( this , this .click) //
}, this .dom);
},
/**
*
* @param
*/
addBall: function (ball)
{
if (ball.cell) ball.cell.ball = null ; // ( )
this .ball = ball; //
ball.cell = this ; //
this .dom.appendChild(ball.getDom()); // DOM
},
/**
*
*/
removeBall: function ()
{
$.remove( this .ball.getDom()); // DOM
this .ball.cell = null ; //
this .ball = null ;
},
/**
*
*/
isBall: function ()
{
return !! this .ball;
},
/**
*
*/
getBall: function ()
{
return this .ball;
},
/**
* DOM
*/
getDom: function ()
{
return this .dom;
},
/**
*
*/
click: function ()
{
// onclick
return this .callEvent( 'onclick' );
}
},jsfw.Object);


* This source code was highlighted with Source Code Highlighter .

We already have the styles, the cells with the help of float: left and the hard task of the width and height of the cell and the container, just fold as we need. More than this class, we will not touch all that we need from him, he knows how. Now we realize the creation of cells. We just need to go through the whole field, create cells and add events to them. We have one dimensional array for storing cells. The location of the cell in the array will be calculated according to the formula x * this.width + y, for convenience, we will create a function getIndex (x, y) that will check whether the coordinates are in the specified range and, if not, return -1. Let's write functions for this and add them to the Game class.
/**
*
*/
createCell: function ()
{
$.empty( this .dom); // DOM
var p = $.create( 'div' ,{className: 'Pole' }); //
//
for ( var y=0,lenY= this .height;y<lenY;y++)
for ( var x=0,lenX= this .width;x<lenX;x++)
{
var cell = new Cell(x,y); //
cell.addEvent( 'onclick' , this .dSelectCell); // ,
p.appendChild(cell.getDom()); // DOM
this .cell[ this .getIndex(x,y)] = cell; // ,
}
this .dom.appendChild(p); // DOM
},
/**
*
*/
selectCell: function (cell)
{
alert( ' x=' +cell.x+ ' y=' +cell.y);
},
/**
*
* @param X
* @param Y
*/
getIndex: function (x,y)
{
return (x >= 0 && x < this .width && y>=0 && y< this .height)?x* this .width+y:-1;
}


* This source code was highlighted with Source Code Highlighter .

Now, if you have done everything as it should, then when you run the script, a nice mesh will appear :).
Ball class

The ball class we will only be able to respond to the onclick event and select ourselves by blinking. The ball itself will choose what color it is.
var Ball = jsfw.Class({
countColor:6, //
__constructor: function ()
{
this .color = c = Math.rand(1, this .countColor); // , .Ball{}
this .dom = $.create( 'div' ,{className: 'Ball Ball' + this .color,onclick:$d( this , this .click)}, this .dom); // DOM , onclick
},
/**
* DOM
*/
getDom: function ()
{
return this .dom;
},
/**
*
*/
click: function ()
{
return this .callEvent( 'onclick' );
},
/**
*
*/
select: function ()
{
// jsFW.fx.blink time
this .blink = jsFW.fx.blink( this .dom,{time:300}); //
},
/**
*
*/
unselect: function ()
{
if ( this .blink) //
{
this .blink.stop();
delete this .blink;
}
},
/**
* ,
*/
remove: function ()
{
if ( this .cell)
{
$.remove( this .dom);
this .cell.ball= null ;
this .cell = null ;
}
}
},jsfw.Object);


* This source code was highlighted with Source Code Highlighter .


Now you can add a few more methods to the Game class to create and add balls in a random free space.
/**
*
*/
addRandBall: function (ball)
{
/*
this.emptyCell
*/
var i = Math.rand(0, this .emptyCell.length-1); //
this .cell[ this .emptyCell[i]].addBall(ball); //
this .emptyCell.splice(i,1); // , ..
},
/**
*
*/
newBall: function (){
this .emptyCell = []; // , ,
for ( var i= this .cell.length;i--;)
{
if (! this .cell[i].isBall()) this .emptyCell.push(i); //
}
/*
this.countNewBall

*/
for ( var i=Math.min( this .countNewBall, this .emptyCell.length);i--;)
{
var ball = new Ball();
ball.addEvent( 'onclick' , this .dSelectBall); //
this .addRandBall(ball); //
}
//
if ( this .emptyCell.length<= this .countNewBall) this .gameOver();
},
/**
*
*/
selectBall: function (ball){
if ( this .seletedBall) this .seletedBall.unselect(); //
this .seletedBall = ball; //
ball.select();
return false ;
}


* This source code was highlighted with Source Code Highlighter .


You also need to add a newBall method call to the start function like this
start: function ()
{
setScore.call( this ,0); //
this .createCell(); //
this .newBall();
this .callEvent( 'onstart' ); //
},


* This source code was highlighted with Source Code Highlighter .


Let's change the selectCell cell selection function a little
selectCell: function (cell)
{
if (!cell.isBall() && this .seletedBall) //
{
cell.addBall( this .seletedBall); //
this .newBall();
}
return false ;
}


* This source code was highlighted with Source Code Highlighter .

Run and see what we did. Now we have a field on which balls fall out which can be made and moved to free places.

The article turned out great for this, I decided to split it into several parts.

Conclusion


We have prepared everything to take on the logic of the game, and this is the most interesting part of game programming. In the next part, we will look at the algorithm for checking the collected lines, counting the balls for the burnt balls. And the most interesting algorithm for finding the path, because our balls should not fly as they are now - we will cut their wings. > :)

Yes, I almost forgot the example and source for the first part

In the example, instead of balls, squares were used, since the balls were busy for unknown reasons.

Waiting for constructive criticism in the comments, and indications of spelling errors only in a personal

Source: https://habr.com/ru/post/49182/


All Articles