【coco2d-html5简单游戏开发】一、连锁反应小游戏
最近在做什么?很多兄弟可能想知道,放着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文件,全部替换为:
MyTest
在public目录下新建app文件夹,在app下新建cocos2d.js,内容:
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 debugbox2d:false,chipmunk: false, showFPS:false,frameRate:60,tag:'gameCanvas', //the dom element to run cocos2d onengineDir:'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 specifiedvar 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 useralert("Browser doesn't support Canvas or WebGL");return false;}// initialize directorvar 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 thisdirector.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);//menuvar menu = cc.Menu.create(newGame, gameSettings, about);menu.alignItemsVerticallyWithPadding(10);this.addChild(menu, 1, 2);menu.setPosition(winSize.width / 2, winSize.height / 2 - 80);//logovar 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 resourcesscc.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;isize.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
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
