Cocos2d-html5入门之2048游戏
一、介绍
Cocos2d-JS是Cocos2d-x的Javascript版本,它的前身是Cocos2d-html5。在3.0版本以前叫做Cocos2d-html5,从3.0版本开始叫做Cocos2d-JS。我们知道Cocos2d-x支持使用C++、Lua、Javascript来进行程序开发,其所内置的是一个Javascript引擎,通过用C++解析Javascript去执行;而Cocos2d-html5是使用Javascript进行开发,最终运行在浏览器里的。那么在v3.0的时候,Cocos2d-html5和Cocos2d-x
JSBinding被合到了一起,称作Cocos2d-JS。
和Cocos2d-html5不同的是,Cocos2d-JS开发的程序不仅可以运行在浏览器里,还可以编译运行在Mac OSX, Windows, iOS, Android的原生平台上,真正做到“一次开发,全平台运行”。Cocos2d-JS支持Cocos2d-x的所有特性并提供更简单易用的Javascript风格API,它还自带了Cocos Console,一个用于简化项目创建和不同目标平台编译发布流程的终端工具。
二、Cocos2d-html5目录结构
为了快速入门,所以决定开发一个最近比较热门的2048小游戏。当然,首先需要去Cocos2d-x官网下载Cocos2d-html5-v2.2.3引擎,下载后解压就行了。Cocos2d-html5的目录结构如下:
- cocos2d:游戏引擎的主要文件
- extensions:包含一些扩展的功能,且支持自定义扩展
- external:包含box2d和chipmunk这两个物理引擎
- HelloHTML5World:一个最简单的HelloWorld项目
- samples:官网例子和几款小游戏
- template:项目模板
我们可以通过拷贝 HelloHTML5World 或 template中的项目模板,然后基于它编写自己的代码程序。
这里使用WebStorm作为IDE进行游戏开发,WebStorm有非常强大的智能补全功能,提高了开发效率。还能与 Google Chrome 浏览器配合,完成实时编辑和调试。只需要下载WebStorm然后载入引擎目录稍微配置一下就可以了,不知道怎么做的可以看看快速搭建 Cocos2d-HTML5 开发调试环境这篇博文。
三、2048游戏开发
1、创建项目
Cocos2d-html5中创建项目很简单,只需要拷贝HelloHTML5World项目(当然你也可以复制template下的文件夹),然后重命名就行了。
- res:资源文件夹(图片、音频等)
- src:js脚本存放目录(我们自己的项目源码目录)
- index.html:主页面
- build.xml:文件的引用,包括引擎库文件和自己写的文件
- cocos2d.js:定义了程序运行需要的一些参数,如 是否显示FPS,是否加载扩展库等
- main.js:定义程序的入口,初始化导演类等等。
我们需要在src文件夹里编写我们自己的代码,首先我们删除myApp.js中的所有代码,开始写我们自己的2048游戏。
2、创建游戏场景
由于2048游戏很简单,它只需要一个场景,下面我们来创建一个场景:
// 层
var Helloworld = cc.Layer.extend({
init:function () {
this._super();
return true;
}
}); // 场景
var HelloWorldScene = cc.Scene.extend({
onEnter:function () {
this._super();
var layer = new Helloworld();
layer.init();
this.addChild(layer);
}
});
很简单吧!我们只需要创建一个Layer类,然后将它的一个实例加入Scene中,程序运行时main.js会创建一个Scene的实例作为程序入口。
3、创建卡片类
我们把2048游戏中的每一个方格看作一个卡片,上面的数字是它的属性。也就是说我们需要4x4=16个卡片类的对象。新建一个CardSprite.js文件:
var CardSprite = cc.Layer.extend({
// 全局变量
number:0,
labelCardNumber:null,
cardColorBG:null,
// 构造函数
ctor:function()
{
this._super();
},
// 初始化卡牌
initCard:function(num, width, height, positionX, positionY)
{
this.number = num;
// 背景层,也就是一个小正方形
this.cardColorBG = cc.LayerColor.create(new cc.Color4B(200, 190, 180, 255), width-15, height-15);
this.cardColorBG.setPosition(positionX, positionY);
// 添加数字,大于0显示,否则不显示
if(this.number > 0)
{
this.labelCardNumber = cc.LabelTTF.create(this.number,"Arial", 60);
this.labelCardNumber.setPosition(this.cardColorBG.getContentSize().width/2, this.cardColorBG.getContentSize().height/2);
this.labelCardNumber.setTag(8);
this.cardColorBG.addChild(this.labelCardNumber);
}
else
{
this.labelCardNumber = cc.LabelTTF.create("","Arial", 60);
this.labelCardNumber.setPosition(this.cardColorBG.getContentSize().width/2, this.cardColorBG.getContentSize().height/2);
this.labelCardNumber.setTag(8);
this.cardColorBG.addChild(this.labelCardNumber);
}
this.addChild(this.cardColorBG);
},
// 获取数字
getNumber:function()
{
return this.number;
},
// 重置卡片数字
setNumber:function(num)
{
this.number = num;
if(this.number > 0)
{
this.labelCardNumber.setString(this.number);
}
else
{
this.labelCardNumber.setString("");
}
}
}); // 静态函数
CardSprite.createCardSprite = function(num, width, height, positionX, positionY)
{
var card = new CardSprite();
if(card)
{
card.initCard(num, width, height, positionX, positionY);
return card;
}
return null;
}
这里将CardSprite类继承自Layer,然后初始化卡片背景和上面的数字,还定义了number的set/get方法。这里需要注意几点:
- 新建.js文件以后需要在build.xml和cocos2d.js相关位置添加文件路径。
- 继承都需要有
this._super();
,一般写在构造函数ctor:function()
中。 - 注意静态函数的写法,
类名.函数名 = function(){}
。
4、初始化界面
下面我们来初始化游戏界面,主要是在Layer的init()函数中初始化,我们使用一个4x4的二维组来放置在主界面创建16个卡片:
var Helloworld = cc.Layer.extend({
cardArr:null, // 存放4x4=16个卡片
// 初始化
init:function () {
this._super();
var size = cc.Director.getInstance().getWinSize(); // 主界面背景层->设置颜色
var lazyLayer = cc.LayerColor.create(new cc.Color4B(180, 170, 160, 255) , null, null);
this.addChild(lazyLayer); // 创建卡片数组
this.cardArr = new Array(4);
for(var i=0; i<4; i++) {
this.cardArr[i] = new Array(4);
} // 初始化所有卡片,数字为0,不显示
this.createCards(size); // 开始的时候,随机生成两个数字
this.autoCreateCardNumber();
this.autoCreateCardNumber(); return true;
}, // 初始化卡片数组*******************************
createCards:function(size)
{
var unitSize = (size.height - 80)/4;
for(var i=0; i<4; i++) {
for(var j=0; j<4; j++) {
var card = CardSprite.createCardSprite(0, unitSize, unitSize, unitSize*i + 210, unitSize*j + 30);
this.cardArr[i][j] = card;
this.addChild(card);
}
}
}, // 随机生成新的2或4的卡片****************
autoCreateCardNumber:function()
{
while(1) {
var i = Math.floor(Math.random()*4); // 随机生成0~3
var j = Math.floor(Math.random()*4); if (this.cardArr[i][j].getNumber() == 0) {
// 4与2生成的概率比为1:9
this.cardArr[i][j].setNumber(Math.floor(Math.random()*10) < 1 ? 4 : 2);
break;
} if (!this.shouldCreateCardNumber()) {
break;
}
}
}, // 判断是否还有空位******************
shouldCreateCardNumber:function()
{
var should = false;
for(var i=0; i<4; ++i) {
for(var j=0; j<4; ++j) {
if (this.cardArr[i][j].getNumber() == 0) {
should = true;
break;
}
}
}
return should;
}
});
通过调用this.createCards(size);
初始化所有16个卡片,由于0不显示,所以卡片上都没有数字。然后调用this.autoCreateCardNumber();
在随机的两个卡片上生成数字,在随机生成的时候我们应该先判断还有没有空位,否则有可能会陷入死循环。
初始化的界面如下图:
5、定义手势动作
我们需要通过触摸滑动来操作游戏,所以就需要定义上下左右的手势动作。这就要用到引擎的触摸响应机制,Cocos2d-html5与Cocos2d-x一样,有多点触控 和单点触控。默认情况下是多点触控,要使用单点触控,我们要使用addTargetedDelegate()
方法设置代理。
那么如何判断上下左右呢?当然是根据起始触摸点和结束触摸点的坐标变化:
var Helloworld = cc.Layer.extend({
firstX:null,
firstY:null,
cardArr:null, init:function () {
this._super();
// 设置单点触摸
cc.Director.getInstance().getTouchDispatcher()._addTargetedDelegate(this, 0, true);
...
// 打开触摸
this.setTouchEnabled(true);
return true;
},
// onTouchBegan函数,需要返回true
onTouchBegan:function (touch, event) {
var touchPoint = touch.getLocation();
this.firstX = touchPoint.x;
this.firstY = touchPoint.y;
return true;
},
// onTouchEnded函数
onTouchEnded:function (touch, event) {
var touchPoint = touch.getLocation();
var offsetX = this.firstX - touchPoint.x;
var offsetY = this.firstY - touchPoint.y; if(Math.abs(offsetX) > Math.abs(offsetY)) {
if(offsetX > 5) {
this.doLeft();
//this.doCheckGameOver();
//this.setScore(this.score);
}
else if(offsetX < -5) {
this.doRight();
//this.doCheckGameOver();
//this.setScore(this.score);
}
}
else {
if(offsetY > 5) {
this.doDown();
//this.doCheckGameOver();
//this.setScore(this.score);
}
else if(offsetY < -5) {
this.doUp();
//this.doCheckGameOver();
//this.setScore(this.score);
}
}
},
// ...other methods
});
6、卡片合并
游戏2048主要玩法就是通过合并相同数字的卡片以达到2048。通过手势动作往一个方向进行合并。我们的思路就是根据手势方向,遍历每一行或每一列,将在这个方向上相邻(中间没有其他数字)且数字相同的卡片合并加倍。
// 向上***************************************
doUp:function(){
var isdo = false;
for (var x=0; x<4; ++x)
{
for (var y=3; y>=0; --y)
{
for (var y1=y-1; y1>=0; --y1)
{
if (this.cardArr[x][y1].getNumber() > 0)
{
if (this.cardArr[x][y].getNumber() <= 0)
{
this.cardArr[x][y].setNumber(this.cardArr[x][y1].getNumber());
this.cardArr[x][y1].setNumber(0);
++y;
isdo = true;
}
else if(this.cardArr[x][y].getNumber() == this.cardArr[x][y1].getNumber())
{
this.cardArr[x][y].setNumber(this.cardArr[x][y].getNumber()*2);
this.cardArr[x][y1].setNumber(0);
//this.score += this.cardArr[x][y].getNumber();
isdo = true;
}
break;
}
}
}
}
return isdo;
},
// 向下***************************************
doDown:function() {
var isdo = false;
for (var x=0; x<4; ++x)
{
for (var y=0; y<4; ++y)
{
for (var y1=y+1; y1<4; ++y1)
{
if (this.cardArr[x][y1].getNumber() > 0)
{
if (this.cardArr[x][y].getNumber() <= 0)
{
this.cardArr[x][y].setNumber(this.cardArr[x][y1].getNumber());
this.cardArr[x][y1].setNumber(0);
--y;
isdo = true;
}
else if(this.cardArr[x][y].getNumber() == this.cardArr[x][y1].getNumber())
{
this.cardArr[x][y].setNumber(this.cardArr[x][y].getNumber()*2);
this.cardArr[x][y1].setNumber(0);
//this.score += this.cardArr[x][y].getNumber();
isdo = true;
}
break;
}
}
}
}
return isdo;
},
// 向左***************************************
doLeft:function() {
var isdo = false;
for (var y=0; y<4; ++y)
{
for(var x=0; x<4; ++x)
{
for(var x1=x+1; x1<4; ++x1)
{
if(this.cardArr[x1][y].getNumber() > 0)
{
if(this.cardArr[x][y].getNumber() <= 0)
{
this.cardArr[x][y].setNumber(this.cardArr[x1][y].getNumber());
this.cardArr[x1][y].setNumber(0);
--x;
isdo = true;
}
else if(this.cardArr[x][y].getNumber() == this.cardArr[x1][y].getNumber())
{
this.cardArr[x][y].setNumber(this.cardArr[x][y].getNumber()*2);
this.cardArr[x1][y].setNumber(0);
//this.score += this.cardArr[x][y].getNumber();
isdo = true;
}
break;
}
}
}
}
return isdo;
},
// 向右***************************************
doRight:function() {
var isdo = false;
for (var y = 0; y < 4; ++y)
{
for (var x = 3; x >= 0; --x)
{
for (var x1 = x - 1; x1 >= 0; --x1)
{
if (this.cardArr[x1][y].getNumber() > 0)
{
if (this.cardArr[x][y].getNumber() <= 0)
{
this.cardArr[x][y].setNumber(this.cardArr[x1][y].getNumber());
this.cardArr[x1][y].setNumber(0);
++x;
isdo = true;
}else if(this.cardArr[x][y].getNumber() == this.cardArr[x1][y].getNumber())
{
this.cardArr[x][y].setNumber(this.cardArr[x][y].getNumber()*2);
this.cardArr[x1][y].setNumber(0);
//this.score += this.cardArr[x][y].getNumber();
isdo = true;
}
break;
}
}
}
}
return isdo;
}
7、添加分数
添加两个变量:
score:0, // 分数
scoreLabel:null, // 显示分数的控件
然后初始化分数显示:
// 显示分数
var label = cc.LabelTTF.create("Score : ", "Arial", 20);
label.setAnchorPoint(0,0);
label.setPosition(size.width/2 - 50, size.height-50);
this.addChild(label); this.scoreLabel = cc.LabelTTF.create("0", "Arial", 20);
this.scoreLabel.setAnchorPoint(0,0);
this.scoreLabel.setPosition(size.width/2 + 20, size.height-50);
this.addChild(this.scoreLabel);
卡片合并的时候要增加分数,然后更新分数显示:
// 更新分数 -> this.setScore(this.score);
setScore:function(s)
{
this.scoreLabel.setString(s);
}
8、判断游戏结束和胜利
每一次卡片合并操作后,我们都需要判断游戏是否胜利或者结束。利用五个条件判断游戏是否还能够继续:(1)还有空卡片 (2)还可以向右滑 (3)还可以向左滑 (4)还可以向上滑 (5)还可以向下滑。只要以上条件满足一个,游戏就可以再继续。否则,游戏不能再继续了。判断胜利则是看卡片中有没有数字达到2048。
// 判断游戏是否结束*******************************
doCheckGameOver:function()
{
var size = cc.Director.getInstance().getWinSize(); var isGameOver = true;
for(var y=0; y<4; ++y)
{
for(var x=0; x<4; ++x)
{
if(this.cardArr[x][y].getNumber() == 0 ||
(x>0&&(this.cardArr[x][y].getNumber() == this.cardArr[x-1][y].getNumber())) ||
(x<3&&(this.cardArr[x][y].getNumber() == this.cardArr[x+1][y].getNumber())) ||
(y>0&&(this.cardArr[x][y].getNumber() == this.cardArr[x][y-1].getNumber())) ||
(y<3&&(this.cardArr[x][y].getNumber() == this.cardArr[x][y+1].getNumber())))
{
isGameOver = false;
}
}
} if (isGameOver) { // if the game is over
console.log("The Game Is Over!");
cc.Director.getInstance().replaceScene(cc.TransitionFade.create(1, new HelloWorldScene()));
}
else {
if (this.shouldCreateCardNumber()) {
this.autoCreateCardNumber();
}
} if(this.isWin()) { // if win
cc.Director.getInstance().replaceScene(cc.TransitionFade.create(1, new HelloWorldScene()));
}
} // 判断是否胜利**********************
isWin:function() {
var Win = false;
for (var i=0; i<4; ++i) {
for(var j=0; j<4; ++j) {
if (this.cardArr[i][j].getNumber() == 2048) {
Win = true;
break;
}
}
}
return Win;
}
9、界面优化
在一个卡片里面,当数字变成两位数、三位数的时候,就需要调整一下数字的大小,在CardSprite的setNumber方法中添加代码:
// 设置数字大小
if(num >= 0)
{
this.labelCardNumber.setFontSize(60);
}
if(num >= 16)
{
this.labelCardNumber.setFontSize(55);
}
if(num >= 128)
{
this.labelCardNumber.setFontSize(40);
}
if(num >= 1024)
{
this.labelCardNumber.setFontSize(30)
}
我们还需要给不同的数字设置不同的卡片颜色,同样在setNumber方法中添加代码:
//判断数字的大小来调整颜色
if(this.number == 0){
this.cardColorBG.setColor(new cc.Color3B(200,190,180));
}
if (this.number == 2) {
this.cardColorBG.setColor(new cc.Color3B(240,230,220));
}
if (this.number == 4) {
this.cardColorBG.setColor(new cc.Color3B(240,220,200));
}
if (this.number == 8) {
this.cardColorBG.setColor(new cc.Color3B(240,180,120));
}
if (this.number == 16) {
this.cardColorBG.setColor(new cc.Color3B(240,140,90));
}
if (this.number == 32) {
this.cardColorBG.setColor(new cc.Color3B(240,120,90));
}
if (this.number == 64) {
this.cardColorBG.setColor(new cc.Color3B(240,90,60));
}
if (this.number == 128) {
this.cardColorBG.setColor(new cc.Color3B(240,90,60));
}
if (this.number == 256) {
this.cardColorBG.setColor(new cc.Color3B(240,200,70));
}
if (this.number == 512) {
this.cardColorBG.setColor(new cc.Color3B(240,200,70));
}
if (this.number == 1024) {
this.cardColorBG.setColor(new cc.Color3B(0,130,0));
}
if (this.number == 2048) {
this.cardColorBG.setColor(new cc.Color3B(0,130,0));
}
10、最终游戏截图
结语
采用Cocos2D-HTML5引擎进行游戏开发,开发效率更高,加上丰富的工具集支持、实时的各种调试手段和云合作开发手段,更加直接的效果调校方式,完全没有开发环境依赖,各种优势的叠加,可以大幅度降低开发成本,提升游戏的上架速度。
如果觉得这样还不够,我们可以使用Cocos2d-JS-v3.0,同一份JavaScript游戏代码不用修改或者小范围修改,配合Cocos2D-X JavaScript-Binding就能以Hybrid的方式直接作为本地应用发布,也可以编译到Android、iOS等移动平台。
通过Cocos2D-HTML5或Cocos2d-JS,开发者能以一个更快、更惬意的方式实现自己的想法。
参考:http://blog.csdn.net/column/details/love2048.html
Cocos2d-html5入门之2048游戏的更多相关文章
- 推荐10个适合初学者的 HTML5 入门教程
HTML5 作为下一代网站开发技术,无论你是一个 Web 开发人员或者想探索新的平台的游戏开发者,都值得去研究.借助尖端功能,技术和 API,HTML5 允许你创建响应性.创新性.互动性以及令人惊叹的 ...
- android 2048游戏、kotlin应用、跑马灯、动画源码
Android精选源码 2048游戏源码 android实现获取号码归属地和其他信息诈骗.骚扰 android kotlin仿开眼app源码 android多种reveal动画效果 android K ...
- 微信小程序开发(5) 2048游戏
在这篇微信小程序开发教程中,我们将介绍如何使用微信小程序开发2048小游戏. 本文主要分为两个部分,小程序主体部分及小游戏页面部分 一.小程序主体部分 一个小程序主体部分由三个文件组成,必须放在项目的 ...
- 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理
[微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...
- Cocos2d-x 3.x版2048游戏开发
Cocos2d-x 3.x版2048游戏开发 本篇博客给大家介绍怎样高速开发2048这样一款休闲游戏,理解整个2048游戏的开发流程.从本篇博客你将能够学习到下面内容: 这里注明一下,本教程来自极客学 ...
- 用javascript实现一个2048游戏
早就想自己写一个2048游戏了,昨晚闲着没事,终于写了一个 如下图,按方向键开始玩吧. 如果觉得操作不方便,请直接打开链接玩吧: http://gujianbo.1kapp.com/2048/2048 ...
- HTML5入门以及新标签
HTML5 学习总结(一)--HTML5入门与新增标签 目录 一.HTML5概要 1.1.为什么需要HTML5 1.2.什么是HTML5 1.3.HTML5现状及浏览器支持 1.4.HTML5特性 ...
- powershell字符界面的,powershell加WPF界面的,2048游戏
------[序言]------ 1 2048游戏,有段时间很火,我在地铁上看有人玩过.没错,坐地铁很无聊,人家玩我就一直盯着看. 2 我在电脑上找了一个,试玩了以下,没几次格子就满了.我就气呼呼的放 ...
- [python] python实现2048游戏,及代码解析。
我初学python,有不对之处望大家指教.转载请征得同意. 我在网络上也找了一些2048游戏代码的讲解,但都不是特别详细.所以我希望能够尽量详细的讲解.同时,有的地方我也不懂,希望大家能帮助补充.我会 ...
随机推荐
- cocos2dx在windows下搭建环境android报错
报错:Program bash is not found in PATH (如果按照我的方法来的话是没有这个错误的,我之前用别的方法的时候有但是后来还是没解决,写出来放到这里做参考吧) 参考原文: ...
- 【OptiX】第5个示例 递归反射、抗锯齿
运行结果如下: [抗锯齿] 可以看到中间那个竖线的右侧从地面上看有款明显的锯齿,而左边就没有.包括球的反射出来的三角形和地面也有明显的锯齿.那么抗锯齿究竟本例中是怎么做的呢? 首先在采样时,当场景需要 ...
- TCP端口状态LISTENING ESTABLISHED CLOSE_WAIT TIME_WAIT SYN_SENT
TCP状态转移要点 TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不 会被释放.网络服务器程序要同时管理 ...
- ThinkPHP---案例2--部门管理功能
[一]部门列表展示 分析: ①控制器DeptController.class.php ②方法showList(不要使用list方法,因为list是关键词) ③模板文件:showList.html 下面 ...
- TWaver HTML5之树形布局
转眼间春节假期已经过完,作为一个职业的程序猿,不知道大家有没有这样的感觉,一天不碰电脑,总觉得生活少点什么.今天是春节后上班的第三天,给大家分享一下我们前段时间的一个需求,需求是这样的:界面中的网元分 ...
- 这份Koa的简易Router手敲指南请收下
上一期链接--也就是本文的基础,参考KOA,5步手写一款粗糙的web框架 本文参考仓库:点我 Router其实就是路径匹配,通过匹配路径,返回给用户相应的网站内容. 以下方例子为例,主要通过提取req ...
- Humidex POJ - 3299 (数学)
题目大意 给定你三个变量中的两个输出剩下的那一个 题解 没有什么,就是把公式推出来即可,完全的数学题 代码 #include <iostream> #include <cmath&g ...
- Centos下Yum安装PHP5.5,5.6,7.0及扩展
默认的版本太低了,手动安装有一些麻烦,想采用Yum安装的可以使用下面的方案: 1.检查当前安装的PHP包 yum list installed | grep php 如果有安装的PHP包,先删除他们 ...
- Android写入到mysql里的中文总是乱码?
中文编码的问题总是让人头疼,之前在python爬虫就折腾得死去活来,现在写app又是这样. 总结下来,就是三点吧: 数据库: 确定字符编码是utf8, collate: utf8_general_ci ...
- python 读取指定文件信息并拼接
python 读取指定文本并拼接成指定的格式 # -*- coding: utf-8 -*- import os def getHelloWorld(path, fileName): "&q ...