因为一些原因最近比较空闲,本来一直以来的目标是想向着Unity大神进发的,抱着毕其一生的心态,毕竟Unity的前景摆在眼前,可现在闲着也是闲着就玩一下Cocos,还用是TypeScript语言,哈哈!在我一个前辈的建议下先做了个程序员都知道的2048小游戏,说真的2048这个游戏我之前就看人玩过,自己从来没有上过手,连规则都不知道。。所以还专门下了个玩了会才开始动手。
原谅我把这个技术博客写成了个人生活日记一般了。。哈哈!真是闲着蛋疼又很久没人没地和人扯淡了,就当在这发泄一下了!既然这么多废话,那我索性把它当作初学者的心得写吧。
用cocos前,当前还是先把整个官方文档都过了一边啦,因为有Unity的开发经验,所以文档里的大部分功能基本都能理解,看起来挺轻松的。然后我就跑去看Js的官方文档了。。。没错。。我还粗略看了一边js文档。。因为我开始并不知道可以用TS,哈哈哈!最后我还是又把TS的官方文档粗略的看完了一边,真的是粗略,甚至还没Js文档看得仔细,我就动手用Ts写这个游戏了。我想,一定是那个啥,二八原则!80%的问题都可以用20%的技术解决,哈哈哈哈!不扯,真正的原因是2048用的Ts语言的东西不多,后面要写复杂的游戏肯定还有坑要踩。
好了先上结果吧:
确实是简单的实现,其他UI部分都没有的。
下面上代码:
核心部分
import GameCtrl from './GameCtrl';
const {ccclass, property} = cc._decorator;
@ccclass
export default class GameCore{
private static _instance : GameCore = null;
public static Instance():GameCore{
if(GameCore._instance ===null){
GameCore._instance = new GameCore();
}
return GameCore._instance;
}
map : Array<Array<any>> = new Array<Array<any>>();
mapContrast : Array<Array<any>> = new Array<Array<any>>();
SpaceAmount : number; //剩余空格数量
Init(){
this.SpaceAmount = 0;
let x : number = Math.random() * 4;
let y : number = Math.random() * 4;
x = Math.floor(x);
y = Math.floor(y);
for(let i=0; i < 4; i ++)
{
this.map[i] = [];
this.mapContrast[i] = [];
for(let j=0; j < 4; j ++)
{
this.map[i][j] = 0;
this.mapContrast[i][j] = 0;
}
}
console.log(x +" <---> " + y);
this.map[x][y] = 2;
this.mapContrast[x][y] = 2;
GameCtrl.ShowUI(this.map);
this.map.forEach((val,idx,array)=>{
console.log(idx +" --- " + val);
});
}
onKeyUp(event){
//console.log("uppppppp");
this.SpaceAmount = 0;
switch(event.keyCode)
{
case cc.macro.KEY.up:
this.MergeToUp();
break;
case cc.macro.KEY.down:
this.MergeToDown();
break;
case cc.macro.KEY.left:
this.MergeToLeft();
break;
case cc.macro.KEY.right:
this.MergeToRight();
break;
}
this.AddNewNumber();
GameCtrl.ShowUI(this.map);
this.map.forEach((val, idx, ar)=>{
console.log(idx +" === " + val);
});
}
//增加新数字
AddNewNumber(){
if(this.SpaceAmount == 0)
{
GameCtrl.Instance().GameOver();
return;
}
let isCanAdd = false;
let dic: { [key: number]: cc.Vec2; } = {};
let idx = 0;
for(let i =0; i < 4; i++)
{
for(let j = 0; j < 4; j++)
{
if(this.map[i][j] == 0)
{
//记录空白处的XY,即数组中空白处的xy值
dic[idx] = new cc.Vec2(i, j);
idx +=1;
}
if(this.map[i][j] != this.mapContrast[i][j])
{
//和记录的对照数组做对比,与上一次的数组出现不同则说明可以增加数字
isCanAdd = true;
}
}
}
if(isCanAdd)
{
//随机
let randomIdx = Math.floor(Math.random() * idx);
//前提是存在空白的xy
if(dic != null && dic.hasOwnProperty(randomIdx))
{
this.map[dic[randomIdx].x][dic[randomIdx].y] = 2;
console.log(" ## random add --> " + dic[randomIdx].x + dic[randomIdx].y);
}
}
}
MergeToUp(){
for(let i = 0; i < 4; i++)
{
let temp : number[] = [0,0,0,0];
for(let j=0; j < 4; j++)
{
temp[j] = this.map[j][i];
}
//重新赋值每列的数
let newArr = this.MergeArr(temp);
for(let k = 0; k < 4; k++)
{
this.map[k][i] = newArr[k];
}
}
// this.map.forEach((val, idx, ar)=>{
// console.log(idx +" === " + val);
// });
}
MergeToDown(){
for(let i = 0; i < 4; i++)
{
let temp : number[] = [0,0,0,0];
let tempidx = 0;
for(let j= 3; j >=0; j--)
{
temp[tempidx] = this.map[j][i];
tempidx +=1;
}
//重新赋值每列的数
let newArr = this.MergeArr(temp);
tempidx = 0;
for(let k = 3; k >=0; k--)
{
this.map[k][i] = newArr[tempidx];
tempidx +=1;
}
}
// this.map.forEach((val, idx, ar)=>{
// console.log(idx +" === " + val);
// });
}
//向左合并
MergeToLeft(){
for(let i = 0; i < 4; i ++)
{
//重新赋值每列的数
this.map[i] = this.MergeArr(this.map[i]);
}
// this.map.forEach((val, idx, ar)=>{
// console.log(idx +" === " + val);
// });
}
//向右合并
MergeToRight(){
for(let i = 0; i < 4; i++)
{
let temp : number[] = [0,0,0,0];
let tempidx = 0;
for(let j = 3; j >=0; j--)
{
temp[tempidx] = this.map[i][j];
tempidx +=1;
}
//重新赋值每列的数
let newArr = this.MergeArr(temp);
tempidx = 0;
for(let k = 3; k >=0; k--)
{
this.map[i][k] = newArr[tempidx];
tempidx +=1;
}
}
// this.map.forEach((val, idx, ar)=>{
// console.log(idx +" === " + val);
// });
}
//核心合并
MergeArr (arr : Array<Number>)
{
let myArr : Array<Number> = [0,0,0,0];
let myArrIdx = 0;
let isCompara = false;
for(let i = 0; i < 4; i ++)
{
if(arr[i] >0)
{
if(isCompara)
{
//可以比较则比较是否相等
if(myArr[myArrIdx -1] == arr[i])
{
myArr[myArrIdx -1] = (arr[i] as number) * 2;
isCompara = false;
continue;
}
}
myArr[myArrIdx] = arr[i];
myArrIdx +=1;
//新加入的数字,可以进行比较
isCompara = true;
}
}
//记录空格数量
this.SpaceAmount += 4 - myArrIdx;
return myArr;
}
}
游戏控制部分
import GameCore from './GameCore';
import ShopCtrl from './ShopCtrl';
const {ccclass, property} = cc._decorator;
@ccclass
export default class GameCtrl extends cc.Component {
private static _instance : GameCtrl = null;
public static Instance():GameCtrl{
return GameCtrl._instance;
}
@property(cc.Node)
shopsRoot : cc.Node = null;
// @property(cc.Label)
// allShops : cc.Label[] = [];
showShops: cc.Label[] = [];
shopCtrls : ShopCtrl[] = [];
onLoad () {
GameCtrl._instance = this;
//获取所有shopLab
this.showShops = this.shopsRoot.getComponentsInChildren(cc.Label);
this.shopCtrls = this.shopsRoot.getComponentsInChildren(ShopCtrl);
cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP,this.onKeyUp, this);
// FBInstant
}
start()
{
GameCore.Instance().Init();
}
onDestroy(){
cc.systemEvent.off(cc.SystemEvent.EventType.KEY_UP,this.onKeyUp, this);
}
onKeyUp(event){
console.log("uppppppp");
GameCore.Instance().SpaceAmount = 0;
switch(event.keyCode)
{
case cc.macro.KEY.up:
GameCore.Instance().MergeToUp();
break;
case cc.macro.KEY.down:
GameCore.Instance().MergeToDown();
break;
case cc.macro.KEY.left:
GameCore.Instance().MergeToLeft();
break;
case cc.macro.KEY.right:
GameCore.Instance().MergeToRight();
break;
}
GameCore.Instance().AddNewNumber();
GameCtrl.ShowUI(GameCore.Instance().map);
// GameCore.Instance.map.forEach((val, idx, ar)=>{
// console.log(idx +" === " + val);
// });
}
GameOver(){
console.log(" ~~~~~ game over ~~~~~");
}
static ShowUI(Arr : Array<Array<any>>){
let idx = 0;
for(let i = 0; i < 4; i++)
{
for(let j = 0; j < 4; j ++)
{
//this._instance.showShops[idx].string = Arr[i][j];
this._instance.shopCtrls[idx].showNumber(Arr[i][j]);
idx +=1;
}
}
}
// update (dt) {}
}
方格控制脚本,我习惯每个方格挂脚本,传参数让它自己管理
const {ccclass, property} = cc._decorator;
@ccclass
export default class ShopCtrl extends cc.Component {
label: cc.Label = null;
// @property(cc.Sprite)
bg: cc.Node = null;
// LIFE-CYCLE CALLBACKS:
onLoad () {
this.label = this.node.getComponentInChildren(cc.Label);
this.bg = this.node;
}
showNumber(number : number)
{
this.label.string = number.toString();
let col = cc.Color.WHITE;
switch(number)
{
case 0 :
break;
case 2 :
col = cc.Color.YELLOW;
break;
case 4 :
col = cc.Color.BLUE;
break;
case 8 :
col = cc.Color.CYAN;
break;
case 16 :
col = cc.Color.GRAY;
break;
case 32:
col = cc.Color.GREEN;
break;
case 64:
col = cc.Color.MAGENTA;
break;
case 128:
col = cc.Color.ORANGE;
break;
case 256:
col = cc.Color.RED;
break;
case 512:
col = cc.Color.YELLOW;
break;
case 1024:
col = cc.Color.GREEN;
break;
case 2048:
col = cc.Color.TRANSPARENT;
break;
}
this.bg.color = col;
}
}
最后,结束本并没有很好的做好判断,只是粗略的写了下。