赞
踩
转载自:https://www.jianshu.com/p/29883621184c
本文主要讲解以下几个方面:
- card model
- 滑动处理
- 阴影
- 选择
- 出牌
首先,牌有两个属性:数字、花型;
ps:本文现在是,用数字和花型来组成一张牌,有空可以再用另一种形式走一遍,比如用54个数字(0-53)来表示一副牌。
- CardInfo.js
-
- //花型
- var CardSuit = cc.Enum ({
- none: 0,
- spade: 1, //黑桃
- heart: 2, //红心
- club: 3, //梅花
- diamond: 4,//方块
- });
-
- //数字
- var CardNumber = cc.Enum ({
- none: 0,
- num_3: 3,
- num_4: 4,
- num_5: 5,
- num_6: 6,
- num_7: 7,
- num_8: 8,
- num_9: 9,
- num_10: 10,
- num_J: 11,
- num_Q: 12,
- num_K: 13,
- num_A: 14,
- num_2: 15,
- littleJoker: 16,
- bigJoker: 17,
- });
- var CardInfo = cc.Class ({
- extends: cc.Component,
-
- properties: {
- //数字
- number: {
- default: CardNumber.none,
- type: CardNumber
- },
- //花型
- suit: {
- default: CardSuit.none,
- type: CardSuit
- },
- },
-
- statics: {
- CardNumber: CardNumber,
- CardSuit: CardSuit
- },
-
- //主要用于打印时,能清晰看到现在是哪张牌
- desc() {
- var desc = "";
-
- if (this.number == CardNumber.littleJoker) {
- return "小王";
- }
- if (this.number == CardNumber.bigJoker) {
- return "大王";
- }
-
- switch(this.suit) {
- case CardSuit.heart:
- desc = "红桃";
- break;
- case CardSuit.spade:
- desc = "黑桃";
- break;
- case CardSuit.club:
- desc = "梅花";
- break;
- case CardSuit.diamond:
- desc = "方块";
- break;
- }
-
- switch(this.number) {
- case CardNumber.num_3:
- desc += "3";
- break;
- case CardNumber.num_4:
- desc += "4";
- break;
- case CardNumber.num_5:
- desc += "5";
- break;
- case CardNumber.num_6:
- desc += "6";
- break;
- case CardNumber.num_7:
- desc += "7";
- break;
- case CardNumber.num_8:
- desc += "8";
- break;
- case CardNumber.num_9:
- desc += "9";
- break;
- case CardNumber.num_10:
- desc += "10";
- break;
- case CardNumber.num_J:
- desc += "J";
- break;
- case CardNumber.num_Q:
- desc += "Q";
- break;
- case CardNumber.num_K:
- desc += "K";
- break;
- case CardNumber.num_A:
- desc += "A";
- break;
- case CardNumber.num_2:
- desc += "2";
- break;
- }
-
- return desc;
- },
- });
ps:小王,大王的花型为 CardSuit.none。
首先,在场景中,添加一个空节点,锚点设置为(0,0);
宽度,我这里设置为屏幕宽度1334;(如果你能准确算出,所有牌最长的宽,也可以设置为具体值)
高度,牌的高+牌选中状态向上的偏移量(我这里设置为:201+19)
手牌node.png
代码走起来
- main.js(绑定在当前场景上)
-
- var CardInfo = require("CardInfo");
- ...
- initHandCards : function(numbers){
- //随便初始化几张牌
- for (var number = 3; number <= 15; number++) {
- let cardInfo = new CardInfo();
- cardInfo.suit = number%2==0?CardInfo.CardSuit.diamond:CardInfo.CardSuit.spade;
- cardInfo.number = number;
- cardInfo.name = cardInfo.desc();
-
- //cardInfoArr 存储牌的信息对象的数组
- this.cardInfoArr.push(cardInfo);
-
- //根据牌的信息 初始化预制体
- var card = cc.instantiate(this.cardPrefab);
- card.getComponent("Card").mCardInfo = cardInfo;
-
- //将牌预制体 添加到父节点
- this.handCardArea.addChild(card, cardInfo.number);
- card.isChiose = false;
-
- //cardArr 存储card prefab的对象数组
- this.cardArr.push(card);
- }
-
- //计算posx,第一张牌显示的x坐标
- var posx = 1334/2 - (this.cardArr.length -1)/2 * 50;
- for (var i = 0; i < this.cardArr.length; i++){
- this.cardArr[i].setPosition(posx+ i*50, 100.5);
- }
- }
运行结果如下(牌的间距为50):
显示自己牌.png
选牌的事件监听对象,是不是牌呢?
如果只需要点击选择,我们可以直接在card prefab上添加点击事件监听
如果做滑动选牌,就需要在card prefab的父节点上(handCardArea),监听touchDown,touchMove,touchUp等事件
- CardArea.js(绑定在handCardArea节点上)、
-
- var Main = require("Main");
- cc.Class({
- extends: cc.Component,
-
- properties: {
- _touchBegan: null,
- _touchMoved: null,
-
- //用于调用Main场景上的脚本的方法,同时可以传递数据
- game:{
- default : null,
- type: Main,
- }
- },
-
- onTouchEvent: function () {
- this.node.on(cc.Node.EventType.TOUCH_START, this.touchBegan, this);
- this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.touchCancel, this);
- this.node.on(cc.Node.EventType.TOUCH_END, this.touchEnd, this);
- this.node.on(cc.Node.EventType.TOUCH_MOVE, this.touchMoved, this);
- },
-
- offTouchEvent: function () {
- this.node.off(cc.Node.EventType.TOUCH_START, this.touchBegan, this);
- this.node.off(cc.Node.EventType.TOUCH_CANCEL, this.touchCancel, this);
- this.node.off(cc.Node.EventType.TOUCH_END, this.touchEnd, this);
- this.node.off(cc.Node.EventType.TOUCH_MOVE, this.touchMoved, this);
- },
-
- onLoad () {
- this.onTouchEvent();
- },
-
- onDestroy(){
- this.offTouchEvent();
- },
-
- /**
- * Touch begin
- * 当前触摸的点 是否在牌的区域
- * */
- _getCardForTouch: function (touch, cardArr) {
- cardArr.reverse(); //to 1
- for (var k in cardArr) {
- var box = cardArr[k].getBoundingBox(); //获取card覆盖坐标范围
- if (cc.rectContainsPoint(box, touch)) { //判断触摸的点,是否在当前牌的范围内
- cardArr[k].isChiose = true;
- cardArr[k].getComponent("Card").setMaskShowing(true); //显示阴影遮罩
- cc.log("CCC touch select: "+k);
-
- cardArr.reverse();
- return cardArr[k];
- }
- }
- cardArr.reverse();
- },
-
- /**
- * Touch move
- *
- * */
- _checkSelectCardReserve(touchBegan, touchMoved) {
- //获取左边的点 为起始点
- var p1 = touchBegan.x < touchMoved.x ? touchBegan : touchMoved;
- //滑动的宽度
- var width = Math.abs(touchBegan.x - touchMoved.x);
- //滑动的高度 最小设置为5
- var height = Math.abs(touchBegan.y - touchMoved.y) > 5 ? Math.abs(touchBegan.y - touchMoved.y) : 5;
- //根据滑动 获取矩形框
- var rect = cc.rect(p1.x, p1.y, width, height);
-
- for (let i = 0; i < this.game.cardArr.length; i++) {
- //判断矩形是否相交
- if (!cc.rectIntersectsRect(this.game.cardArr[i].getBoundingBox(), rect)) {
- //不相交 设置为反选状态
- this.game.cardArr[i].isChiose = false;
- this.game.cardArr[i].getComponent("Card").setMaskShowing(false);
- }
- }
-
- //如果是从右向左滑动
- if (p1 === touchMoved) {
- for (let i = this.game.cardArr.length - 1; i >= 0; i--) {
- //从右往左滑时,滑到一定距离,又往右滑
- //这是要判断反选
- if (this.game.cardArr[i].x - p1.x < 24) { //
- this.game.cardArr[i].getComponent("Card").setMaskShowing(false);
- this.game.cardArr[i].isChiose = false;
- }
- }
- }
-
- },
-
- /**
- * 开始点击 TOUCH_START回调函数
- * */
- touchBegan: function (event) {
- cc.log("Touch begin");
- var touches = event.getTouches();
- var touchLoc = touches[0].getLocation();
- cc.log("touch begin location: "+touchLoc);
- this._touchBegan = this.node.convertToNodeSpace(touchLoc);
- this._getCardForTouch( this._touchBegan, this.game.cardArr);
- },
-
- /**
- * 移动 TOUCH_MOVE回调函数
- * */
- touchMoved: function (event) {
- cc.log("Touch move");
- var touches = event.getTouches();
- var touchLoc = touches[0].getLocation();
- this._touchMoved = this.node.convertToNodeSpace(touchLoc);
- this._getCardForTouch(this._touchMoved, this.game.cardArr);
- this._checkSelectCardReserve(this._touchBegan, this._touchMoved);
- },
-
- touchCancel: function () {
-
- },
-
- /**
- * 点击结束 TOUCH_END回调函数
- * */
- touchEnd: function (event) {
- cc.log("Touch end");
- var touches = event.getTouches();
- var touchLoc = touches[0].getLocation();
- for (var k in this.game.cardArr) {
- this.game.cardArr[k].getComponent("Card").setMaskShowing(false);
- if (this.game.cardArr[k].isChiose === true) {
- this.game.cardArr[k].isChiose = false;
- // to 2
- if (this.game.cardArr[k].status === SITDOWN) {
- this.game.cardArr[k].status = STANDUP;
- this.game.cardArr[k].y += 19;
- } else {
- this.game.cardArr[k].status = SITDOWN;
- this.game.cardArr[k].y -= 19;
- }
- }
- }
- },
1. 为什么要调用 cardArr.reverse()?
上面这张图里,鼠标现在放在 “方块8” 上,由于牌重叠放置,现在 “方块6”,“黑桃7”,“方块8” 三张牌的坐标范围,都包含了鼠标当前的位置。
首先,显示牌的时候,我们是从左往右显示的,也是从 0 到 cardArr.length-1 显示的。也就是说cardArr中,第0个元素是显示在最左边的。
第二点,我们举个例子:
现在鼠标在当前位置点击一下
如果,我们从“黑桃3”开始判断,那结果就会出现 “方块6”,“黑桃7”,“方块8” 三张牌,
很显然,这样的记过是不对的,我们想选择的只有 “方块8” 而已。
所以,正确的操作应该是,从最右边的 “黑桃2” 开始判断,因此,我们需要调用一次 reverse()。
第三点,需要注意的是,如果在 _getCardForTouch(cardArr) 中,使用的是原始cardArr数据,则需要在本地判断完成后,再次调用 reverse() 方法,将cardArr原始数据顺序还原,否则当你判断下一个点的时候,调用 reverse() 后,cardArr的数据就变成了正序,就达不到我们想要的效果了;
当然,如果每次传递的是原始数据,在 _getCardForTouch(cardArr) 方法中,使用的是cardArr的引用,就不需要再次调用 reverse()方法了。
2. touchEnd()中,为什么要将牌的状态反置?
如果滑动覆盖的区域内,包含已经是STANDUP状态的牌,应该将其置为未选中状态。
选牌时.png
选牌后.png
注意:
要打出的牌,不能直接用handCardArea节点下的组件,否则会提示被绑定。
代码先行
- discards (cards) {
- //出牌
- if (!cards || cards.lenngth == 0) return;
-
- //从父节点分离
- for (const key in cards) {
- if (cards.hasOwnProperty(key)) {
- const card = cards[key];
- card.node.removeFromParent(true); // 1
-
- for (var i = 0; i < this.handCards.length; i++) {
- var cardInfo = this.handCards[i];
- if (cardInfo == card.cardInfo) {
- this.handCards.splice(i, 1); // 2
- break;
- }
- }
- }
- }
-
- this.appendCardsToOutZone(cards); // 3
- this.updateCards(); // 4
-
- if(this.handCards.length == 0) {
- this.game.gameOver(this);
- }
- },
- /**
- * 将牌的预制体,添加到出牌区域
- */
- appendCardsToOutZone(cards) {
- this.outCardZone.node.removeAllChildren(true); // 3.1
-
- var count = cards.length;
- var zeroPoint = count / 2;
-
- for (var i = 0; i < count; i++) {
- var card = cards[i];
- var cardNode = card.node;
- this.outCardZone.node.addChild(cardNode, 100 - card.cardInfo.number); // 3.2
- }
- this.outCardZone.node.sortAllChildren();
-
- // 设置position
- for (var i = 0; i < count; i++) {
- var cardNode = this.outCardZone.node.getChildren()[i];;
-
- var x = (i - zeroPoint) * 30;
-
- var y = cardNode.getPositionY()+180;
- cardNode.setScale(0.7, 0.7); // 3.3
- cardNode.setPosition(x, y); // 3.4
- }
-
- },
1. 将 选中的牌 从父节点中移除
card.node.removeFromParent(true);
2. 从handCards 数组中,删除 选中的牌
this.handCards.splice(i, 1);
3. this.appendCardsToOutZone(cards)
将 “选中的牌” 添加到出牌区域
3.1 清空出牌区域
this.outCardZone.node.removeAllChildren(true);
3.2 添加子节点
this.outCardZone.node.addChild(cardNode, 100 - card.cardInfo.number);
3.3 设置scale
cardNode.setScale(0.7, 0.7);
3.4 设置position
cardNode.setPosition(x, y);
4. this.updateCards();
重新设置 手中的牌 的位置,这一点和显示手上牌的最后一步类似。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。