Cocos2d creator js 使用javascript制作扑克游戏
1.前言
最近想做一个游戏,想起以前做安卓游戏的时候,ios他就运行不了,所以跨平台是一个目标,然后大概有二种语言备选,lua和js,其实我只是个写java的,都二种语言都不太熟悉,但是js的框架还是用了一些,就选择了js,目前只是单机版的V1.0,有很多改进的地方,cocos creator是一个中国的框架,网上的资源根本没有,只有硬着头皮看API和用户手册,看demo,和java和android编程不同,android游戏有很多资源,搜一个扑克游戏能找到很多下载,这个根本连游戏都少,扑克可能就没有,另外写完代码之后,我有点懵,想着赶紧总结一下,不然自己的代码也看不懂了
2.效果
3.准备
游戏少不了图片,需要各个图片的资源,另外就是扑克是prefab,也就是预制资源,也是altas,就是图集,关于图集就是一组图放到一个图片上面了,可以根据位移可以得到其中的某一张图。
另外就是声音资源,包括背景音乐,摸牌和出牌时候的声效。
4.核心代码分析
4.1 ItemTemplate.js
这个是扑克预制资源图片的脚本文件,也是用来逻辑控制的部分,id其实没什么用,也不唯一,icon是图片资源,名称为数字+a|b|c|d,abcd代表着方片,红心,梅花和黑桃四种花色,具体不是这个顺序,是这个意思,itemName是扑克牌的值,用来处理后台算数逻辑的主要部分。
cc.Class({
extends: cc.Component,
properties: {
id: 0,
icon: cc.Sprite,
itemName: cc.Label
},
init: function (data) {
this.id = data.id;
this.icon.spriteFrame = data.iconSF;
this.itemName.string = data.itemName;
}
});4.2 ItemList.js
cc.Class({
extends: cc.Component,
properties: {
items: {
default: [],
type: Item
},
opponentcards: {
default: []
},
itemPrefab: cc.Prefab,
backgroundAudio: {
default: null,
url: cc.AudioClip
},
getcardAudio: {
default: null,
url: cc.AudioClip
},
sendcardAudio: {
default: null,
url: cc.AudioClip
},
},
// use this for initialization
onLoad: function () {
//cc.log("ItemList:onLoad()");
//var sprite = cc.find("Canvas").addComponent(cc.Sprite);
//cc.eventManager.setEnabled(false);
cc.audioEngine.playEffect(this.backgroundAudio, true,0.5);
var targetcalNumber = 10;//need user to calculate this number
var isCalculatable = function(a,b,target){
cc.log("[isCalculatable] : (a,b,target) is (" + a + "," + b + "," + target + ")");
if(a + b === target){
return true;
}else if(a * b === target){
return true;
}else if(a - b === target){
return true;
}else if(b - a === target){
return true;
}else if(a / b === target){
return true;
}else if(b / a === target){
return true;
}else{
return false;
}
};
//return the value of cards
var getTwoNumberOfResult = function(arr,targetNumber){
cc.log("[getTwoNumberOfResult] : (arr,targetNumber) is (" + arr + "," + targetNumber + ")");
cc.log("arr is " );
cc.log(arr);
cc.log("targetNumber is ");
cc.log(targetNumber);
var result = [];
outerloop:
for(var o = 0;o < arr.length;o++){
for(var t = 1;t < arr.length;t++){
if(isCalculatable(arr[o],arr[t],targetNumber)){
result.push(arr[o]);
result.push(arr[t]);
break outerloop;
}
}
}
return result;
};
var getNewString = function(myindex,myspecies){
cc.log("[getNewString] : (myindex,myspecies) is (" + myindex + "," + myspecies + ")");
var index = myindex | parseInt(15*Math.random()) + 1;
var species = myspecies | parseInt(4*Math.random());
switch(species){
case 0: species = "a";break;
case 1: species = "b";break;
case 2: species = "c";break;
case 3: species = "d";break;
default:break;
}
var isString = "";
if(index < 14){
isString += index + species;
}else{
isString += index + (index === 14 ? "b" : "a");
}
cc.log("isString is " + isString);
return isString;
};
//init the opponentcards
var opponentcards = cc.find("Canvas").getComponent("ItemList").opponentcards;
for(var h = 0;h < 5;h++){
opponentcards[h] = parseInt(Math.random()*15) + 1;
}
cc.log("opponentcards is ");
cc.log(opponentcards);
//get new card function
var getNewCard = function(frame,i,frameNumber){
cc.log("[getNewCard] : (" + frame + ","+ i + "," + frameNumber + ")");
i = i | cc.find("Canvas").getComponent("ItemList").items.length;
var item = cc.instantiate(cc.find("Canvas").getComponent("ItemList").itemPrefab);
//cc.log("error message is " + err);
//var frame = atlas.getSpriteFrame(isString);
cc.find("Canvas").getComponent("ItemList").items[i] = new Item().init({id:i,itemName:""+frameNumber,iconSF:frame});
//cc.log(cc.find("Canvas").getComponent("ItemList").items[i]);
var data = cc.find("Canvas").getComponent("ItemList").items[i];
//cc.log("data is : ");
//cc.log(data);
item.getComponent('ItemTemplate').init(data);
item.setPosition(-300 + i*30,-220);
cc.log("item is ");
cc.log(item);
//set the Cards tag to 1001
cc.find("Canvas").addChild(item,null,1001);
return item;
};
var sendCards = function(arr,targetNumber){
cc.log("[sendCards] : (arr,targetNumber) is (" + arr + "," + targetNumber + ")");
//for remove the item loop,data in arr should sorted
arr.sort();
cc.log("arr in sendCards is ");
cc.log(arr);
var items = cc.find("Canvas").getComponent("ItemList").items;
var resultArray = [];
var tempArray = [];//my cards values
for(var e = 0;e < arr.length;e++){
tempArray.push(parseInt(items[arr[e]].itemName));
}
resultArray = getTwoNumberOfResult(tempArray,targetNumber);
if(resultArray.length === 0){
cc.log("not right operation");
alert("你出错了");
return;
}
var resultOfOpponentArray = [];
resultOfOpponentArray = getTwoNumberOfResult(opponentcards,tempArray[tempArray.length - 1]);
for(var r = 0; r < 10;r++){
cc.log("tempArray[tempArray.length - 1] is " + tempArray[tempArray.length - 1]);
}
while(resultOfOpponentArray.length === 0){
opponentcards.push(parseInt(Math.random()*15) + 1);
cc.log("opponent get the card: " + opponentcards[opponentcards.length - 1]);
resultOfOpponentArray = getTwoNumberOfResult(opponentcards,tempArray[tempArray.length - 1]);
}
for(var outer = 0;outer < resultOfOpponentArray.length;outer++){
for(var inner = 0;inner < opponentcards.length;inner++){
if(resultOfOpponentArray[outer] === opponentcards[inner]){
opponentcards.splice(opponentcards[inner],1);
}
}
}
cc.log("opponentcards after splice is ");
cc.log(opponentcards);
for(var i = 0;i < items.length;i++){
cc.find("Canvas").removeChildByTag(1001);
}
for(var j = 0;j < arr.length;j++){
//items[arr[j] - j].
var item = cc.instantiate(cc.find("Canvas").getComponent("ItemList").itemPrefab);
var data = items[arr[j] - j];
item.getComponent('ItemTemplate').init(data);
item.setPosition(j*30,0);
//set the sended Cards tag to 1002
cc.find("Canvas").addChild(item,null,1002);
items.splice(arr[j] - j,1);//re calculate the index of items
}
cc.log("items after splice is ");
cc.log(items);
cc.loader.loadRes("cards", cc.SpriteAtlas, function (err, atlas) {
for(var w = 0;w < items.length;w++){
var item = cc.instantiate(cc.find("Canvas").getComponent("ItemList").itemPrefab);
items[w].id = w;// reset the id of item
var data = items[w];
item.getComponent('ItemTemplate').init(data);
item.setPosition(-300 + w*30,-220);
cc.log("item in sendCards is ");
cc.log(item);
cc.find("Canvas").addChild(item,null,1001);
myAddListener(item,atlas);
}
//show the opponent cards
alert("computer is getting cards");
for(var c = 0;c < resultOfOpponentArray.length;c++){
var citem = cc.instantiate(cc.find("Canvas").getComponent("ItemList").itemPrefab);
var cspecies = parseInt(4*Math.random());
switch(cspecies){
case 0: cspecies = "a";break;
case 1: cspecies = "b";break;
case 2: cspecies = "c";break;
case 3: cspecies = "d";break;
default:break;
}
if(resultOfOpponentArray[c] === 14){
cspecies = "b";
}else if(resultOfOpponentArray[c] === 15){
cspecies = "a";
}
var cframe = atlas.getSpriteFrame(resultOfOpponentArray[c] + cspecies);
var cdata = new Item().init({id:resultOfOpponentArray[c],itemName:""+resultOfOpponentArray[c],iconSF:cframe});
citem.getComponent('ItemTemplate').init(cdata);
citem.setPosition(c*30,0);
//set the opponent sended Cards tag to 1003
cc.find("Canvas").addChild(citem,null,1003);
}
targetcalNumber = resultOfOpponentArray[resultOfOpponentArray.length - 1];
});
};
var myAddListener = function(item,atlas){
cc.eventManager.addListener({
event: cc.EventListener.MOUSE,
onMouseDown: function (event) {
event.stopPropagation();
event.cancelBubble = true;
//cc.log("x:" + event.getLocationX() + ",y:" + event.getLocationY());
var x = event.getLocationX();
var y = event.getLocationY();
cc.log("clicked position is (" + x + "," + y + ")");
if(x >=673 && x <= 750){
//click the get cards button
if(y>=114 && y <=174){
cc.audioEngine.playEffect(cc.find("Canvas").getComponent("ItemList").getcardAudio, false,1);
var str = getNewString();
var number = str.substring(0,str.length - 1);
getNewCard(atlas.getSpriteFrame(str),null,number);
}else if(y >= 34 && y <= 96){//click the send cards button
cc.audioEngine.playEffect(cc.find("Canvas").getComponent("ItemList").sendcardAudio, false,1);
var arr = [];
var nodes = [];
nodes = cc.find("Canvas").getChildren();
for(var s = 0;s < nodes.length;s++){
if(nodes[s].getComponent("ItemTemplate") !== null){
//the cards are clicked
if(nodes[s].y === -200){
if(arr.length === 2){
break;
}
arr.push(nodes[s].getComponent("ItemTemplate").id);
}
}
}
sendCards(arr,targetcalNumber);
}else{
}
return;
}
//card(s) are/is clicked by the user
if(y >= 36 && y <= 190){
//cc.log("length is " + cc.find("Canvas").getComponent("ItemList").items.length);
var nodes2 = [];
nodes2 = cc.find("Canvas").getChildren();
//cc.log("nodes length is " + nodes.length);
//for(var j = 0;j < cc.find("Canvas").getComponent("ItemList").items.length;j++){
//cc.log("x is " + x);
//}
for(var j = 0;j < nodes2.length;j++){
//cc.log(nodes[j].getComponent("ItemTemplate") === null);
if(nodes2[j].getComponent("ItemTemplate") !== null){
//cc.log("x is " + x + ",while nodes.x is " + nodes[j].x);
if((x-nodes2[j].x) < 460 && (x-nodes2[j].x) > 430){
cc.log(nodes2[j].y);
nodes2[j].y = (nodes2[j].y === -220 ? -200 : -220);
cc.log(nodes2[j].getComponent("ItemTemplate").id);
}//end if
}//end if
}//end for
}//end if
//cc.log('Mouse Down: ' + event.x);
},//end onMouseDown
onMouseUp: function (event) {
event.stopPropagation();
//cc.log('Mouse Up: ' + event);
}}, item);
}
cc.loader.loadRes("cards", cc.SpriteAtlas, function (err, atlas) {
for (var i = 0; i < 5; ++i) {
var frameName = getNewString();
var frameNumber = frameName.substring(0,frameName.length - 1);
cc.log("frameNumber is " + frameNumber);
var item = getNewCard(atlas.getSpriteFrame(frameName),i,frameNumber);
myAddListener(item,atlas);
}
});
}
// called every frame, uncomment this function to activate update callback
// update: function (dt) {// },
});代码主要如上,下面一一分析
properties: {
items: {
default: [],
type: Item
},
opponentcards: {
default: []
},
itemPrefab: cc.Prefab,
backgroundAudio: {
default: null,
url: cc.AudioClip
},
getcardAudio: {
default: null,
url: cc.AudioClip
},
sendcardAudio: {
default: null,
url: cc.AudioClip
},
},其中items就是上面item的数组,存储着扑克牌的图片和数值
opponentcards是数字整形int的数组,存储着机器人扑克牌的数值
itemPrefab暂时没有用
backgroundAudio是背景音乐
getcardAudio是摸牌音乐
sendcardAudio是出牌音乐
// use this for initialization
onLoad: function () {
//cc.log("ItemList:onLoad()");
//var sprite = cc.find("Canvas").addComponent(cc.Sprite);
//cc.eventManager.setEnabled(false);
cc.audioEngine.playEffect(this.backgroundAudio, true,0.5);
var targetcalNumber = 10;//need user to calculate this number 这个是为了播放背景音乐,API中有playmusic接口,但是浏览器同时只能播放一段music,可以同时播放多个Effect,为了在播放背景音乐的同时播放摸牌和出牌的音效,使用了playEffect方法
targetcalNumber机器人要计算出的数值,这个数值是用户放在上面的牌的值。
var isCalculatable = function(a,b,target){
cc.log("[isCalculatable] : (a,b,target) is (" + a + "," + b + "," + target + ")");
if(a + b === target){
return true;
}else if(a * b === target){
return true;
}else if(a - b === target){
return true;
}else if(b - a === target){
return true;
}else if(a / b === target){
return true;
}else if(b / a === target){
return true;
}else{
return false;
}
};
这个函数是为了判断二个数字a,b是不是可以通过加减乘除得到target这个数字
//return the value of cards
var getTwoNumberOfResult = function(arr,targetNumber){
cc.log("[getTwoNumberOfResult] : (arr,targetNumber) is (" + arr + "," + targetNumber + ")");
cc.log("arr is " );
cc.log(arr);
cc.log("targetNumber is ");
cc.log(targetNumber);
var result = [];
outerloop:
for(var o = 0;o < arr.length;o++){
for(var t = 1;t < arr.length;t++){
if(isCalculatable(arr[o],arr[t],targetNumber)){
result.push(arr[o]);
result.push(arr[t]);
break outerloop;
}
}
}
return result;
};
这个函数是为了返回一个长度为2的数组,这个数组里面的值是从arr中的二个能通过加减乘除计算出targetNumber值的得到的,这个函数是为了机器人服务的。
var getNewString = function(myindex,myspecies){
cc.log("[getNewString] : (myindex,myspecies) is (" + myindex + "," + myspecies + ")");
var index = myindex | parseInt(15*Math.random()) + 1;
var species = myspecies | parseInt(4*Math.random());
switch(species){
case 0: species = "a";break;
case 1: species = "b";break;
case 2: species = "c";break;
case 3: species = "d";break;
default:break;
}
var isString = "";
if(index < 14){
isString += index + species;
}else{
isString += index + (index === 14 ? "b" : "a");
}
cc.log("isString is " + isString);
return isString;
};
随机生成扑克牌的图片帧数名称,也就是随机生成扑克牌,大王和小王的出现概率高了一些,这个改改应该会更好,另外就是这是个会产生重复随机数的代码,也需要改改
//init the opponentcards
var opponentcards = cc.find("Canvas").getComponent("ItemList").opponentcards;
for(var h = 0;h < 5;h++){
opponentcards[h] = parseInt(Math.random()*15) + 1;
}
cc.log("opponentcards is ");
cc.log(opponentcards);
这个是为了初始化机器人手中的扑克牌
var getNewCard = function(frame,i,frameNumber){
cc.log("[getNewCard] : (" + frame + ","+ i + "," + frameNumber + ")");
i = i | cc.find("Canvas").getComponent("ItemList").items.length;
var item = cc.instantiate(cc.find("Canvas").getComponent("ItemList").itemPrefab);
//cc.log("error message is " + err);
//var frame = atlas.getSpriteFrame(isString);
cc.find("Canvas").getComponent("ItemList").items[i] = new Item().init({id:i,itemName:""+frameNumber,iconSF:frame});
//cc.log(cc.find("Canvas").getComponent("ItemList").items[i]);
var data = cc.find("Canvas").getComponent("ItemList").items[i];
//cc.log("data is : ");
//cc.log(data);
item.getComponent('ItemTemplate').init(data);
item.setPosition(-300 + i*30,-220);
cc.log("item is ");
cc.log(item);
//set the Cards tag to 1001
cc.find("Canvas").addChild(item,null,1001);
return item;
};这个是为了得到一个新的扑克牌用来展示,frame是扑克牌的图片,i是在items中的索引,frameNumber是扑克牌的数值
var sendCards = function(arr,targetNumber){
cc.log("[sendCards] : (arr,targetNumber) is (" + arr + "," + targetNumber + ")");
//for remove the item loop,data in arr should sorted
arr.sort();
cc.log("arr in sendCards is ");
cc.log(arr);
var items = cc.find("Canvas").getComponent("ItemList").items;
var resultArray = [];
var tempArray = [];//my cards values
for(var e = 0;e < arr.length;e++){
tempArray.push(parseInt(items[arr[e]].itemName));
}
resultArray = getTwoNumberOfResult(tempArray,targetNumber);
if(resultArray.length === 0){
cc.log("not right operation");
alert("你出错了");
return;
}
var resultOfOpponentArray = [];
resultOfOpponentArray = getTwoNumberOfResult(opponentcards,tempArray[tempArray.length - 1]);
for(var r = 0; r < 10;r++){
cc.log("tempArray[tempArray.length - 1] is " + tempArray[tempArray.length - 1]);
}
while(resultOfOpponentArray.length === 0){
opponentcards.push(parseInt(Math.random()*15) + 1);
cc.log("opponent get the card: " + opponentcards[opponentcards.length - 1]);
resultOfOpponentArray = getTwoNumberOfResult(opponentcards,tempArray[tempArray.length - 1]);
}
for(var outer = 0;outer < resultOfOpponentArray.length;outer++){
for(var inner = 0;inner < opponentcards.length;inner++){
if(resultOfOpponentArray[outer] === opponentcards[inner]){
opponentcards.splice(opponentcards[inner],1);
}
}
}
cc.log("opponentcards after splice is ");
cc.log(opponentcards);
for(var i = 0;i < items.length;i++){
cc.find("Canvas").removeChildByTag(1001);
}
for(var j = 0;j < arr.length;j++){
//items[arr[j] - j].
var item = cc.instantiate(cc.find("Canvas").getComponent("ItemList").itemPrefab);
var data = items[arr[j] - j];
item.getComponent('ItemTemplate').init(data);
item.setPosition(j*30,0);
//set the sended Cards tag to 1002
cc.find("Canvas").addChild(item,null,1002);
items.splice(arr[j] - j,1);//re calculate the index of items
}
cc.log("items after splice is ");
cc.log(items);
cc.loader.loadRes("cards", cc.SpriteAtlas, function (err, atlas) {
for(var w = 0;w < items.length;w++){
var item = cc.instantiate(cc.find("Canvas").getComponent("ItemList").itemPrefab);
items[w].id = w;// reset the id of item
var data = items[w];
item.getComponent('ItemTemplate').init(data);
item.setPosition(-300 + w*30,-220);
cc.log("item in sendCards is ");
cc.log(item);
cc.find("Canvas").addChild(item,null,1001);
myAddListener(item,atlas);
}
//show the opponent cards
alert("computer is getting cards");
for(var c = 0;c < resultOfOpponentArray.length;c++){
var citem = cc.instantiate(cc.find("Canvas").getComponent("ItemList").itemPrefab);
var cspecies = parseInt(4*Math.random());
switch(cspecies){
case 0: cspecies = "a";break;
case 1: cspecies = "b";break;
case 2: cspecies = "c";break;
case 3: cspecies = "d";break;
default:break;
}
if(resultOfOpponentArray[c] === 14){
cspecies = "b";
}else if(resultOfOpponentArray[c] === 15){
cspecies = "a";
}
var cframe = atlas.getSpriteFrame(resultOfOpponentArray[c] + cspecies);
var cdata = new Item().init({id:resultOfOpponentArray[c],itemName:""+resultOfOpponentArray[c],iconSF:cframe});
citem.getComponent('ItemTemplate').init(cdata);
citem.setPosition(c*30,0);
//set the opponent sended Cards tag to 1003
cc.find("Canvas").addChild(citem,null,1003);
}
targetcalNumber = resultOfOpponentArray[resultOfOpponentArray.length - 1];
});
};
这个就是出牌的时候的处理逻辑,也是本游戏的主要处理逻辑,忽略我全是语法错误的注释,首先判断用户点击的二张牌是不是能算出目标数值,如果不可以弹窗提醒,可以的话将所有节点移除然后重新生成节点,被用户发出去的牌坐标改为中心点,其他的牌重新设置坐标,这时候机器人也要计算他所有的牌是不是可以通过计算得到用户的放在上面的牌的值,可以了之后将二张扑克的图片也显示在中心点。
var myAddListener = function(item,atlas){
cc.eventManager.addListener({
event: cc.EventListener.MOUSE,
onMouseDown: function (event) {
event.stopPropagation();
event.cancelBubble = true;
//cc.log("x:" + event.getLocationX() + ",y:" + event.getLocationY());
var x = event.getLocationX();
var y = event.getLocationY();
cc.log("clicked position is (" + x + "," + y + ")");
if(x >=673 && x <= 750){
//click the get cards button
if(y>=114 && y <=174){
cc.audioEngine.playEffect(cc.find("Canvas").getComponent("ItemList").getcardAudio, false,1);
var str = getNewString();
var number = str.substring(0,str.length - 1);
getNewCard(atlas.getSpriteFrame(str),null,number);
}else if(y >= 34 && y <= 96){//click the send cards button
cc.audioEngine.playEffect(cc.find("Canvas").getComponent("ItemList").sendcardAudio, false,1);
var arr = [];
var nodes = [];
nodes = cc.find("Canvas").getChildren();
for(var s = 0;s < nodes.length;s++){
if(nodes[s].getComponent("ItemTemplate") !== null){
//the cards are clicked
if(nodes[s].y === -200){
if(arr.length === 2){
break;
}
arr.push(nodes[s].getComponent("ItemTemplate").id);
}
}
}
sendCards(arr,targetcalNumber);
}else{
}
return;
}
//card(s) are/is clicked by the user
if(y >= 36 && y <= 190){
//cc.log("length is " + cc.find("Canvas").getComponent("ItemList").items.length);
var nodes2 = [];
nodes2 = cc.find("Canvas").getChildren();
//cc.log("nodes length is " + nodes.length);
//for(var j = 0;j < cc.find("Canvas").getComponent("ItemList").items.length;j++){
//cc.log("x is " + x);
//}
for(var j = 0;j < nodes2.length;j++){
//cc.log(nodes[j].getComponent("ItemTemplate") === null);
if(nodes2[j].getComponent("ItemTemplate") !== null){
//cc.log("x is " + x + ",while nodes.x is " + nodes[j].x);
if((x-nodes2[j].x) < 460 && (x-nodes2[j].x) > 430){
cc.log(nodes2[j].y);
nodes2[j].y = (nodes2[j].y === -220 ? -200 : -220);
cc.log(nodes2[j].getComponent("ItemTemplate").id);
}//end if
}//end if
}//end for
}//end if
//cc.log('Mouse Down: ' + event.x);
},//end onMouseDown
onMouseUp: function (event) {
event.stopPropagation();
//cc.log('Mouse Up: ' + event);
}}, item); 这个就是通过用户点击的坐标获得用户是点击的哪张扑克,哪个按键。这个我使用的event.stopPropagation不行。导致只能在这个js里面监听按键的坐标,按理说我阻止了冒泡,但是它还是把事件向上传了
5.实例地址
Demo:http://justforuse.cn/cards
6.源代码下载
地址:http://pan.baidu.com/s/1eRVhirK
希望大家如果感兴趣可以参与到项目中来,共同学习,共同进步,也可以将对游戏的改进意见发给我
13820802870@163.com,其他联系方式见置顶文章
更多推荐


所有评论(0)