Flappy Bird & HTML5

Cocos2d & Flappy Bird

Example

Index.html

						
<!DOCTYPE html>
<html>
<head>
    <title>Flappy Bird Clone HTML5</title> 
    <script type="text/javascript" src="cocos2d-js-v3.2.js" charset="UTF-8"></script>
    <script type="text/javascript" src="resource.js" charset="UTF-8"></script>
</head>
<body>   
    <canvas id="gameCanvas" width="800" height="450"></canvas>
    <script type="text/javascript">
          window.onload = function(){
              cc.game.onStart = function(){
                  // nastaveni vychoziho rozliseni
                  cc.view.setDesignResolutionSize(320, 480, cc.ResolutionPolicy.SHOW_ALL);
                  // zvetsovani podle velikosti okna prohlizece
                  cc.view.resizeWithBrowserSize(true);
                  // nacteni obrazku - pote spusteni hry
                  cc.LoaderScene.preload(g_resources, function () {
                      cc.director.runScene(new FlappyScene());
                  }, this);
              };
              // predani vykreslovaciho canvasu
              cc.game.run("gameCanvas");
          };
    </script>
</body>
</html>
								
						

Nastaveni Rozliseni

							
	// nastaveni vychoziho rozliseni								
	cc.view.setDesignResolutionSize(320, 480, cc.ResolutionPolicy.SHOW_ALL);
	// zvetsovani podle velikosti okna prohlizece
	cc.view.resizeWithBrowserSize(true);
							
						

Nacteni Obrazku

							
				// soubor s polem obrazku
	<script type="text/javascript" src="resource.js" charset="UTF-8"></script>

          cc.LoaderScene.preload(g_resources, function () {
              cc.director.runScene(new FlappyScene());
          }, this);
							
						

Vytvoreni sceny


// nahodne cislo od-do
// @return int
Math.randRange = function(min, max){
    return Math.floor(Math.random() * (max - min + 1)) + min;
};

var FlappyScene = cc.Scene.extend({
    // volani po inicializaci
	onEnter:function () {
		this._super();
	},
});
						

Logika - čtverec

Example

Konstanty, priprava

							
    	// konstanty pro nastaveni hry
	gravity : 0.4, // gravitace padani
    	rot : 1.6, // rotace ctverce
    	vel : 7, // skok
    	velY : 0,
    	distance : 0,
    	obstacleRange : { f : 150, t : 200 }, // rozlozeni prekazek
    	nextObstacle : Math.randRange(200, 250), // vzdalenost dalsi prekazky
    	speed : 2, // rychlost posunu
    	score : 0, // body
    	gap : 125, // velikost diry v prekazce

    	// volani po inicializaci
	onEnter:function () {
		this._super();
		this.makeFlappy();
	},
							
						

Priprava


    // vytvoreni vseho
    makeFlappy : function(){
        	this.wSize = cc.director.getWinSize(); // velikost okna
        	this.dom = {}; // zasobnik pro nody
        	this.obstacles = []; // zasobnik pro prekazky

        	this.makeRectangle(); // vytvoreni ctverce
        	cc.eventManager.addListener({
            	event : cc.EventListener.TOUCH_ONE_BY_ONE,
            	onTouchBegan : this.onTouchesBegan.bind(this)
        	}, this);
        	this.scheduleUpdate();
    },					
						

Vytvoření čtverce

							
    // vytvoreni ctverce
    makeRectangle : function(){
        this.dom.rectangle = cc.Sprite.create('res/bird.png'); // obrazek
        this.dom.rectangle.setPosition(cc.p(this.wSize.width/3, this.wSize.height/2)); // pozice
        this.addChild(this.dom.rectangle, 4); // pridani potomka
    },

							
						

Update metoda

							

    // update metoda (scheduleUpdate)
    // @param CGTime dt cas tiku
    update : function(dt){
        // aplikace gravitace
        this.velY -= this.gravity;
        // ubehnuda vzdalenost
        this.distance += this.speed;
        
        // volani update metod pro jednotlive casti
        this.rectangleUpdate(dt);
    },

							
						

Update ctverce


    // update methoda pro ctverec
    rectangleUpdate : function(){
        var p = this.dom.rectangle.getPosition(); // pozice ctverce
        var newP = cc.p(p.x, p.y+this.velY); // nova pozice
        // kontrola vysky ctverce max / min
        newP.y = newP.y <= 0 ? 0 : newP.y; 
        newP.y = newP.y >= this.wSize.height ? this.wSize.height : newP.y;
        
        // rotace ctverce
        var rot = this.dom.rectangle.getRotation() + this.rot;
        rot = rot >= 90 ? 90 : rot;

        // nastaveni rotace a pozice
        this.dom.rectangle.setRotation(rot);
        this.dom.rectangle.setPosition(newP);
    },
						

Touch událost

							
    // zmacknuti skoku ctverce
    onTouchesBegan:function (touches, event) {
        this.velY = this.vel; // skok
        this.dom.rectangle.setRotation(0); // rotace
    }
							
						

Logika prekazek

Example

Vytvoření tuby

							
    // vytvareni prekazek
    // @param CGPoint pos
    makeObstacle : function(pos){
        // nahodna vyska prekazky
        var height = Math.randRange(180, this.wSize.height-200);
        // prekazka
        var obs = cc.Sprite.create('res/pipe.png');
        obs.tag = 0;
        obs.setAnchorPoint(cc.p(0, 1));
        obs.setPosition(cc.p(pos.x, height));

        // horni cast prekazky nad dirou
        var h = this.wSize.height-height-this.gap;
        var obs1 = cc.Sprite.create('res/pipe.png');
        obs1.setFlippedY(true); // otoceni obrazky
        obs1.tag = 0; // prozatimni  nepocitani bodu u prekazky
        obs1.setAnchorPoint(cc.p(0, 0));
        obs1.setPosition(cc.p(pos.x, this.wSize.height - h));

        // vlozeni do zasobniku
        this.obstacles.push(obs);
        this.obstacles.push(obs1);

        // vlozeni potomku
        this.addChild(obs, 2);
        this.addChild(obs1, 2);
    },
							
						

Update tuby

							
    // update metoda prekazek
    obstaclesUpdate : function(){
        var r = null; // prazdna prekazka pro odstraneni
        // prochazeni prekazek
        for(var i=0;i<this.obstacles.length;i++){
            var p = this.obstacles[i].getPosition(); // pozice prekazky
            var newP = cc.p(p.x - this.speed, p.y); // nova pozice prekazky pri tiku
            this.obstacles[i].setPosition(newP); // nastaveni pozice
            if(newP.x < this.obstacles[i].getBoundingBox().width * -1){ // jestlize je za okrajem
                this.obstacles[i].removeFromParent(); // odstraneni prekazky
                r = this.obstacles[i]; // oznaceni prekazky
            }
        }
        if(!!r){ // odstraneni prekazky ze zasobniku
            this.obstacles.splice(this.obstacles.indexOf(r), 1);
        }

        // jestlize je vzdalenost pro dalsi prekazku
        if(this.distance > this.nextObstacle){
            this.nextObstacle = Math.randRange(this.obstacleRange.f, this.obstacleRange.t); // nastaveni nova vzdalenosti prekazky
            this.distance = 0; // vynulovani vzdalenosti
            this.makeObstacle(cc.p(this.wSize.width, 0)); // vytvoreni nova prekazky
        }
    },
							
						

Nekonecne pozadi a zem

Example

Vytvoreni opkovaneho obrazku



    // vytvareni obrazku pro nekonecne pozadi
    // @return cc.Sprite
    makeInfiniteSprite : function(res){
        var s = cc.Sprite.create(res);
        s.setAnchorPoint(cc.p(0, 0)); // nastaveni kotvy
        return s;
    },
						

Vytvoreni pozadi


    // vytvareni pozadi
    makeBg : function(){
        var sprite = cc.Sprite.create('res/bg.png'); // vytvoreni obrazku pro ziskani velikosti
        this.dom.bg = []; // zasobnik pro pozadi
        // smycka pro vytvoreni obrazku pozadi pro zaplneni cele velikosti okna
        for(var i=0;i<Math.ceil(this.wSize.width / sprite.getBoundingBox().width); i++){
            var bg = this.makeInfiniteSprite('res/bg.png'); // obrazek
            bg.setPosition(cc.p((bg.getBoundingBox().width*i) - (i > 0 ? 5 : 0), 0)); // pozice
            this.addChild(bg, 1); // pridani potomka
            this.dom.bg.push(bg); // pridani do zasobniku
        }
        // posledni obrazek na konec
        var bg = this.makeInfiniteSprite('res/bg.png');
        bg.setPosition(cc.p((bg.getBoundingBox().width*i) - 5, 0));
        this.addChild(bg, 1);
        this.dom.bg.push(bg);
    },
						

Vytvoreni zeme


    // vytvareni zeme (to same co nekonecne pozadi)
    makeGround : function(){
        var sprite = cc.Sprite.create('res/ground.png');
        this.dom.ground = [];

        for(var i=0;i<Math.ceil(this.wSize.width / sprite.getBoundingBox().width); i++){
            var bg = this.makeInfiniteSprite('res/ground.png');
            bg.setPosition(cc.p((bg.getBoundingBox().width*i), 0));
            this.addChild(bg, 3);
            this.dom.ground.push(bg);
        }
        var bg = this.makeInfiniteSprite('res/ground.png');
        bg.setPosition(cc.p((bg.getBoundingBox().width*i), 0));
        this.addChild(bg, 3);
        this.dom.ground.push(bg);
    },
						

Update opakovani


    // update metoda pro nekonecne pozadi / zem
    // @param CGTime dt cas tiku
    // @param Array array pole pozadi / zemi
    // @param float speed rychlost pozadi / zeme
    infiniteUpdate : function(dt, array, speed){
        // nastaveni nove pozice
        for(var i=0;i<array.length;i++){
            var bg = array[i];
            var bp = bg.getPosition();
            bg.setPosition(cc.p(bp.x - speed, bp.y));
        }
        // kontrola nevideneho prvku pro posun na konec
        var bf = array[0];
        var bfp = bf.getPosition();
        if(bfp.x <= bf.getBoundingBox().width*-1){ // jestlize uz neni videt
            var sb = array.shift(); // odstranime ze zasobniku
            var lb = array[array.length-1]; // posledni prvek
            var p = cc.p((lb.getPosition().x + lb.getBoundingBox().width) - 5, lb.getPosition().y); // nova pozice pro presun prvniho na konec
            sb.setPosition(p);
            array.push(sb); // znovu vlozeni prvku na konec zasobniku
        }
    },
						

Pocitani bodu

Example

Vytvoreni ukazatele bodu


    // vtvoreni ukazatele bodu
    makeScore : function(){
        this.dom.score = cc.LabelTTF.create(String(this.score), 'Tahoma', 45); // label
        this.dom.score.setColor(cc.color(0, 0, 0)); // nastaveni barvy fontu
        this.dom.score.setPosition(cc.p(this.wSize.width/2, this.wSize.height - this.dom.score.getBoundingBox().height)); // pozice
        this.addChild(this.dom.score, 9); // pridani potomka
    },
						

Pridani pocitani


    // pridani bodu
    addScore : function(){
        // oznaceni nejblizsich prekazek pro pocitani bodu
        this.obstacles[0].tag = 1;
        this.obstacles[1].tag = 1;
        this.score += 1; // prdani bodu
        this.dom.score.setString(String(this.score)); // zobrazeni aktualni pocet bodu
    },
						

Uprava updatovani prekazek


    // update metoda prekazek
    obstaclesUpdate : function(){
        var r = null; // prazdna prekazka pro odstraneni
        // prochazeni prekazek
        for(var i=0;i<this.obstacles.length;i++){
            var p = this.obstacles[i].getPosition(); // pozice prekazky
            var newP = cc.p(p.x - this.speed, p.y); // nova pozice prekazky pri tiku
            this.obstacles[i].setPosition(newP); // nastaveni pozice
            if(newP.x < this.obstacles[i].getBoundingBox().width * -1){ // jestlize je za okrajem
                this.obstacles[i].removeFromParent(); // odstraneni prekazky
                r = this.obstacles[i]; // oznaceni prekazky
            }
        }
        if(!!r){ // odstraneni prekazky ze zasobniku
            this.obstacles.splice(this.obstacles.indexOf(r), 1);
        }

        // pridani bodu
        var op = this.obstacles[0].getPosition(); // pozice prekazky
        if(op.x <= this.dom.rectangle.getPosition().x){ // jestlize ctverec je dal nez prekazka
            if(this.obstacles[0].tag == 0 && this.obstacles[1].tag == 0){ // jeslize je prekazka oznacena jako jeste neobodovana
                this.addScore(); // pridani bodu
            }
        }

        // jestlize je vzdalenost pro dalsi prekazku
        if(this.distance > this.nextObstacle){
            this.nextObstacle = Math.randRange(this.obstacleRange.f, this.obstacleRange.t); // nastaveni nova vzdalenosti prekazky
            this.distance = 0; // vynulovani vzdalenosti
            this.makeObstacle(cc.p(this.wSize.width, 0)); // vytvoreni nova prekazky
        }
    },
						

Kolize, start a konec

Example

Uprava kolize


    // update metoda kolize s prekazkou
    collisionUpdate : function(){
        var status = false; // stav kolize
        var oRect, rRect = this.dom.rectangle.getBoundingBox(); // pozice & velikost ctverce
        // prochazeni vsech prekazek pro detekci kolize
        for(var i=0;i<this.obstacles.length;i++){
            oRect = this.obstacles[i].getBoundingBox(); // pozice & velikost prekazky
            if(cc.rectIntersectsRect(oRect, rRect)){ // je ctverec v prekazce ? 
                status = true; // stav kolize
                break;
            }
        }

        // kolize se zemi a hornik okrajem okna
        var rp = this.dom.rectangle.getPosition(); // pozice ctverce
        if(
            rp.y <= this.dom.ground[0].getBoundingBox().height || // horni okraj
            rp.y + this.dom.rectangle.getBoundingBox().height >= this.wSize.height // zem
        ){
            status = true; // stav kolize
        }

        // jestlize je stav kolize pravdivy - konec
        if(!!status){
            this.gameOver();
        }
    },
						

Konec


    // konec hry
    gameOver : function(){
        // stopnuti tikani
        this.unscheduleUpdate();
        // odstraneni posluchace
        cc.eventManager.removeListener(this.onTouchesBegan.bind(this));
        // zviditelneni menu
        this.dom.menuLayer.setVisible(true);
    },
						

Zacatek

							
    // start hry
    startGame : function(target, type){
    	if(type == ccui.Widget.TOUCH_ENDED){ // podminka po ukonceni doteku
	        this.resetGame();
            // nastaveni posluchace
	        cc.eventManager.addListener({
	        	event : cc.EventListener.TOUCH_ONE_BY_ONE,
	        	onTouchBegan : this.onTouchesBegan.bind(this)
	        }, this);
            // nastaveni tikaci metody 
	        this.scheduleUpdate();
	        this.dom.menuLayer.setVisible(false); // schovani menu
	    }
    },
						

Reset


    // reset hry
    resetGame : function(){
        // vynulovani ubehle vzdalenosti, bodu, vzdalenosti dalsi prekazky a skoku
        this.distance = 0;
        this.velY = 0;
        this.score = 0;
        this.nextObstacle = Math.randRange(this.obstacleRange.f, this.obstacleRange.t);
        // vynulovani ukazatele bodu
        this.dom.score.setString('0');
        // nsataveni vychozi pozice ctverce
        this.dom.rectangle.setPosition(cc.p(this.wSize.width/3, this.wSize.height/2));
        // odstraneni vsech prekazek
        for(var i=0;i<this.obstacles.length;i++){
            this.obstacles[i].removeFromParent();
        }
        this.obstacles = [];
        // vytvoreni prvni prekazky
        this.makeObstacle(cc.p(this.wSize.width, 0));
    },
						

Uprava MakeFlappy metody


    // vytvoreni vseho
    makeFlappy : function(){
        this.wSize = cc.director.getWinSize(); // velikost okna
        this.dom = {}; // zasobnik pro nody
        this.obstacles = []; // zasobnik pro prekazky

        this.makeScore(); // vytvoreni ukazatele bodu
        this.makeBg(); // vytvoreni pozadi
        this.makeGround(); // vytvoreni zeme
        this.makeRectangle(); // vytvoreni ctverce
        this.makeObstacle(cc.p(this.wSize.width, 0)); // vytvoreni dalsi prekazky
        this.makeMenu(); // vytvoreni menu
    },
						

Otazky?

Vypracoval Lukáš 'chleba' Franěk.