一張圖告訴你2048有多火
小3的悲劇 在每個階段手機裡面都會有一兩款讓人愛不釋手的遊戲存在,無論是在公車上、床鋪上、馬桶上還是在睡覺前、吃飯前、總會有讓你拿出手機開啟它的慾望。大部分人被Flappy bird給蹂躪的體無完膚,生活不能自理。在這危難降臨的時刻,一款名為小3傳奇的數字益智遊戲出現在我們的視野中,遊戲既簡單又複雜,既單一又千變萬化,簡直就讓人停不下來! 但故事的發展是這樣的,小3傳奇的兩位開發人員花了近一年半時間才開發出這個遊戲的核心玩法,卻在其上架appstore後僅21天就被《1024》抄了過去。而《2048》則更為迅速,19歲的Gabriele Cirulli只用了一個星期改編前兩者遊戲,卻獲得最大的成功,而小3卻不被人知 ;這類遊戲從發布到現在,不管是app store還是android市場,下載量已經遠遠超越了千萬,網上各種版本的都有;
CocosEditor開源版
筆者曆時一個晚上,終於完成了cocos2d-js開源版本,編碼雖易,創意不易,且行且珍惜;
此版本包含了網上流行的各種版本。包括原版,朝代版,金庸版,星座,豪車等等近10個版本,代碼開源,希望讀者基於開原始碼做出各種版本,供全名娛樂;
運行demo需要配置好CocosEditor,暫不支援其他工具。demo是跨平台的,可移植運行android,ios,html5網頁等,代碼是基於javascript語言,cocos2d-x遊戲引擎,CocosEditor手遊開發工具完成的。
本文共兩篇,第一篇分析原版,第二篇分析各種版本,本代碼僅供參考,有更好的實現方法可以評論中探討;
發行上線apk示範效果
幾個小時開發,一天審核上線,這就是CocosEditor開發遊戲的速度
360應用市場(2048 彙總版):http://zhushou.360.cn/detail/index/soft_id/1634607?recrefer=SE_D_2048%20%E8%81%9A%E5%90%88
CocosEditor版原始碼下載:
cocos2d-js原始碼請到集中營下載:http://blog.makeapp.co/?p=523
github版本管理:https://github.com/makeapp/cocoseditor-2048
Github裡面大牛提供了各種語言的版本
包括(java ,css,shell,python,objective-c等等),讀者可自行下載https://github.com/search?q=2048&ref=cmdform
不同平台下的:
windows
html5網頁
android平台(各種主題版本)
程式碼分析:
1初始化;進入遊戲,初始化4*4表格,並隨機產生兩個2;
# 二維數組this.tables表格迴圈存入資料
#random1, random2 ,random11, random22四個隨機數可以確定兩個2的xy位置;
#方法newNumber裡面,根據位置i,j和層級num可以確定一個新的數字;建立背景cell和cell上面的數字標籤cellLabel;並根據num確定是否顯示cellLabel;最後給cell關聯一個data資料;特別說明這裡的number:num不是精靈上面的數字而是精靈的層級,比如number=11 則數字是1024
MainLayer.prototype.onEnter = function () { //version this.versionNum = indexVersions; this.indexVersion = VERSIONS[this.versionNum]; this.title.setString(this.indexVersion.name + "目標:" + this.indexVersion.array[this.indexVersion.array.length - 1] + ""); var random1 = getRandom(4); var random2 = getRandom(4); while (random1 == random2) { random2 = getRandom(4); } var random11 = getRandom(4); var random22 = getRandom(4); this.tables = new Array(4); for (var i = 0; i < 4; i++) { var sprites = new Array(4); for (var j = 0; j < 4; j++) { if (i == random1 && j == random11) { sprites[j] = this.newNumber(i, j, 1); } else if (i == random2 && j == random22) { sprites[j] = this.newNumber(i, j, 1); } else { sprites[j] = this.newNumber(i, j, 0); } } this.tables[i] = sprites; } this.totalScore = 0;};MainLayer.prototype.newNumber = function (i, j, num) { var cell = cc.MySprite.create(this.rootNode, "5.png", this.getPosition(i, j), 1); var cellLabel = cc.MySprite.createLabel(cell, ""); if (num > 0) { cell.setColor(COLOR[num]); cellLabel.setVisible(true); cellLabel.setString(this.indexVersion.array[num]); cellLabel.setFontSize(this.indexVersion.labelFontSize); } else { cellLabel.setVisible(false); } cell.data = {col: i, row: j, numberLabel: cellLabel, number: num}; return cell;};
2 四個方向演算法;玩遊戲的時候觸摸四個方向,表格就向四個方向合并靠攏leftCombineNumber,rightCombineNumber,downCombineNumber,upCombineNumber,四個方法函數的演算法都是一樣的,我只分析一個leftCombineNumber;
第一步 相同資料疊加 :
#j從左至右變大,i從下到上變大;也就初始位置是左下角;
#如果該單元格層級不是空背景 cell.data.number != 0 ;
#從它的右邊開始var k = i + 1; 迴圈遍曆while (k < 4) {k++};
#如果遍曆到單元格層級也不是空背景 if (nextCell.data.number != 0) 遍曆結束 k = 4; break;;
#而且如果發現兩個單元的層級一樣if (cell.data.number == nextCell.data.number)
#層級資料number重新整理變化
cell.data.number += 1;
nextCell.data.number = 0;
第二步 填充空資料;
#同理第一步,如果是空背景if (cell.data.number == 0),也是迴圈遍曆while (k < 4) {k++};
#如果遍曆到單元格層級不是空背景 if (nextCell.data.number != 0) ,空背景獲得該單元格的資料,而該單元格則設為空白背景;
cell.data.number = nextCell.data.number;
nextCell.data.number = 0;
//direction leftMainLayer.prototype.leftCombineNumber = function () { for (var j = 0; j < 4; j++) { for (var i = 0; i < 4; i++) { var cell = this.tables[i][j]; if (cell.data.number != 0) { var k = i + 1; while (k < 4) { var nextCell = this.tables[k][j]; if (nextCell.data.number != 0) { if (cell.data.number == nextCell.data.number) { cell.data.number += 1; nextCell.data.number = 0; this.totalScore += SCORES[cell.data.number]; } k = 4; break; } k++; } } } } for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { cell = this.tables[i][j]; if (cell.data.number == 0) { k = i + 1; while (k < 4) { nextCell = this.tables[k][j]; if (nextCell.data.number != 0) { cell.data.number = nextCell.data.number; nextCell.data.number = 0; k = 4; } k++; } } } } this.refreshNumber();};//direction rightMainLayer.prototype.rightCombineNumber = function () { for (var j = 0; j < 4; j++) { for (var i = 3; i >= 0; i--) { var cell = this.tables[i][j]; if (cell.data.number != 0) { var k = i - 1; while (k >= 0) { var nextCell = this.tables[k][j]; if (nextCell.data.number != 0) { if (cell.data.number == nextCell.data.number) { cell.data.number += 1; nextCell.data.number = 0; this.totalScore += SCORES[cell.data.number]; } k = -1; break; } k--; } } } } for (j = 0; j < 4; j++) { for (i = 3; i >= 0; i--) { cell = this.tables[i][j]; if (cell.data.number == 0) { k = i - 1; while (k >= 0) { nextCell = this.tables[k][j]; if (nextCell.data.number != 0) { cell.data.number = nextCell.data.number; nextCell.data.number = 0; k = -1; } k--; } } } } this.refreshNumber();};MainLayer.prototype.downCombineNumber = function () { for (var i = 0; i < 4; i++) { for (var j = 0; j < 4; j++) { var cell = this.tables[i][j]; if (cell.data.number != 0) { var k = j + 1; while (k < 4) { var nextCell = this.tables[i][k]; if (nextCell.data.number != 0) { if (cell.data.number == nextCell.data.number) { cell.data.number += 1; nextCell.data.number = 0; this.totalScore += SCORES[cell.data.number]; } k = 4; break; } k++; } } } } for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { cell = this.tables[i][j]; if (cell.data.number == 0) { k = j + 1; while (k < 4) { nextCell = this.tables[i][k]; if (nextCell.data.number != 0) { cell.data.number = nextCell.data.number; nextCell.data.number = 0; k = 4; } k++; } } } } this.refreshNumber();};//touch upMainLayer.prototype.upCombineNumber = function () { for (var i = 0; i < 4; i++) { for (var j = 3; j >= 0; j--) { var cell = this.tables[i][j]; if (cell.data.number != 0) { var k = j - 1; while (k >= 0) { var nextCell = this.tables[i][k]; if (nextCell.data.number != 0) { if (cell.data.number == nextCell.data.number) { cell.data.number += 1; nextCell.data.number = 0; this.totalScore += SCORES[cell.data.number]; } k = -1; break; } k--; } } } } for (i = 0; i < 4; i++) { for (j = 3; j >= 0; j--) { cell = this.tables[i][j]; if (cell.data.number == 0) { k = j - 1; while (k >= 0) { nextCell = this.tables[i][k]; if (nextCell.data.number != 0) { cell.data.number = nextCell.data.number; nextCell.data.number = 0; k = -1; } k--; } } } } this.refreshNumber();};
3 重新整理資料和顏色;
上面的演算法完成了,只是該精靈的data裡面的資料發生了變化,但視覺上沒有任何變化,所以需要重新整理資料和顏色
#建立一個空背景數組emptyCellList;
#又是迴圈二維數組this.tables
#得到單元格的文字標籤label,和層級cellNumber
#如果不是空背景cellNumber!=0,label顯示和設定文字內容和大小,同時如果檢測到是最進階別,遊戲成功結束
#如果是空背景,label隱藏 emptyCellList添加該元素emptyCellList.push(cell);;
#得到一個emptyCellList後,如果發現該數組大小為空白,也就無法再產生一個數字2了,遊戲over;
#而如果數組大小不是空,隨機取一個位置randomCell,設定資料等級為0,數字為2,並播放縮放動畫runAction;
MainLayer.prototype.refreshNumber = function () { var emptyCellList = []; for (var i = 0; i < 4; i++) { var numbers = " "; for (var j = 0; j < 4; j++) { var cell = this.tables[i][j]; var label = cell.data.numberLabel; var cellNumber = cell.data.number; if (cellNumber != 0) { cell.setColor(COLOR[cellNumber]); label.setString(this.indexVersion.array[cellNumber] + " "); label.setFontSize(this.indexVersion.labelFontSize); label.setVisible(true); if (cellNumber == (this.indexVersion.array.length - 1)) { //check success var toast = cc.Toast.create(this.rootNode, "成功到達:" + this.indexVersion.array[cellNumber], 2); toast.setColor(cc.c3b(255, 0, 0)); this.rootNode.scheduleOnce(function () { cc.BuilderReader.runScene("", "MainLayer"); }, 2) } } else { cell.setColor(COLOR[cellNumber]); label.setVisible(false); emptyCellList.push(cell); } numbers += " " + cellNumber; } cc.log("numbers==" + numbers); } //score this.scoreLabel.setString("分數:" + this.totalScore); if (emptyCellList.length < 1) { //check fail var toast = cc.Toast.create(this.rootNode, "失敗!", 2); toast.setColor(cc.c3b(255, 0, 0)); this.rootNode.scheduleOnce(function () { cc.BuilderReader.runScene("", "MainLayer"); }, 2) } else { //create random cell var randomCell = emptyCellList[getRandom(emptyCellList.length)]; randomCell.data.number = 1; randomCell.data.numberLabel.setVisible(true); randomCell.data.numberLabel.setString(VERSIONS[this.versionNum].array[1] + ""); randomCell.data.numberLabel.setFontSize(this.indexVersion.labelFontSize); randomCell.setColor(COLOR[1]); randomCell.runAction(cc.Sequence.create(cc.ScaleTo.create(0, 0.8), cc.ScaleTo.create(0.5, 1))); }};
4 觸摸檢測 兩個觸摸點this.pEnded this.pBegan 根據x y確定方向,再根據距離確定左右和上下;
MainLayer.prototype.onTouchesEnded = function (touches, event) { this.pEnded = touches[0].getLocation(); if (this.pBegan) { if (this.pEnded.x - this.pBegan.x > 50) { this.rightCombineNumber(); } else if (this.pEnded.x - this.pBegan.x < -50) { this.leftCombineNumber(); } else if (this.pEnded.y - this.pBegan.y > 50) { this.upCombineNumber(); } else if (this.pEnded.y - this.pBegan.y < -50) { this.downCombineNumber(); } }};
思路很清晰簡單,遊戲卻是簡約不簡單;
cocos2d-x跨平台遊戲引擎
cocos2d-x是全球知名的遊戲引擎 ,引擎在全球範圍內擁有眾多開發人員,涵蓋國內外各知名遊戲開發商。目前Cocos2d-x引擎已經實現橫跨ios、Android、Bada、MeeGo、BlackBerry、Marmalade、Windows、Linux等平台。編寫一次,到處運行,分為兩個版本 cocos2d-c++和cocos2d-html5 本文使用了後者;cocos2d-x 官網:http://cocos2d-x.org/cocos2d-x 資料下載 http://cocos2d-x.org/download
CocosEditor開發工具:
CocosEditor,它是開發跨平台的手機遊戲工具,運行window/mac系統上,javascript指令碼語言,基於cocos2d-x跨平台遊戲引擎, 集合代碼編輯,情境設計,動畫製作,字型設計,還有粒子,物理系統,地圖等等的,而且調試方便,和即時類比;
CocosEditor 下載,介紹和教程:http://blog.csdn.net/touchsnow/article/details/19070665;
CocosEditor官方部落格:http://blog.makeapp.co/;
2048系列文章
2048原始碼解密和下載(第一篇 分析原版)
2048原始碼解密和下載(第二篇 分析各種版本)
傳送門(優質博文):
flappy bird遊戲原始碼揭秘和下載
flappy bird遊戲原始碼揭秘和下載後續---移植到android真機上
flappy bird遊戲原始碼揭秘和下載後續---移植到html5網頁瀏覽器
flappy bird遊戲原始碼揭秘和下載後續---日進5萬美元的秘訣AdMob廣告
PopStar(消滅星星)遊戲原始碼下載、分析及跨平台移植---第一篇(介面)
PopStar(消滅星星)遊戲原始碼下載、分析及跨平台移植---第二篇(演算法)
PopStar(消滅星星)遊戲原始碼下載、分析及跨平台移植---第三篇(分數)
PopStar(消滅星星)遊戲原始碼下載、分析及跨平台移植---第四篇(關卡)
Fruit Ninja(水果忍者)遊戲原始碼下載、分析(上)
Fruit Ninja(水果忍者)遊戲原始碼下載、分析(中)
Fruit Ninja(水果忍者)遊戲原始碼下載、分析(下)
筆者語:
想瞭解更多請進入官方部落格,最新部落格和代碼在官方部落格首發;請持續關注,還有更多CocosEditor遊戲源碼即將放出;
聯絡筆者:zuowen@makeapp.co(郵箱) qq群:232361142
附錄:
整理各種版本的2048線上玩,狂歡起來吧;
1、2048原始版
http://gabrielecirulli.github.io/2048/
2、2048進階版(有乘法和繼續玩下去的功能)
http://baiqiang.github.io/2048-advanced/
3、2048漢化版1:甲乙丙丁
http://tiansh.github.io/2048/zhong/
4、2048漢化版2:商周秦漢
http://oprilzeng.github.io/2048/
5、2048喵喵版:色弱慎入
http://hczhcz.github.io/2048/20mu/
6、2048喪病版:8*8
http://cyberzhg.github.io/2048/
7、2048flappy版
http://hczhcz.github.io/Flappy-2048/
8、2048六角形版
http://baiqiang.github.io/2048-hexagon/
9、2048cross版
http://baiqiang.github.io/2048-cross/
10、2048double版
http://baiqiang.github.io/2048-double/
11、2048哲學版
http://learn.tsinghua.edu.cn:8080/2013310744/philosopher2048/
12、2048一步登天版
http://jennypeng.me/2048/
13、2048斐波那契數列版
http://mike199515.free3v.com/1597/2.htm
14、2048雙人對戰版
http://emils.github.io/2048-multiplayer/
15、2048變2版
https://www.prism.gatech.edu/~hli362/
16、2048直線版
http://tiansh.github.io/2048/
17、新增3D版的2048:
http://baiqiang.github.io/2048-3d/
18、2048的一個合集:
http://get2048.com/