Speed Challenge-2 hours to complete HTML5 puzzle games __html

Source: Internet
Author: User
Tags addchild array sort event listener prepare

Beginner Lufylegend.js Day, I used lufylegend.js developed the first HTML5 games-jigsaw puzzles, but also wrote a Bovinlai show off: HTML5 small Game "puzzle" released to challenge your thinking storm. But at that time beginner game development, experience is shallow, so did not study the game in the algorithm and the code flaw, causes the game to appear many bugs, even after the puzzle is probably unable to recover. Recently, friends have often asked about the game, I hope I can change the bug in the code to facilitate beginners to learn, by the way I also intend to test their own writing the speed of this small game, so I took some time to write the game back to the beginning of the whole, calculated when, from the preparation, modify the material to the final completion of the game, It took about 2h of time altogether.

Here is the game address:

http://yuehaowang.github.io/games/puzzle/

This is my record of the game, welcome you to challenge:

Then let's talk about how to develop this game. (press "chronological") preparation Phase

Ready to Lufylegend game engine, you can go to the official website to download:

Lufylegend.com/lufylegend

Engine Document Address:

Lufylegend.com/lufylegend/api

It can be said, if there is no strong lufylegend engine, this kind of HTML5 games with native canvas production, less to say a day. 0~30min

Prepare material (10min) + Modify material (20min). Because in the next really hand residual, not good at the p figure, modify the picture used about 20min, embarrassed ... 30~50min

Development start interface. The game can not have a start interface, so we first implement this part of the code. Before this is the code in index.html, the code is as follows:

<! DOCTYPE html>

The main is to introduce some JS files, not much said. Then prepare a main.js file to add the initialization interface and the code to load the resource in this file:

/** Initialization Game * * Linit, "mygame", 390, 580, main);
var imgbmpd;
/** Game Layer * * var stagelayer, Gamelayer, Overlayer;
/** Puzzle Block List * * var blocklist;
/** whether the game is over/var isgameover;
/** time * * var starttime, time, timetxt;

/** Step Number * * var steps, Stepstxt;
    function Main () {/** full-screen setting */if (lglobal.mobile) {lglobal.stagescale = Lstagescalemode.show_all;

    } lglobal.screen (Lglobal.full_screen);
    /** ADD load Hint * * var loadinghint = new Ltextfield ();
    Loadinghint.text = "Resource loading ...";
    Loadinghint.size = 20;
    Loadinghint.x = (Lglobal.width-loadinghint.getwidth ())/2;
    Loadinghint.y = (Lglobal.height-loadinghint.getheight ())/2;

    AddChild (Loadinghint); /** Load Picture/lloadmanage.load ([{path:./js/block.js "}, {name:" img ", Path:"./ima Ges/img.jpg "}], NULL, function (result) {/** removal load hint * * Loadinghint.remov

            E (); /** save bitmap data to facilitate subsequent use/IMGBMPD = new Lbitmapdata (result["img"]);
        Gameinit ();
}
    );
    The function Gameinit (e) {/** Initialize the stage layer/Stagelayer = new Lsprite ();
    StageLayer.graphics.drawRect (0, "", [0, 0, Lglobal.width, Lglobal.height], True, "#EFEFEF");

    AddChild (Stagelayer);
    /** Initialization Game Layer * * Gamelayer = new Lsprite ();

    Stagelayer.addchild (Gamelayer);
    /** initialization of the top-level/Overlayer = new Lsprite ();

    Stagelayer.addchild (Overlayer);
/** Add Start Interface * * Addbeginningui (); }

The above code has detailed comments that you can read against the engine documentation and comments. Some global variables will be used in future code, and you can ignore them first. Next is the code in the Addbeginningui function, which implements the start interface:

function Addbeginningui () {
    var beginninglayer = new Lsprite ();
    BeginningLayer.graphics.drawRect (0, "", [0, 0, Lglobal.width, Lglobal.height], True, "#EDEDED");
    Stagelayer.addchild (Beginninglayer);

    /** Game title *
    /var title = new Ltextfield ();
    Title.text = "puzzle game";
    Title.size = m;
    Title.weight = "bold";
    title.x = (Lglobal.width-title.getwidth ())/2;
    Title.y = 160;
    Title.color = "#FFFFFF";
    Title.linewidth = 5;
    Title.linecolor = "#000000";
    Title.stroke = true;
    Beginninglayer.addchild (title);

    /** Start Game Tips * *
    var hint = new Ltextfield ();
    Hint.text = "-click on the screen to start the game-";
    Hint.size =;
    Hint.x = (Lglobal.width-hint.getwidth ())/2;
    Hint.y = 370;
    Beginninglayer.addchild (hint);

    /** Start Game * *
    beginninglayer.addeventlistener (lmouseevent.mouse_up, function () {
        beginninglayer.remove ();

        Startgame ();
    });

To this, run the code and get our start interface:

See this picture, in fact, I want to spit a slot is really too "simple", embarrassed ...

But this time I figure a production speed, so also hope you reader mass. 50~90min

This 40-minute time is the most critical period during which we are going to complete the main part of the game. First, we need to use code to implement the following procedures:

Initialize game interface data (such as game time, number of steps) and display some UI parts (such as drawings)
|
-> get a random puzzle block position
|
-> shows the puzzle pieces after the upset

We make these steps a function to facilitate our unified invocation:

function Startgame () {
    isgameover = false;

    /** initialization time and number of steps/
    StartTime = (new Date ()). GetTime ();
    Time = 0;
    steps = 0;
    /** Initialization Puzzle Block list *
    /Initblocklist ();
    /** Puzzles
    /getrandomblocklist ();
    /** Display Puzzle * *
    showblock ();
    /** Display thumbnail * *
    showthumbnail ();
    /** Display Time * *
    addtimetxt ();
    /** Show Step number * *
    addstepstxt ();

    Stagelayer.addeventlistener (Levent.enter_frame, onframe);
}

function at the beginning, we set the Isgameover variable to false to represent the game is not over, in the later code, we will see the role of this variable. We then initialized the two global variables, time and steps, which were used to represent times and steps, and the value of the initialization variable StartTime to calculate the game time later.
Next, we're going to start initializing the puzzle pieces. See the code in Initblocklist:

function Initblocklist () {
    blocklist = new Array ();

    for (var i = 0; i < 9; i++) {
        /** calculates the position of the puzzle piece according to the ordinal number * *
        var y = (I/3) >>> 0, x = i% 3;

        Blocklist.push (new block (i, x, y));
    }

Here we use a block class that displays the puzzle pieces and the data that stores the puzzle pieces, and provides some ways to manipulate the puzzle pieces, following is the code for its constructor:

function block (index, x, y) {
    lextends (this, lsprite, []);

    var bmpd = Imgbmpd.clone ();
    Bmpd.setproperties (x * 130, Y * 130, 130, 130);
    This.bmp = new Lbitmap (BMPD);
    This.addchild (this.bmp);

    var border = new Lshape ();
    Border.graphics.drawRect (3, "#CCCCCC", [0, 0, 130, 130]);
    This.addchild (border);

    This.index = index;

    This.addeventlistener (lmouseevent.mouse_up, This.onclick);
}

The Block class inherits from Lsprite and belongs to a display object, so we have added a bitmap object to the class to display the picture for the puzzle piece. In addition, we have added a border to the puzzle piece, which is used to separate the surrounding puzzle pieces when displayed. The Block class has an index property that represents the correct position of the puzzle piece in the puzzle block list blocklist. Finally, we added a mouse press event for this class to handle moving the tile after the mouse is pressed.

Next we will introduce a method of this class setlocation:

Block.prototype.setLocation = function (x, y) {
    this.locationx = x;
    This.locationy = y;

    this.x = x * 130;
    This.y = y * 130;
};

This method is used to set the display position of the puzzle piece object and to save the "array position" of the puzzle piece. What is "array position"? Your reader can be understood through the following pictures:

As you can see, "array position" is similar to the subscript of an element in a two-dimensional array. The function of storing this position is to easily get to the other nearby puzzle pieces from the blocklist. This method is called when we show the puzzle, before we show the puzzle, we have to break the puzzle and see the following code:

function Getrandomblocklist () {
    /** randomly disrupts jigsaw/
    blocklist.sort (function () {return
        0.5-math.random ();
    } );

    /** calculates reverse order and * *
    var reverseamount = 0;

    for (var i = 0, L = blocklist.length i < l; i++) {
        var currentblock = blocklist[i];

        for (var j = i + 1; j < L; j + +) {
            var comparedblock = blocklist[j];

            if (Comparedblock.index < Currentblock.index) {
                reverseamount++;
            }

    }} /** detection After the disruption can be reduced * * *
    (reverseamount% 2!= 0) {
        /** unqualified, again upset
        /getrandomblocklist ();
    }

Scrambling the puzzle part directly with the array sort method for random scrambling:

Blocklist.sort (function () {return
    0.5-math.random ();
});

In fact, there are many kinds of scrambling algorithms, I use the most brutal method, that is, random upset. This algorithm is simple and bad in the likelihood of irreversible phenomena. In response to this problem, there is a matching detection of whether the algorithm can be reduced, the specific algorithm theory I borrowed the lufy of the Great God's comments:

The key to this kind of game is to see if the sum of the number of reverse order is even when it is disturbed.
Suppose you scramble after each small tile in the array for Obj0,obj1,obj2, ... The serial number before they disturb is obj0.num,obj1.num ...
The next loop array, if the ordinal of the preceding element is larger than the ordinal of an element after this element, such as Obj0.num > Obj1.num or Obj2.num > Obj4.num represents a reverse order
when all of the sum of the reverse order is an odd number, it can not be restored, and then it is disturbed again, and then it is detected again until the sum of the reverse is even.

For example, if there is an array of [3, 4, 2, 1], then the inside 3 2, 3 1, 2 4, 4 1, 2 1 are in reverse order, so the reverse number is 5.

The code in the getrandomblocklist I gave above is the implementation of the scrambling algorithm and the detection of the reversible algorithm.

There is also a way to disrupt, you can try: As with the restoration puzzle, the blank block step-by-step with the surrounding puzzle random exchange order. This scrambling algorithm, in contrast to the previous one, does not appear to be irreversible, and can be based on the number of scrambled steps to set the game difficult.

After the puzzle piece is finished, the puzzle piece is displayed as scheduled:

function Showblock () {
    for (var i = 0, L = blocklist.length; i < L; i++) {
        var b = blocklist[i];

        /** calculates the puzzle block position according to the ordinal number * *
        var y = (I/3) >>> 0, x = i% 3;

        B.setlocation (x, y);

        Gamelayer.addchild (b);
    }

After displaying the puzzle pieces, all we have to do is add the ability to manipulate the puzzle pieces. You need to expand the block class to add an event listener OnClick method to it:

Block.prototype.onClick = function (e) {var self = e.currenttarget;
    if (isgameover) {return;

    var checklist = new Array (); /** to determine whether there is a square */if (Self.locationx > 0) {checklist.push (Block.getblock self.locationx-1, Self.locationy
    )); /** to determine whether there is a square/if (Self.locationx < 2) {Checklist.push (Block.getblock Self.locationx + 1, Self.lo
    Cationy)); /** determine if there is a square/if (Self.locationy > 0) {checklist.push (Block.getblock Self.locationx, Self.locati
    ONY-1)); /** to determine if there are squares/if (Self.locationy < 2) {Checklist.push (Block.getblock Self.locationx, Self.locati
    OnY + 1));

        for (var i = 0, L = checklist.length i < l; i++) {var Checko = checklist[i];
            /** to determine whether it is a blank puzzle block/if (Checko.index = = 8) {steps++;

            Updatestepstxt ();

            Block.exchangeposition (self, Checko);
        Break }
    }
};

First, here we see the role of the Isgameover global variable, that is, after the game is over, block the action after clicking the puzzle block.

After clicking on the puzzle piece, let's get the puzzle pieces around the puzzle pieces and load them into the checklist, then iterate over the checklist, and when you're judged to have a blank puzzle around it, that is, after the puzzle block with the Index property equal to 8, update the number of steps, and then swap the two puzzle blocks for the location. The specific Exchange puzzle block location method for the following code:

Block.exchangeposition = function (B1, b2) {
    var b1x = B1.locationx, b1y = b1.locationy,
        b2x = B2.locationx, b2y = B2.locationy,
        b1index = b1y * 3 + b1x,
        b2index = b2y * 3 + b2x;

    /** in the map block array to exchange both positions * *
    blocklist.splice (b1index, 1, B2);
    Blocklist.splice (B2index, 1, B1);

    /** Exchange both display position * *
    b1.setlocation (b2x, b2y);
    B2.setlocation (b1x, b1y);

    /** judge whether the game is over
    /block.isgameover ();

There is also the Block.getblock static method, which is used to get the puzzle piece under the given "array position":

Block.getblock = function (x, y) {return
    Blocklist[y * 3 + x];
};

In Block.exchangeposition, we determine by Block.isgameover whether the player has restored the puzzle:

Block.isgameover = function () {
    var reductionamount = 0, L = blocklist.length;

    /** calculates the degree of reduction
    /for (var i = 0; i < L; i++) {
        var b = blocklist[i];

        if (B.index = i) {
            reductionamount++
        }
    }

    /** calculate whether full restore
    /if (Reductionamount = = L) {
        /** game end * *
        gameover ();
    }   
;

Here, we realize the puzzle pieces and manipulate the parts. 90~120min

The last 30min is for minutiae processing, such as displaying puzzle thumbnails, displaying & updating time and steps, and adding game end images to the following lengthy and simple code:

function Showthumbnail () {var thumbnail = new Lbitmap (IMGBMPD);
    Thumbnail.scalex = 130/imgbmpd.width;
    Thumbnail.scaley = 130/imgbmpd.height;
    thumbnail.x = (lglobal.width-100)/2;
    THUMBNAIL.Y = 410;
Overlayer.addchild (thumbnail);
    function Addtimetxt () {timetxt = new Ltextfield ();
    Timetxt.stroke = true;
    Timetxt.linewidth = 3;
    Timetxt.linecolor = "#54D9EF";
    Timetxt.color = "#FFFFFF";
    Timetxt.size = 18;
    Timetxt.x = 20;
    Timetxt.y = 450;

    Overlayer.addchild (Timetxt);
Updatetimetxt ();

function Updatetimetxt () {timetxt.text = "time:" + gettimetxt (times);}

    function Gettimetxt () {var d = new Date (time);

return d.getminutes () + ":" + D.getseconds ();};
    function Addstepstxt () {stepstxt = new Ltextfield ();
    Stepstxt.stroke = true;
    Stepstxt.linewidth = 3;
    Stepstxt.linecolor = "#54D9EF";
    Stepstxt.color = "#FFFFFF";
    Stepstxt.size = 18;
    Stepstxt.y = 450; Overlayer.addchild (Stepstxt);
Updatestepstxt ();

    function Updatestepstxt () {stepstxt.text = "Step number:" + steps;
Stepstxt.x = Lglobal.width-stepstxt.getwidth ()-20;
    function Onframe () {if (isgameover) {return;

    /** Gets the current time/var currenttime = (new Date ()). GetTime ();
    /** calculate the time used and update the time display * * = Currenttime-starttime;
Updatetimetxt ();

    function Gameover () {isgameover = true;
    var resultlayer = new Lsprite ();
    Resultlayer.filters = [New Ldropshadowfilter ()];
    ResultLayer.graphics.drawRoundRect (3, "#BBBBBB", [0, 0, N,, 5], True, "#DDDDDD");
    Resultlayer.x = (Lglobal.width-resultlayer.getwidth ())/2;
    Resultlayer.y = LGLOBAL.HEIGHT/2;
    Resultlayer.alpha = 0;

    Overlayer.addchild (Resultlayer);
    var title = new Ltextfield ();
    Title.text = "game clearance" Title.weight = "bold";
    Title.stroke = true;
    Title.linewidth = 3;
    Title.linecolor = "#555555";
    Title.size = 30;
 Title.color = "#FFFFFF";   title.x = (Resultlayer.getwidth ()-title.getwidth ())/2;
    Title.y = 30;

    Resultlayer.addchild (title);
    var usedtimetxt = new Ltextfield ();
    Usedtimetxt.text = "game When:" + gettimetxt (time);
    Usedtimetxt.size = 20;
    Usedtimetxt.stroke = true;
    Usedtimetxt.linewidth = 2;
    Usedtimetxt.linecolor = "#555555";
    Usedtimetxt.color = "#FFFFFF";
    Usedtimetxt.x = (Resultlayer.getwidth ()-usedtimetxt.getwidth ())/2;
    Usedtimetxt.y = 130;

    Resultlayer.addchild (Usedtimetxt);
    var usedstepstxt = new Ltextfield ();
    Usedstepstxt.text = "The number of steps used:" + steps;
    Usedstepstxt.size = 20;
    Usedstepstxt.stroke = true;
    Usedstepstxt.linewidth = 2;
    Usedstepstxt.linecolor = "#555555";
    Usedstepstxt.color = "#FFFFFF";
    Usedstepstxt.x = Usedtimetxt.x;
    USEDSTEPSTXT.Y = 180;

    Resultlayer.addchild (Usedstepstxt);
    var hinttxt = new Ltextfield ();
    Hinttxt.text = "-click on the screen to start again-";
    Hinttxt.size = 23;
    Hinttxt.stroke = true; Hinttxt.linewiDTH = 2;
    Hinttxt.linecolor = "#888888";
    Hinttxt.color = "#FFFFFF";
    Hinttxt.x = (Resultlayer.getwidth ()-hinttxt.getwidth ())/2;
    Hinttxt.y = 260;

    Resultlayer.addchild (Hinttxt);
        Ltweenlite.to (Resultlayer, 0.5, {alpha:0.7, Y: (Lglobal.height-resultlayer.getheight ())/2, Oncomplete:function () {/** Click the interface to restart the game * * Stagelayer.addeventlistener (lmouseevent.mouse_up, Fu
                Nction () {gamelayer.removeallchild ();

                Overlayer.removeallchild ();

                Stagelayer.removealleventlistener ();
            Startgame ();
        });
}
    }); }

Ok,2h down, the whole game will be done slightly ~ had to praise Lufylegend this game engine, it is possible

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.