仿神经猫游戏制作教程
微信曾经火爆过一款名为《围住神经猫》的小游戏,其玩法简单,玩家需用最少的步数将一只神经兮兮的猫围死。在这篇教程中,我们将学习如何使用 Cocos2d - JS 实现一个类似神经猫的游戏。在本游戏中,神经猫换成了可爱的小羊驼。
游戏效果展示
你可以通过以下在线游戏地址体验最终完成的游戏:在线游戏
游戏分析
整个游戏主要由三个界面构成:
- 主界面:位于左边,展示游戏名称以及主角,让玩家对游戏的整体画风有一个大概的印象。
- 游戏界面:处于中间,玩家通过点击空格放置橙色六边形砖块来围堵小羊驼。
- 游戏结果界面:在右边,显示游戏成功或失败的状态。
游戏的主逻辑在游戏界面中完成,具体玩法如下:
- 游戏初始化:小羊驼始终站在地图中间,同时在地图的其他区域随机生成一些位置随机的砖块。
- 玩家操作:玩家点击一个空白区域,放置一个砖块来围堵羊驼。
- 羊驼移动:羊驼的 AI 进行寻路并移动一步。
- 循环操作:重复步骤 2 和 3,直到羊驼被围堵在一个圈里面(游戏成功),或者羊驼到达地图边界(游戏失败)。
理清了整个游戏的思路后,接下来我们进入编码阶段。
开发环境与新建项目
本教程基于当前最新的 Download v3.0RC1 进行开发。具体步骤如下:
- 下载引擎并解压到磁盘的某个目录。
- 打开控制台,输入以下命令来新建项目:
$ cd cocos2d-js-v3.0-rc1/tools/cocos2d-console/bin $ ./cocos new -l js --no-native $ cd MyJSGame/ $ ../cocos run -p web
主界面实现
游戏的入口代码在 main.js 中,使用编辑器打开并修改为以下代码:
cc.game.onStart = function() {
// 1. 设置浏览器 meta 来适配屏幕,引擎内部会根据屏幕大小来设置 meta 的 viewport 值,达到更好的屏幕适配效果
cc.view.adjustViewPort(true);
// 2. 针对手机浏览器和 PC 浏览器启用不同的分辨率适配策略
if (cc.sys.isMobile) {
cc.view.setDesignResolutionSize(320, 500, cc.ResolutionPolicy.FIXED_WIDTH);
} else {
cc.view.setDesignResolutionSize(320, 480, cc.ResolutionPolicy.SHOW_ALL);
}
cc.view.resizeWithBrowserSize(true);
// 3. 预加载图片声音等资源
cc.LoaderScene.preload(resources, function () {
// 4. 启动游戏的第一个场景
gameScene = new GameScene();
cc.director.runScene(gameScene);
}, this);
};
cc.game.run();
关键点解析
- 屏幕适配:设置浏览器
meta来适配屏幕,引擎内部会根据屏幕大小来设置meta的viewport值,从而达到更好的屏幕适配效果。 - 分辨率适配策略:针对手机浏览器和 PC 浏览器启用不同的分辨率适配策略。
- 资源预加载:预加载图片、声音等资源。
cc.LoaderScene.preload会生成一个“加载中 x%”的界面,等待资源加载结束后,调用第二个参数传入的匿名函数。对于基于 HTML 的游戏,页面是放在服务器端供浏览器下载的,为了获得流畅的用户体验,cc.LoaderScene.preload让浏览器先把远程服务器的资源缓存到本地。需要预加载的资源定义在src/Resources.js文件中。 - 启动场景:启动游戏的第一个场景。
主界面层次结构
主界面由两个层实现:
- GameLayer 层:游戏主逻辑层,在未初始化地图矩阵时,它只显示背景地图。
- StartUI 层:显示 logo 图片和开始游戏按钮。
GameScene 初始化代码
var GameScene = cc.Scene.extend({
onEnter : function () {
this._super();
var bg = new cc.Sprite(res.bg);
bg.attr({
anchorX : 0.5,
anchorY : 0.5,
x : cc.winSize.width / 2,
y : cc.winSize.height / 2
});
this.addChild(bg);
layers.game = new GameLayer();
this.addChild(layers.game);
layers.startUI = new StartUI();
this.addChild(layers.startUI);
layers.winUI = new ResultUI(true);
layers.loseUI = new ResultUI(false);
layers.shareUI = new ShareUI();
}
});
这里使用了引擎提供的 cc.Scene.extend 方法,让 JS 能实现高级面向对象语言的继承特性。onEnter 方法是场景初始化完成即将展示的消息回调,在 onEnter 中必须调用 this._super() 来确保 Scene 被正确初始化。整个游戏的设计只有一个 scene,界面之间的切换由 layer 来实现,全局变量 layers 存储了各层的一个实例。
StartUI 实现
var StartUI = cc.Layer.extend({
ctor : function () {
this._super();
var start = new cc.Sprite(res.start);
start.x = cc.winSize.width / 2;
start.y = cc.winSize.height / 2 + 20;
this.addChild(start);
},
onEnter : function () {
this._super();
cc.eventManager.addListener({
event: cc.EventListener.TOUCH_ALL_AT_ONCE,
onTouchesEnded: function (touches, event) {
var touch = touches[0];
var pos = touch.getLocation();
if (pos.y < cc.winSize.height / 3) {
layers.game.initGame();
layers.startUI.removeFromParent();
}
}
}, this);
}
});
cc.Layer.extend 的作用与 cc.Scene.extend 类似,只不过一个扩展 Scene,一个扩展 Layer。ctor 是 Cocos2d - JS 中的构造函数,在 ctor 中必须调用 this._super() 以确保正确初始化。在 onEnter 中,我们为 StartUI 层绑定事件监听,通过判断触摸点的位置坐标来触发 scene 切换。这里不使用 Menu 控件的原因是,当前的 Cocos2d - JS 版本已实现模块化,可以选择只加载游戏中用到的模块,以减少最终打包的大小,所以使用了最简单的触摸点坐标判断来实现相同的功能。
游戏界面的实现
橙色块的初始化
游戏地图区域由 9 * 9 的六边形方块组成,首先使用 InActive 的图片初始化一个矩阵,相关代码如下:
var ox = x = y = 0, odd = false, block, tex = this.batch.texture;
for (var r = 0; r < ROW; r++) {
y = BLOCK_YREGION * r;
ox = odd * OFFSET_ODD;
for (var c = 0; c < COL; c++) {
x = ox + BLOCK_XREGION * c;
block = new cc.Sprite(tex, BLOCK2_RECT);
block.attr({
anchorX : 0,
anchorY : 0,
x : x,
y : y,
width : BLOCK_W,
height : BLOCK_H
});
this.batch.addChild(block);
}
odd = !odd;
}
每次循环 odd 的值会改变,以此实现上下错位的排布。attr 是 Node 基类的新方法,可以方便地一次性设置多个属性。
橙色方块的初始化由 initGame 函数完成,下面是 initGame 的实现代码(此处原文档代码未完整给出,需补充完整后才能准确展示)。
通过以上步骤,我们就可以逐步实现一个仿神经猫的游戏。在实际开发过程中,还需要根据具体需求对代码进行进一步的优化和完善。