博主原来是做Kjava(J2ME)游戏,就是早期那种MOTO,NOKIA,三星智能机。240*320。对于游戏还是相当的爱好。今天无意中看到一篇关于cocos2dx-html5的游戏开发文章,于是就收藏下来。后面学习下也供大家学习。学好了这个,做游戏真的是跨平台了。只要你有浏览器,你就能玩!当然,运行效率一定要非常不错才可以。不然用户体验比较槽。 我也是第一次使用cocos2d_html5,对js和html5也不熟,看引擎自带的例子和引擎源码,边学边做,如果使用过cocos2d-x的话,完成这个游戏还是十分简单的。游戏体验地址: http://zhoujianghai.github.io/games/flappybird/
1. 首先去cocos2d-x官网下载Cocos2d-html5-v2.2.2(目前最新版本)压缩包
2. 下载安装WampServer(http://www.wampserver.com/en/),后期在浏览器运行程序的时候,需要用到wampserver。WampServer是一款由法国人开发的Apache Web服务器、PHP解释器以及MySQL数据库的整合软件包,本身也不大,才30多M。我这里安装到e盘,安装到最后会出现选择explorer的提示,定位到WINDOWS目录下explorer.exe或者其他自己安装的浏览器目录下的explorer.exe文件。安装好后启动,在桌面的右下角会有一个绿色图标。
3. 解压Cocos2d-html5-v2.2.2到E:\wamp\www目录下,此时打开浏览器,输入localhost,就可以看到下面的界面了,点击cocos2d_html5,就可以看到项目列表了:
4. 复制cocos2d_html5目录下的HelloHTML5World例子,命名为flappybird,这是引擎自带的Hello World demo。在引擎目录下创建projects目录,然后把flappybird放到projects目录下。修改引擎根目录下的index.html文件,在MoonWarriors下添加
flappybird - Game
刷新浏览器,会看到刚添加的flappybird了:
flappybird目录结构如下:
5. 开始编写游戏 src目录下有两个文件,myApp.js(游戏主要代码在这个文件里)和resource.js(定义游戏所使用的资源),由于这个游戏代码量比较少,就直接在这两个文件添加代码。 游戏有三个状态:READY、START、OVER。 READY表示游戏刚开始时显示logo,然后提示玩家点击开始游戏; START表示游戏进行中; OVER表示游戏结束,显示游戏结算界面。 游戏中出现的精灵有:小鸟、底部不停滚动的地面、背景图片、一直向左滚动的水管。其实小鸟在水平方向是一直不动的,只有水管和地面在滚动。 游戏中需要完成的主要功能点:小鸟自身的动画、点击屏幕时小鸟上升和下降的动画、小鸟死亡动画、地面滚动动画、水管滚动动画、添加水管、小鸟和地面及小鸟和水管的碰撞检测、游戏分数存储。
首先加载资源和添加游戏背景:
游戏资源使用TexturePacker打包在flappy_packer.plist文件中,函数名跟cocos2d-x c++版本是一样的。 初始化地面:
js可以使用proptotype来为类型添加行为,不理解的可以google一下。当然也可以跟init函数一样写在里面,像这样:
这里为地面定义两个动作,因为地面图片宽度是840px,而游戏屏幕分辨率指定是720×1280,所以先让地面向左移动120px,再迅速回到原位置。
初始化小鸟动画:
小鸟自身动画是一个帧动画,创建成功后添加到缓存中。
初始化ready界面,就是游戏开始的时候提示用户点击的画面:
效果如下:
这里自定义了一个自由落体的Action:FreeFall:
模仿了CCActionInterval.js中的其他内置的Action,如MoveBy,主要重写了initWithDuration,startWithTarget,update,isDone函数。 initWithDuration是设置该action运行的时间,时间的长短决定下降的速度。 startWithTarget函数由ActionManager调用,设置_target的值。 update函数在ActionInterval的step函数中会调用,在这个函数中不断更新精灵的坐标,使用了自由落体计算位移的公式。 isDone函数设置了动作是否运行结束。 重力加速度和action运行的时间需要不断调试。
添加水管:
分为上下两根水管,随机设置上下水管的高度,固定小鸟飞行区间的高度为300。然后把创建的水管放到数组中,同时每添加一排水管就增加一分。
添加碰撞检测函数:
采用最简单的方式:判断矩形是否相交。把小鸟分别跟地面和数组中的水管进行检测,如果发生碰撞,则执行小鸟死亡动画:
让小鸟旋转90度,然后垂直下落,然后显示game over画面:
显示game over时保存游戏数据,显示这局游戏的分数和历史最高分。
记得在init函数中清空水管数组:
下面是Helloworld类的代码:
在update函数中更新水管的位置,如果水管出了左边的屏幕就从数组中移除,每经过一定的时间就添加一排水管。 现在看看index.html的内容,在浏览器中访问的就是它:
在这个文件中指定了canvas的尺寸。html的内容从cocos2d-html5自带的例子中copy过来的,这里在底部添加了一个img,这个图片是分享到微信朋友圈时显示在左边的图片。 当浏览器窗口大小改变时,为了能自动调整显示游戏完整画面,需要在main.js的applicationDidFinishLaunching函数中添加:
还记得那个build.xml文件么,可以使用ant打包工具,把src目录下的js代码跟引擎代码打包成一个myApp-HelloWorld.js文件,这样我们只需要把res资源、cocos2d.js、index.html、myApp-HelloWorld.js放到网站上就可以了,也就更安全了。切换到项目build.xml所在目录,在命令符窗口执行:ant。很快就会生成myApp-HelloWorld.js文件,然后还需要修改cocos2d.js的window.addEventListener函数,修改s.src的值为myApp-HelloWorld.js,cocos2d.js文件里有详细注释的。
ok,flappy bird游戏的主要代码就完成了,感觉cocos2d-html5还是非常强大的,开发效率很高。
项目源码:flappybird
1. 首先去cocos2d-x官网下载Cocos2d-html5-v2.2.2(目前最新版本)压缩包
2. 下载安装WampServer(http://www.wampserver.com/en/),后期在浏览器运行程序的时候,需要用到wampserver。WampServer是一款由法国人开发的Apache Web服务器、PHP解释器以及MySQL数据库的整合软件包,本身也不大,才30多M。我这里安装到e盘,安装到最后会出现选择explorer的提示,定位到WINDOWS目录下explorer.exe或者其他自己安装的浏览器目录下的explorer.exe文件。安装好后启动,在桌面的右下角会有一个绿色图标。
3. 解压Cocos2d-html5-v2.2.2到E:\wamp\www目录下,此时打开浏览器,输入localhost,就可以看到下面的界面了,点击cocos2d_html5,就可以看到项目列表了:
4. 复制cocos2d_html5目录下的HelloHTML5World例子,命名为flappybird,这是引擎自带的Hello World demo。在引擎目录下创建projects目录,然后把flappybird放到projects目录下。修改引擎根目录下的index.html文件,在MoonWarriors下添加
刷新浏览器,会看到刚添加的flappybird了:
flappybird目录结构如下:
5. 开始编写游戏 src目录下有两个文件,myApp.js(游戏主要代码在这个文件里)和resource.js(定义游戏所使用的资源),由于这个游戏代码量比较少,就直接在这两个文件添加代码。 游戏有三个状态:READY、START、OVER。 READY表示游戏刚开始时显示logo,然后提示玩家点击开始游戏; START表示游戏进行中; OVER表示游戏结束,显示游戏结算界面。 游戏中出现的精灵有:小鸟、底部不停滚动的地面、背景图片、一直向左滚动的水管。其实小鸟在水平方向是一直不动的,只有水管和地面在滚动。 游戏中需要完成的主要功能点:小鸟自身的动画、点击屏幕时小鸟上升和下降的动画、小鸟死亡动画、地面滚动动画、水管滚动动画、添加水管、小鸟和地面及小鸟和水管的碰撞检测、游戏分数存储。
首先加载资源和添加游戏背景:
this.winSize = cc.Director.getInstance().getWinSize(); cc.SpriteFrameCache.getInstance().addSpriteFrames(res.flappy_packer); this.bgSprite = cc.Sprite.create(res.bg); this.bgSprite.setPosition(this.winSize.width / 2, this.winSize.height / 2); this.addChild(this.bgSprite, 0);
游戏资源使用TexturePacker打包在flappy_packer.plist文件中,函数名跟cocos2d-x c++版本是一样的。 初始化地面:
Helloworld.prototype.initGround = function() { //cc.log("initGround"); this.groundSprite = cc.Sprite.create(res.ground); var halfGroundW = this.groundSprite.getContentSize().width; var halfGroundH = this.groundSprite.getContentSize().height; this.groundSprite.setAnchorPoint(0.5, 0.5); this.groundSprite.setPosition(halfGroundW / 2, halfGroundH / 2); this.addChild(this.groundSprite, GROUND_Z); var action1 = cc.MoveTo.create(0.5, cc.p(halfGroundW / 2 - 120, this.groundSprite.getPositionY())); var action2 = cc.MoveTo.create(0, cc.p(halfGroundW / 2, this.groundSprite.getPositionY())); var action = cc.Sequence.create(action1, action2); this.groundSprite.runAction(cc.RepeatForever.create(action)); };
js可以使用proptotype来为类型添加行为,不理解的可以google一下。当然也可以跟init函数一样写在里面,像这样:
var Helloworld = cc.Layer.extend({ init:function () { }, initGround::function() { } );
这里为地面定义两个动作,因为地面图片宽度是840px,而游戏屏幕分辨率指定是720×1280,所以先让地面向左移动120px,再迅速回到原位置。
初始化小鸟动画:
Helloworld.prototype.initBird = function() { //cc.log("initBird"); var animation = cc.AnimationCache.getInstance().getAnimation("FlyBirdAnimation") if(!animation) { var animFrames = []; var str = ""; var birdFrameCount = 4; for (var i = 1; i < birdFrameCount; ++ i) { str = "bird" + i + ".png"; var frame = cc.SpriteFrameCache.getInstance().getSpriteFrame(str); animFrames.push(frame); } var animation = cc.Animation.create(animFrames, 0.05); cc.AnimationCache.getInstance().addAnimation(animation, "FlyBirdAnimation"); } this.flyBird = cc.Sprite.createWithSpriteFrameName(res.fly_bird); this.flyBird.setAnchorPoint(cc.p(0.5, 0.5)); this.flyBird.setPosition(this.winSize.width / 2, this.winSize.height / 2); this.addChild(this.flyBird, BIRD_Z); var actionFrame = cc.Animate.create(animation); var flyAction = cc.RepeatForever.create(actionFrame); this.flyBird.runAction(cc.RepeatForever.create(flyAction)); };
小鸟自身动画是一个帧动画,创建成功后添加到缓存中。
初始化ready界面,就是游戏开始的时候提示用户点击的画面:
Helloworld.prototype.initReady = function() { this.readyLayer = cc.Layer.create(); var logo = cc.Sprite.createWithSpriteFrameName(res.logo); logo.setAnchorPoint(cc.p(0.5, 0.5)); logo.setPosition(this.winSize.width / 2, this.winSize.height - logo.getContentSize().height - 50); this.readyLayer.addChild(logo); var getReady = cc.Sprite.createWithSpriteFrameName(res.getReady); getReady.setAnchorPoint(cc.p(0.5, 0.5)); getReady.setPosition(this.winSize.width / 2, this.winSize.height / 2 + getReady.getContentSize().height); this.readyLayer.addChild(getReady); var click = cc.Sprite.createWithSpriteFrameName(res.click); click.setAnchorPoint(cc.p(0.5, 0.5)); click.setPosition(this.winSize.width / 2, getReady.getPositionY() - getReady.getContentSize().height / 2 - click.getContentSize().height / 2); this.readyLayer.addChild(click); this.addChild(this.readyLayer); };
效果如下:
Helloworld.prototype.runBirdAction = function () { var riseHeight = 50; var birdX = this.flyBird.getPositionX(); var birdY = this.flyBird.getPositionY(); var bottomY = this.groundSprite.getContentSize().height - this.flyBird.getContentSize().height / 2; var actionFrame = cc.Animate.create(cc.AnimationCache.getInstance().getAnimation("FlyBirdAnimation")); var flyAction = cc.RepeatForever.create(actionFrame); //上升动画 var riseMoveAction = cc.MoveTo.create(0.2, cc.p(birdX, birdY + riseHeight)); var riseRotateAction = cc.RotateTo.create(0, -30); var riseAction = cc.Spawn.create(riseMoveAction, riseRotateAction); //下落动画 //模拟自由落体运动 var fallMoveAction = FreeFall.create(birdY - bottomY); var fallRotateAction =cc.RotateTo.create(0, 30); var fallAction = cc.Spawn.create(fallMoveAction, fallRotateAction); this.flyBird.stopAllActions(); this.flyBird.runAction(flyAction); this.flyBird.runAction(cc.Spawn.create( cc.Sequence.create(riseAction, fallAction) ) ); };
这里自定义了一个自由落体的Action:FreeFall:
var FreeFall = cc.ActionInterval.extend( { timeElasped:0, m_positionDeltaY:null, m_startPosition:null, m_targetPosition:null, ctor:function() { cc.ActionInterval.prototype.ctor.call(this); this.yOffsetElasped = 0; this.timeElasped = 0; this.m_positionDeltaY = 0; this.m_startPosition = cc.p(0, 0); this.m_targetPosition = cc.p(0, 0); }, initWithDuration:function (duration) { if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) { return true; } return false; }, initWithOffset:function(deltaPosition) { var dropTime = Math.sqrt(2.0*Math.abs(deltaPosition)/k_Acceleration) * 0.1; //cc.log("dropTime=" + dropTime); if (this.initWithDuration(dropTime)) { this.m_positionDeltaY = deltaPosition; return true; } //cc.log("dropTime =" + dropTime + "; deltaPosition=" + deltaPosition); return false; }, isDone:function() { if (this.m_targetPosition.y >= this._target.getPositionY()) { return true; } return false; }, //Node的runAction函数会调用ActionManager的addAction函数,在ActionManager的addAction函数中会调用Action的startWithTarget,然后在Action类的startWithTarget函数中设置_target的值。 startWithTarget:function(target) { //cc.log("startWithTarget target=" + target); cc.ActionInterval.prototype.startWithTarget.call(this, target); this.m_startPosition = target.getPosition(); this.m_targetPosition = cc.p(this.m_startPosition.x, this.m_startPosition.y - this.m_positionDeltaY); }, update:function(dt) { this.timeElasped += dt; //cc.log("isdone=" + this.timeElasped); if (this._target && !(this.m_targetPosition.y >= this._target.getPositionY())) { var yMoveOffset = 0.5 * k_Acceleration * this.timeElasped * this.timeElasped * 0.3; if (cc.ENABLE_STACKABLE_ACTIONS) { var newPos = cc.p(this.m_startPosition.x, this.m_startPosition.y - yMoveOffset); if (this.m_targetPosition.y > newPos.y) { newPos.y = this.m_targetPosition.y; this._target.stopAction(this); } this._target.setPosition(newPos); } else { this._target.setPosition(cc.p(this.m_startPosition.x, this.m_startPosition.y + this.m_positionDeltaY * dt)); } } } }); FreeFall.create = function(deltaPosition) { var ff = new FreeFall(); ff.initWithOffset(deltaPosition); return ff; };
模仿了CCActionInterval.js中的其他内置的Action,如MoveBy,主要重写了initWithDuration,startWithTarget,update,isDone函数。 initWithDuration是设置该action运行的时间,时间的长短决定下降的速度。 startWithTarget函数由ActionManager调用,设置_target的值。 update函数在ActionInterval的step函数中会调用,在这个函数中不断更新精灵的坐标,使用了自由落体计算位移的公式。 isDone函数设置了动作是否运行结束。 重力加速度和action运行的时间需要不断调试。
添加水管:
function getRandom(maxSize) { return Math.floor(Math.random() * maxSize) % maxSize; } Helloworld.prototype.addPipe = function () { cc.log("addPipe"); var ccSpriteDown = cc.Sprite.createWithSpriteFrameName(res.holdback1); var pipeHeight = ccSpriteDown.getContentSize().height; var pipeWidth = ccSpriteDown.getContentSize().width; var groundHeight = this.groundSprite.getContentSize().height; //小鸟飞行区间高度 var acrossHeight = 300; var downPipeHeight = 100 + getRandom(400); // cc.log("downPipeHeight=" + downPipeHeight); var upPipeHeight = this.winSize.height - downPipeHeight - acrossHeight - groundHeight; var PipeX = this.winSize.width + pipeWidth / 2; ccSpriteDown.setZOrder(1); ccSpriteDown.setAnchorPoint(cc.p(0.5, 0.5)); ccSpriteDown.setPosition(cc.p(PipeX + pipeWidth / 2, groundHeight + pipeHeight / 2 - (pipeHeight - downPipeHeight))); var ccSpriteUp = cc.Sprite.createWithSpriteFrameName(res.holdback2); ccSpriteUp.setZOrder(1); ccSpriteUp.setAnchorPoint(cc.p(0.5, 0.5)); ccSpriteUp.setPosition(cc.p(PipeX + pipeWidth / 2, this.winSize.height + (pipeHeight- upPipeHeight) - pipeHeight / 2)); this.addChild(ccSpriteDown, PIPE_Z); this.addChild(ccSpriteUp, PIPE_Z); this.PipeSpriteList.push(ccSpriteDown); this.PipeSpriteList.push(ccSpriteUp); this.score += 1; };
分为上下两根水管,随机设置上下水管的高度,固定小鸟飞行区间的高度为300。然后把创建的水管放到数组中,同时每添加一排水管就增加一分。
添加碰撞检测函数:
Helloworld.prototype.getRect = function(a) { var pos = a.getPosition(); var content = a.getContentSize(); return cc.rect(pos.x - content.width / 2, pos.y - content.height / 2, content.width, content.height); }; Helloworld.prototype.collide = function (a, b) { var aRect = this.getRect(a); var bRect = this.getRect(b); return cc.rectIntersectsRect(aRect, bRect); }; Helloworld.prototype.checkCollision = function () { if (this.collide(this.flyBird, this.groundSprite)) { //cc.log("hit floor"); this.birdFallAction(); return; } for (var i = 0; i < this.PipeSpriteList.length; i++) { var pipe = this.PipeSpriteList[i]; if (this.collide(this.flyBird, pipe)) { cc.log("hit pipe i=" + i); this.birdFallAction(); break; } } }
采用最简单的方式:判断矩形是否相交。把小鸟分别跟地面和数组中的水管进行检测,如果发生碰撞,则执行小鸟死亡动画:
Helloworld.prototype.birdFallAction = function () { this.gameMode = OVER; this.flyBird.stopAllActions(); this.groundSprite.stopAllActions(); var birdX = this.flyBird.getPositionX(); var birdY = this.flyBird.getPositionY(); var bottomY = this.groundSprite.getContentSize().height + this.flyBird.getContentSize().width / 2; var fallMoveAction = FreeFall.create(birdY - bottomY); var fallRotateAction =cc.RotateTo.create(0, 90); var fallAction = cc.Spawn.create(fallMoveAction, fallRotateAction); this.flyBird.runAction(cc.Sequence.create(cc.DelayTime.create(0.1), fallAction) ); this.runAction(cc.Sequence.create(cc.DelayTime.create(1.0), cc.CallFunc.create(this.showGameOver, this)) ); }
让小鸟旋转90度,然后垂直下落,然后显示game over画面:
Helloworld.prototype.showGameOver = function () { var userDefault = cc.UserDefault.getInstance(); var oldScore = userDefault.getIntegerForKey("score"); var maxScore = 0; if(this.score > oldScore) { maxScore = this.score; userDefault.setIntegerForKey("score", maxScore); }else { maxScore = oldScore; } var gameOverLayer = cc.Layer.create(); cc.log("gameover=" + res.gameover); var gameOver = cc.Sprite.createWithSpriteFrameName(res.gameover); gameOver.setAnchorPoint(cc.p(0.5, 0.5)); gameOver.setPosition(this.winSize.width / 2, this.winSize.height - gameOver.getContentSize().height / 2 - 150); gameOverLayer.addChild(gameOver); var scorePanel = cc.Sprite.createWithSpriteFrameName(res.scorePanel); scorePanel.setAnchorPoint(cc.p(0.5, 0.5)); scorePanel.setPosition(gameOver.getPositionX(), gameOver.getPositionY() - gameOver.getContentSize().height / 2 - scorePanel.getContentSize().height / 2 - 60); gameOverLayer.addChild(scorePanel); if(this.score > oldScore) { var gold = cc.Sprite.createWithSpriteFrameName(res.gold); gold.setAnchorPoint(cc.p(0.5, 0.5)); gold.setPosition(68 + gold.getContentSize().width / 2, 72 + gold.getContentSize().height / 2); scorePanel.addChild(gold); }else { var gray = cc.Sprite.createWithSpriteFrameName(res.gray); gray.setAnchorPoint(cc.p(0.5, 0.5)); gray.setPosition(68 + gray.getContentSize().width / 2, 72 + gray.getContentSize().height / 2); scorePanel.addChild(gray); } var newScoreLabel = cc.LabelAtlas.create(this.score, res.number, 22, 28, '0'); newScoreLabel.setAnchorPoint(cc.p(0.5, 0.5)); newScoreLabel.setScale(1.2); newScoreLabel.setPosition(scorePanel.getContentSize().width - newScoreLabel.getContentSize().width - 90, newScoreLabel.getContentSize().height / 2 + 180); scorePanel.addChild(newScoreLabel); var maxScoreLabel = cc.LabelAtlas.create(maxScore, res.number, 22, 28, '0'); maxScoreLabel.setAnchorPoint(cc.p(0.5, 0.5)); maxScoreLabel.setScale(1.2); maxScoreLabel.setPosition(newScoreLabel.getPositionX(), maxScoreLabel.getContentSize().height / 2 + 75); scorePanel.addChild(maxScoreLabel); var start = cc.Sprite.createWithSpriteFrameName(res.start); var startMenuItem = cc.MenuItemSprite.create(start, null, null, this.restartGame, this); var startMenu = cc.Menu.create(startMenuItem); startMenu.setAnchorPoint(cc.p(0.5, 0.5)); startMenu.setPosition(this.winSize.width / 2 , scorePanel.getPositionY() - scorePanel.getContentSize().height / 2 - start.getContentSize().height / 2 - 60); gameOverLayer.addChild(startMenu); this.addChild(gameOverLayer, GAMEOVER_Z); };
显示game over时保存游戏数据,显示这局游戏的分数和历史最高分。
Helloworld.prototype.restartGame = function() { var scene = cc.Scene.create(); scene.addChild(Helloworld.create()); cc.Director.getInstance().replaceScene(cc.TransitionFade.create(1.2, scene)); };
记得在init函数中清空水管数组:
this.PipeSpriteList = [];
下面是Helloworld类的代码:
var Helloworld = cc.Layer.extend({ gameMode:null, bgSprite:null, groundSprite:null, flyBird:null, PipeSpriteList:[], passTime: 0, winSize: 0, screenRect:null, readyLayer:null, score: 0, scoreLabel:null, init:function () { cc.log("helloworld init"); this._super(); this.PipeSpriteList = []; this.winSize = cc.Director.getInstance().getWinSize(); cc.SpriteFrameCache.getInstance().addSpriteFrames(res.flappy_packer); this.bgSprite = cc.Sprite.create(res.bg); this.bgSprite.setPosition(this.winSize.width / 2, this.winSize.height / 2); this.addChild(this.bgSprite, 0); this.initGround(); this.initReady(); this.screenRect = cc.rect(0, 0, this.winSize.width, this.winSize.height); this.gameMode = READY; this.score = 0; this.scheduleUpdate(); this.setTouchEnabled(true); return true; }, onTouchesBegan:function (touches, event) { }, onTouchesMoved:function (touches, event) { }, onTouchesEnded:function (touches, event) { if (this.gameMode == OVER) { return; } if (this.gameMode == READY) { this.gameMode = START; this.readyLayer.setVisible(false); this.initBird();; } this.runBirdAction(); }, onTouchesCancelled:function (touches, event) { }, update:function(dt) { if (this.gameMode != START) { return; } for(var i = 0; i < this.PipeSpriteList.length; ++ i) { var pipe = this.PipeSpriteList[i]; pipe.setPositionX(pipe.getPositionX() - 3); if (pipe.getPositionX() < -pipe.getContentSize().width / 2) { this.PipeSpriteList.splice(i, 1); //cc.log("delete pipe i=" + i); } } this.passTime += 1; if(this.passTime >= this.winSize.width / 6) { this.addPipe(); this.passTime = 0; } this.checkCollision(); } });
在update函数中更新水管的位置,如果水管出了左边的屏幕就从数组中移除,每经过一定的时间就添加一排水管。 现在看看index.html的内容,在浏览器中访问的就是它:
Flappy Bird-codingnow.cn
在这个文件中指定了canvas的尺寸。html的内容从cocos2d-html5自带的例子中copy过来的,这里在底部添加了一个img,这个图片是分享到微信朋友圈时显示在左边的图片。 当浏览器窗口大小改变时,为了能自动调整显示游戏完整画面,需要在main.js的applicationDidFinishLaunching函数中添加:
cc.EGLView.getInstance().adjustViewPort(true); cc.EGLView.getInstance().setDesignResolutionSize(720, 1280, cc.RESOLUTION_POLICY.SHOW_ALL); cc.EGLView.getInstance().resizeWithBrowserSize(true);
还记得那个build.xml文件么,可以使用ant打包工具,把src目录下的js代码跟引擎代码打包成一个myApp-HelloWorld.js文件,这样我们只需要把res资源、cocos2d.js、index.html、myApp-HelloWorld.js放到网站上就可以了,也就更安全了。切换到项目build.xml所在目录,在命令符窗口执行:ant。很快就会生成myApp-HelloWorld.js文件,然后还需要修改cocos2d.js的window.addEventListener函数,修改s.src的值为myApp-HelloWorld.js,cocos2d.js文件里有详细注释的。
ok,flappy bird游戏的主要代码就完成了,感觉cocos2d-html5还是非常强大的,开发效率很高。
项目源码:flappybird
收藏的用户(0) X
正在加载信息~
推荐阅读
C/C++获取系统,CPU,内存,硬盘,IP和MAC(windows和linux)
最新回复 (0)
站点信息
- 文章2305
- 用户1336
- 访客11455432
每日一句
Talent without working hard is nothing.
没有努力,天份不代表什么。
没有努力,天份不代表什么。
MySQL 数据库优化
This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its de
免ROOT实现模拟点击任意位置
Mobaxterm终端神器
CreateProcessW要注意的细节问题
Autonomous NAT Traversal
【教程】win10 彻底卸载edge浏览器
eclipse工程基于Xposed的一个简单Hook
排名前5的开源在线机器学习
Mac OS最简单及(Karabiner)快捷键设置
发一款C++编写的麻将
VMware NAT端口映射外网访问虚拟机linux
独家发布最新可用My-AutoPost——wordpress 采集器
新会员