<!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 vychoziho rozliseni
cc.view.setDesignResolutionSize(320, 480, cc.ResolutionPolicy.SHOW_ALL);
// zvetsovani podle velikosti okna prohlizece
cc.view.resizeWithBrowserSize(true);
// 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);
// 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();
},
});
// 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();
},
// 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();
},
// 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 (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 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);
},
// zmacknuti skoku ctverce
onTouchesBegan:function (touches, event) {
this.velY = this.vel; // skok
this.dom.rectangle.setRotation(0); // rotace
}
// 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 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
}
},
// 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;
},
// 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);
},
// 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 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
}
},
// 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 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
},
// 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
}
},
// 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 hry
gameOver : function(){
// stopnuti tikani
this.unscheduleUpdate();
// odstraneni posluchace
cc.eventManager.removeListener(this.onTouchesBegan.bind(this));
// zviditelneni menu
this.dom.menuLayer.setVisible(true);
},
// 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 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));
},
// 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
},
Vypracoval Lukáš 'chleba' Franěk.