最近在做什么?很多兄弟可能想知道,放着Ideas和Ominds不做,blog也不更新,该有很多人在骂了吧。呵呵,其实,我也很迷茫很纠结,是啊,ideas到底该做成什么样?ominds又该如何,半个月以来一直没有停止过思考,完全没有任何想法,总觉的自己已经没有思想了,快死了吗?
还是做了个简单的东西,首先是我的个人简历(点击查看) 这个就不做过多介绍了,毕竟没有什么技术可言,只不过是一时兴起,也可到github上下载哦。。。
好了言归证转,想做点小游戏玩玩(当然不会说是因为缺钱啊),cocos2d-html5,为什么选中这个,其实,我也不知到,可能是最近在学前端吧,不过,想做的是cocosd-android,毕竟在地铁上是件无聊的事情。。。。。
再说这个连锁反应小游戏,不得不吐嘈一下cocos官网,你妹啊,给个入门教程都是过时的,还在那挂着。。。。这个小游戏是国外的一个教程,自己加了点东西,想要把它加工一下,还没有完成,你们懂的,对游戏,我是在是没什么经验,也不怎么玩。。。。。
那么。。。
一、环境搭建
- 开始吧,到官方下载cocos2d-html5包,我下的是v2.2.2,解压,如果你用的是eclipse,那么新建web项目,将cocos2d、extensions、external、lib、template、tools目录直接拷贝到webroot下,如果是nodejs开发(如果不知道如何使用nodejs点击),请将以上目录拷贝到public下。(开始我用的是eclipse+tomcat,不过发现js修改后,总是很不容易加载进去,这让我很伤心,后来又用nodejs+sublime(当然你也可以继续用eclips)
- 我们假设你已经搭建好了一个nodejs的项目,并且已经把cocos2d相关文件放在了public目录下(其实你用eclipse+tomcat,建立web project也是可以的,但是我不知道怎么部署到heroku上,有会的同学在下面留话),修改view/index.ejs文件,全部替换为:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>MyTest</title> </head> <body style="padding:0; margin: 0 auto; background: #fff;"> <div style="text-align: center; font-size: 0;margin-top:30px;"> <canvas id="gameCanvas" width="600" height="600"> Your browser does not support the canvas tag </canvas> </div> </body> </html> <script src="/app/cocos2d.js"></script>
var MW = MW || {}; (function () { var d = document; var c = { COCOS2D_DEBUG:2, //0 to turn debug off, 1 for basic debug, and 2 for full debug box2d:false, chipmunk: false, showFPS:false, frameRate:60, tag:‘gameCanvas‘, //the dom element to run cocos2d on engineDir:‘cocos2d/‘, appFiles:[‘app/Resource.js‘,‘app/GameConfig.js‘,‘app/MenuLayer.js‘,‘app/CircleChain.js‘, ‘app/AboutLayer.js‘,‘app/GameOver.js‘ ] }; window.addEventListener(‘DOMContentLoaded‘, function () { //first load engine file if specified var s = d.createElement(‘script‘); s.src = ‘cocos2d/jsloader.js‘; d.body.appendChild(s); document.ccConfig = c; s.id = ‘cocos2d-html5‘; }); })();
看一下代码,其中第一行先不说,tag:‘gameCanvas‘ 这句跟我们的html的div标签id一致,engineDir:‘cocos2d/‘这句表示我们使用的是cocos2d引擎,appFiles里面加载的是各个文件,等会一一说明。
在public(确实是public目录)目录下新建main.js,内容:
var cocos2dApp = cc.Application.extend({ config:document.ccConfig, ctor:function (scene) { this._super(); this.startScene = scene; cc.COCOS2D_DEBUG = this.config[‘COCOS2D_DEBUG‘]; cc.setup(this.config[‘tag‘]); cc.AppController.shareAppController().didFinishLaunchingWithOptions(); }, applicationDidFinishLaunching:function () { if(cc.RenderDoesnotSupport()){ //show Information to user alert("Browser doesn‘t support Canvas or WebGL"); return false; } // initialize director var director = cc.Director.getInstance(); cc.EGLView.getInstance().setDesignResolutionSize(480,800,cc.RESOLUTION_POLICY.SHOW_ALL); cc.EGLView.getInstance().resizeWithBrowserSize(true); director.setDisplayStats(this.config[‘showFPS‘]); // set FPS. the default value is 1.0/60 if you don‘t call this director.setAnimationInterval(1.0 / this.config[‘frameRate‘]); cc.LoaderScene.preload(g_mainmenu, function(){ director.replaceScene(new this.startScene()); }, this); return true; } }); var myApp = new cocos2dApp(SysMenu.scene);
里面的一些参数可以看看api(又不得不吐嘈一下这api,你妹,这是api吗?)
好,在app下,新建Resource.js,内容如下:
var res = { effect2_mp3 : ‘audio/effect2.mp3‘, effect2_ogg : ‘audio/effect2.ogg‘, background_mp3 : ‘audio/background.mp3‘, background_ogg : ‘audio/background.ogg‘, greenbullet_png : ‘res/greenbullet.png‘, greencircle_png : ‘res/greencircle.png‘, redbullet_png : ‘res/redbullet.png‘, redcircle_png : ‘res/redcircle.png‘, gameOver_png : ‘res/gameOver.png‘, menu_png : ‘res/menu.png‘, bg3_jpg:‘res/bg3.jpg‘, bg4_jpg:‘res/bg4.jpg‘, logo_png:‘res/logo.png‘, logo1_png:‘res/logo_1.png‘, logo2_png:‘res/logo_2.png‘, menuTitle_png:‘res/menuTitle.png‘ }; var g_mainmenu = [ {src:res.effect2_mp3}, {src:res.effect2_ogg}, {src:res.background_mp3}, {src:res.background_ogg}, {src:res.menu_png}, {src:res.bg4_jpg}, {src:res.logo_png}, {src:res.logo1_png}, {src:res.logo2_png}, {src:res.greencircle_png}, {src:res.menuTitle_png} ]; var g_maingame = [ //image {src:res.greenbullet_png}, {src:res.greencircle_png}, {src:res.redbullet_png}, {src:res.redcircle_png}, {src:res.gameOver_png} ];
这个文件主要是加载资源的,什么你已经知道了啊?????在public下,建立两个文件夹audio放置音频资源,res放置图片资源,由于blog,本教程的资源请到git下载
ok,在app下新建MenuLayer.js,内容:
cc.dumpConfig(); var SysMenu = cc.Layer.extend({ init:function () { var bRet = false; if (this._super()) { //var layer = cc.LayerColor.create(new cc.Color4B(0, 0, 0, 255), 600, 600); //background /*var sp = cc.Sprite.create(res.bg3_jpg); sp.setAnchorPoint(0,0); this.addChild(sp, 0, 1);*/ var circleSpeed = 2; winSize = cc.Director.getInstance().getWinSize(); var newGameNormal = cc.Sprite.create(res.menu_png, cc.rect(0, 0, 126, 33)); var newGameSelected = cc.Sprite.create(res.menu_png, cc.rect(0, 33, 126, 33)); var newGameDisabled = cc.Sprite.create(res.menu_png, cc.rect(0, 33 * 2, 126, 33)); var gameSettingsNormal = cc.Sprite.create(res.menu_png, cc.rect(126, 0, 126, 33)); var gameSettingsSelected = cc.Sprite.create(res.menu_png, cc.rect(126, 33, 126, 33)); var gameSettingsDisabled = cc.Sprite.create(res.menu_png, cc.rect(126, 33 * 2, 126, 33)); var aboutNormal = cc.Sprite.create(res.menu_png, cc.rect(252, 0, 126, 33)); var aboutSelected = cc.Sprite.create(res.menu_png, cc.rect(252, 33, 126, 33)); var aboutDisabled = cc.Sprite.create(res.menu_png, cc.rect(252, 33 * 2, 126, 33)); var newGame = cc.MenuItemSprite.create(newGameNormal, newGameSelected, newGameDisabled, function () { this.onButtonEffect(); this.onNewGame(); }.bind(this)); var gameSettings = cc.MenuItemSprite.create(gameSettingsNormal, gameSettingsSelected, gameSettingsDisabled, this.onSettings, this); var about = cc.MenuItemSprite.create(aboutNormal, aboutSelected, aboutDisabled, this.onAbout, this); //menu var menu = cc.Menu.create(newGame, gameSettings, about); menu.alignItemsVerticallyWithPadding(10); this.addChild(menu, 1, 2); menu.setPosition(winSize.width / 2, winSize.height / 2 - 80); //logo var logo = cc.Sprite.create(res.logo2_png); logo.setAnchorPoint(0, 0); logo.setPosition(winSize.width /2 - 160 ,winSize.height / 2 + 10); this.addChild(logo, 10, 1); this.schedule(this.update, 0.1); for(i=0;i<5;i++){ var greenCircle = cc.Sprite.create(res.greencircle_png); var randomDir = Math.random()*2*Math.PI; greenCircle.xSpeed=circleSpeed*Math.cos(randomDir); greenCircle.ySpeed=circleSpeed*Math.sin(randomDir); this.addChild(greenCircle); greenCircle.setPosition(new cc.Point(Math.random()*winSize.width,Math.random()*winSize.height)); greenCircle.schedule(function(){ this.setPosition(new cc.Point(this.getPosition().x+this.xSpeed,this.getPosition().y+this.ySpeed)); if(this.getPosition().x>winSize.width){ this.setPosition(new cc.Point(this.getPosition().x-winSize.width,this.getPosition().y)); } if(this.getPosition().x<0){ this.setPosition(new cc.Point(this.getPosition().x+winSize.width,this.getPosition().y)); } if(this.getPosition().y>winSize.height){ this.setPosition(new cc.Point(this.getPosition().x ,this.getPosition().y-winSize.height)); } if(this.getPosition().y<0){ this.setPosition(new cc.Point(this.getPosition().x ,this.getPosition().y+winSize.height)); } }) } if (MW.SOUND) { cc.AudioEngine.getInstance().setMusicVolume(0.7); cc.AudioEngine.getInstance().playMusic(res.background_mp3, true); } bRet = true; } return bRet; }, onNewGame:function (pSender) { //load resourcess cc.LoaderScene.preload(g_maingame, function () { var scene = cc.Scene.create(); scene.addChild(CircleChainGame.create()); //scene.addChild(GameControlMenu.create()); cc.Director.getInstance().replaceScene(cc.TransitionFade.create(1.2, scene)); }, this); }, onSettings:function (pSender) { this.onButtonEffect(); var scene = cc.Scene.create(); scene.addChild(SettingsLayer.create()); cc.Director.getInstance().replaceScene(cc.TransitionFade.create(1.2, scene)); }, onAbout:function (pSender) { this.onButtonEffect(); var scene = cc.Scene.create(); scene.addChild(AboutLayer.create()); cc.Director.getInstance().replaceScene(cc.TransitionFade.create(1.2, scene)); }, /* update:function () { if (this._ship.getPosition().y > 480) { var pos = cc.p(Math.random() * winSize.width, 10); this._ship.setPosition( pos ); this._ship.runAction( cc.MoveBy.create( parseInt(5 * Math.random(), 10), cc.p(Math.random() * winSize.width, pos.y + 480))); } },*/ onButtonEffect:function(){ if (MW.SOUND) { var s = cc.AudioEngine.getInstance().playEffect(res.effect2_mp3); } } }); SysMenu.create = function () { var sg = new SysMenu(); if (sg && sg.init()) { return sg; } return null; }; SysMenu.scene = function () { var scene = cc.Scene.create(); var layer = SysMenu.create(); console.log(layer); scene.addChild(layer); return scene; };
这里面的代码是我模仿官方的demo,唉,不说了,都是泪。。。。
新建GameConfig.js,内容:
//game state MW.GAME_STATE = { HOME:0, PLAY:1, OVER:2 }; //keys MW.KEYS = []; //level MW.LEVEL = { STAGE1:1, STAGE2:2, STAGE3:3 }; //life MW.LIFE = 4; //score MW.SCORE = 0; //sound MW.SOUND = true; //enemy move type MW.ENEMY_MOVE_TYPE = { ATTACK:0, VERTICAL:1, HORIZONTAL:2, OVERLAP:3 }; //delta x MW.DELTA_X = -100; //offset x MW.OFFSET_X = -24; //rot MW.ROT = -5.625; //bullet type MW.BULLET_TYPE = { PLAYER:1, ENEMY:2 }; //weapon type MW.WEAPON_TYPE = { ONE:1 }; //unit tag MW.UNIT_TAG = { ENMEY_BULLET:900, PLAYER_BULLET:901, ENEMY:1000, PLAYER:1000 }; //attack mode MW.ENEMY_ATTACK_MODE = { NORMAL:1, TSUIHIKIDAN:2 }; //life up sorce MW.LIFEUP_SORCE = [50000, 100000, 150000, 200000, 250000, 300000]; //container MW.CONTAINER = { ENEMIES:[], ENEMY_BULLETS:[], PLAYER_BULLETS:[], EXPLOSIONS:[], SPARKS:[], HITS:[], BACKSKYS:[], BACKTILEMAPS:[] }; //bullet speed MW.BULLET_SPEED = { ENEMY:-200, SHIP:900 }; // the counter of active enemies MW.ACTIVE_ENEMIES = 0; MW.DEFAULT_CIRCLE = 20;
也是直接从demo中copy的,我去了。。。。
新建CircleChain.js,内容:
var redCircle; var gameLayer; var bulletSpeed=5; var greenCircleArray=new Array(); var size ; var cnt = 0; var CircleChainGame = cc.Layer.extend({ init:function(){ cnt = 0; MW.SCORE = 0; var ret = false; this._super(); // set mouse click event on; this.setMouseEnabled(true); // the default ball‘s speed; var circleSpeed = 2; MW.SCORE = 0; cnt = 0; size= cc.Director.getInstance().getWinSize(); gameLayer = cc.LayerColor.create(new cc.Color4B(0, 0, 0, 255), size.width, size.height); greenCircleArray = new Array(); // give 10 ball‘s when begin; for(i=0;i<MW.DEFAULT_CIRCLE;i++){ var greenCircle = cc.Sprite.create("res/greencircle.png"); greenCircleArray.push(greenCircle); var randomDir = Math.random()*2*Math.PI; greenCircle.xSpeed=circleSpeed*Math.cos(randomDir); greenCircle.ySpeed=circleSpeed*Math.sin(randomDir); gameLayer.addChild(greenCircle); greenCircle.setPosition(new cc.Point(Math.random()*size.width,Math.random()*size.height)); greenCircle.schedule(function(){ this.setPosition(new cc.Point(this.getPosition().x+this.xSpeed,this.getPosition().y+this.ySpeed)); if(this.getPosition().x>size.width){ this.setPosition(new cc.Point(this.getPosition().x-size.width,this.getPosition().y)); } if(this.getPosition().x<0){ this.setPosition(new cc.Point(this.getPosition().x+size.width,this.getPosition().y)); } if(this.getPosition().y>size.height){ this.setPosition(new cc.Point(this.getPosition().x ,this.getPosition().y-size.height)); } if(this.getPosition().y<0){ this.setPosition(new cc.Point(this.getPosition().x ,this.getPosition().y+size.height)); } }) } console.log("Total:"+greenCircleArray.length); redCircle=cc.Sprite.create("res/redcircle.png"); gameLayer.addChild(redCircle); this.addChild(gameLayer); /*var itemStartGame = cc.MenuItemImage.create( "res/btnStartGameNor.png", "res/btnStartGameDown.png", this.menuCallBack, this ); itemStartGame.setPosition(size.width/2, 160); var menu = cc.Menu.create(itemStartGame); menu.setPosition(0,0); this.addChild(menu);*/ ret = true; return true; }, onMouseDown:function (event) { cnt++; /*if(cnt>2||greenCircleArray.length==0){ this.setMouseEnabled(false); MW.SCORE = 20 -greenCircleArray.length; this.runAction(cc.Sequence.create( cc.DelayTime.create(0.2), cc.CallFunc.create(this.onGameOver, this))); console.log(cnt); console.log(greenCircleArray.length); }*/ if(cnt>3||greenCircleArray.length==0){ this.setMouseEnabled(false); MW.SCORE = MW.DEFAULT_CIRCLE - greenCircleArray.length; this.runAction(cc.Sequence.create( cc.DelayTime.create(0.2), cc.CallFunc.create(this.onGameOver, this))); return; } var location = event.getLocation(); gameLayer.removeChild(this.redCircle); for(i=0;i<4;i++){ var redBullet = cc.Sprite.create("res/redbullet.png"); redBullet.xSpeed=bulletSpeed*Math.cos(i*Math.PI/2); redBullet.ySpeed=bulletSpeed*Math.sin(i*Math.PI/2); gameLayer.addChild(redBullet); redBullet.setPosition(location); redBullet.schedule(function(){ /*this.setPosition(new cc.Point(this.getPosition().x+this.xSpeed,this.getPosition().y+this.ySpeed)); if(this.getPosition().x>500 || this.getPosition().y>500 || this.getPosition().x<0 || this.getPosition().y<0){ gameLayer.removeChild(this); }*/ handleBullet(this); }) } }, onMouseMoved:function(event){ var location = event.getLocation(); redCircle.setPosition(location); }, menuCallBack:function(sender){ }, onGameOver:function () { var scene = cc.Scene.create(); scene.addChild(GameOver.create()); cc.Director.getInstance().replaceScene(cc.TransitionFade.create(1.2, scene)); } }); function handleBullet(bullet){ bullet.setPosition(new cc.Point(bullet.getPosition().x+bullet.xSpeed,bullet.getPosition().y+bullet.ySpeed)); if(bullet.getPosition().x>size.width || bullet.getPosition().y>size.height || bullet.getPosition().x<0 || bullet.getPosition().y<0){ gameLayer.removeChild(bullet); } for(i=greenCircleArray.length-1;i>=0;i--){ var distX=bullet.getPosition().x-greenCircleArray[i].getPosition().x; var distY=bullet.getPosition().y-greenCircleArray[i].getPosition().y; if(distX*distX+distY*distY<144){ gameLayer.removeChild(bullet); for(j=0;j<4;j++){ var greenBullet = cc.Sprite.create("res/greenbullet.png"); greenBullet.xSpeed=bulletSpeed*Math.cos(j*Math.PI/2); greenBullet.ySpeed=bulletSpeed*Math.sin(j*Math.PI/2); gameLayer.addChild(greenBullet); greenBullet.setPosition(new cc.Point(greenCircleArray[i].getPosition().x,greenCircleArray[i].getPosition().y)); greenBullet.schedule(function(){ handleBullet(this); }) } gameLayer.removeChild(greenCircleArray[i]); greenCircleArray.splice(i,1); console.log(i+"ii"); console.log(cnt); console.log(greenCircleArray.length); if(cnt>2||greenCircleArray.length==0){ return ; } } } }; /*var circleChainScene = cc.Scene.extend({ onEnter:function(){ this._super(); var layer = new circleChainGame(); layer.init(); this.addChild(layer); } });*/ CircleChainGame.create = function () { var sg = new CircleChainGame(); if (sg && sg.init()) { return sg; } return null; }; CircleChainGame.scene = function () { var scene = cc.Scene.create(); var layer = CircleChainGame.create(); scene.addChild(layer); return scene; };
恩,这个是我们主要的程序,简单的逻辑。。。。
新建AboutLayer.js,内容:
var AboutLayer = cc.Layer.extend({ init:function () { var bRet = false; if (this._super()) { /*var sp = cc.Sprite.create(res.loading_png); sp.setAnchorPoint(0,0); this.addChild(sp, 0, 1);*/ var cacheImage = cc.TextureCache.getInstance().addImage(res.menuTitle_png); var title = cc.Sprite.createWithTexture(cacheImage, cc.rect(0, 36, 100, 34)); title.setPosition( winSize.width / 2, winSize.height - 160 ); this.addChild(title); // There is a bug in LabelTTF native. Apparently it fails with some unicode chars. var about = cc.LabelTTF.create("Circle chain game create by jov.\n QQ:247911950 \n Email:jov123@163.com \n Git:", "Arial", 16, cc.size(winSize.width * 0.85, 320), cc.TEXT_ALIGNMENT_CENTER ); about.setPosition(winSize.width / 2, winSize.height/2 -20 ); about.setAnchorPoint(0.5, 0.5 ); this.addChild(about); var label = cc.LabelTTF.create("Go back", "Arial", 18); var back = cc.MenuItemLabel.create(label, this.onBackCallback); var menu = cc.Menu.create(back); menu.setPosition( winSize.width / 2, winSize.height/2 -100); this.addChild(menu); bRet = true; } return bRet; }, onBackCallback:function (pSender) { var scene = cc.Scene.create(); scene.addChild(SysMenu.create()); cc.Director.getInstance().replaceScene(cc.TransitionFade.create(1.2, scene)); } }); AboutLayer.create = function () { var sg = new AboutLayer(); if (sg && sg.init()) { return sg; } return null; };
新建GameOver.js,内容:
var GameOver = cc.Layer.extend({ //_ship:null, _lbScore:0, init:function () { var bRet = false; if (this._super()) { //var sp = cc.Sprite.create(res.loading_png); //sp.setAnchorPoint(0,0); //this.addChild(sp, 0, 1); var logo = cc.Sprite.create(res.gameOver_png); logo.setAnchorPoint(0,0); logo.setPosition(winSize.width / 2 -160,winSize.height/2); this.addChild(logo,10,1); var playAgainNormal = cc.Sprite.create(res.menu_png, cc.rect(378, 0, 126, 33)); var playAgainSelected = cc.Sprite.create(res.menu_png, cc.rect(378, 33, 126, 33)); var playAgainDisabled = cc.Sprite.create(res.menu_png, cc.rect(378, 33 * 2, 126, 33)); //var cocos2dhtml5 = cc.Sprite.create(res.cocos2d_html5_png); //cocos2dhtml5.setPosition(160,150); //this.addChild(cocos2dhtml5,10); //var flare = cc.Sprite.create(res.flare_jpg); //this.addChild(flare); //flare.setVisible(false); var playAgain = cc.MenuItemSprite.create(playAgainNormal, playAgainSelected, playAgainDisabled, function(){ this.onPlayAgain(); }.bind(this) ); var menu = cc.Menu.create(playAgain); this.addChild(menu, 1, 2); menu.setPosition(winSize.width / 2, winSize.height/2-100); var str = "Your Score:"+MW.SCORE; if(MW.SCORE>=15&&MW.SCORE<=17){ str +="\n\nGood!"; }else if(MW.SCORE>=18&&MW.SCORE<=19){ str +="\n\nGreat!" }else if(MW.SCORE==20){ str +="\n\nExcellent!"; }else{ str += "\n\n干八爹!" } var lbScore = cc.LabelTTF.create(str,"Arial Bold",16); lbScore.setPosition(winSize.width / 2,winSize.height/2-40); lbScore.setColor(cc.c3b(250,250,250)); this.addChild(lbScore,10); /* var b1 = cc.LabelTTF.create("Download Cocos2d-html5","Arial",14); var b2 = cc.LabelTTF.create("Download This Sample","Arial",14); var menu1 = cc.MenuItemLabel.create(b1,function(){ window.location.href = "http://www.cocos2d-x.org/projects/cocos2d-x/wiki/Cocos2d-html5"; }); var menu2 = cc.MenuItemLabel.create(b2,function(){ window.location.href = "https://github.com/ShengxiangChen/MoonWarriors"; }); var cocos2dMenu = cc.Menu.create(menu1,menu2); cocos2dMenu.alignItemsVerticallyWithPadding(10); cocos2dMenu.setPosition(160,80); this.addChild(cocos2dMenu);*/ if(MW.SOUND){ cc.AudioEngine.getInstance().playMusic(res.background_mp3); } bRet = true; } return bRet; }, onPlayAgain:function (pSender) { var scene = cc.Scene.create(); scene.addChild(CircleChainGame.create()); //scene.addChild(GameControlMenu.create()); cc.Director.getInstance().replaceScene(cc.TransitionFade.create(1.2,scene)); } }); GameOver.create = function () { var sg = new GameOver(); if (sg && sg.init()) { return sg; } return null; }; GameOver.scene = function () { var scene = cc.Scene.create(); var layer = GameOver.create(); scene.addChild(layer); return scene; };
恩,ok了,启动server,看看效果:
不管如何跑起来就行,恩,ok了,别忘了上传到heroku哦,好东西大家分享嘛,后面打算加一些关卡。。。
本示例演示地址:http://ogames.herokuapp.com/ 由于加载的东西比较多,可能有点慢,一定要等啊。。。。
github下载地址:https://github.com/joveth/games
QQ交流群:158325682