最近想自己做一个斗地主游戏(使用cocoscreator + javascript),发现滑动选择卡牌还有一点点麻烦呢,这里把实现分享下。

1、首先封装卡牌 CardCtrl.js

  卡牌的touched属性即为触摸框选标记,selected属性为触摸结束所选择卡牌的标记。其他的牌面花色什么的这里不做处理。

  1. /**
  2. * Created by skyxu on 2018/11/1.
  3. *
  4. * 卡牌组件
  5. */
  6. cc.Class({
  7. extends: cc.Component,
  8. properties: {
  9. spSelected: cc.Node,
  10. touched: {
  11. default: false,
  12. notify(){
  13. this.spSelected.active = this.touched;
  14. }
  15. },
  16. selected: {
  17. default: false,
  18. notify(){
  19. if (this.selected){
  20. this.node.y += 20;
  21. } else{
  22. this.node.y -= 20;
  23. }
  24. }
  25. },
  26. },
  27. // LIFE-CYCLE CALLBACKS:
  28. onLoad () {
  29. },
  30. start () {
  31. },
  32. // update (dt) {},
  33. });

 

2、接着实现滑动选择组件 DragSelect.js

  思路就是触摸滑动时画一个矩形,把和矩形有交集的卡牌都设为touched,触摸结束时把属性touched为true卡牌的selected属性设为true即可。

需要注意的是,由于卡牌是有叠加的,选择时要注意。我这里卡牌是右侧的压左侧的,所以每次touchmvoe时,只选择框选范围内最右侧的一张即可。主要分为3步:

  1. 判断矩形范围进行框选,在onTouchMove调用_checkSelectCard(beginPos,  endPos), 这里两个参数都传入当前的touchmove获得的pos, 即画一个最小的矩形,选择范围内最右侧一张即可。

  2.处理框选范围外的卡牌,在onTouchMove调用_checkSelectCardReverse(beginPos,  endPos), 这里两个参数一个传最初触摸开始的点和当前触摸的点。 这里需要注意的是,如果从右侧向左侧框选然后又退回到右侧则要特别处理,一担向右退回到当前卡牌的右侧卡牌上时则要把当前卡牌的touched属性设置为false(虽然矩形范围还包括当前卡牌,但包括的部分为右侧卡牌压着的部分)

  3. 触摸结束,touched属性为true的卡牌即为所选,并重置touched为false

  1. /**
  2. * Created by skyxu on 2018/11/1.
  3. *
  4. * 滑动选择卡牌组件
  5. * 把此组件拖放到卡牌根节点即可,卡牌根节点添加cc.Layout组件来自动布局
  6. *
  7. */
  8. cc.Class({
  9. extends: cc.Component,
  10. // LIFE-CYCLE CALLBACKS:
  11.  
  12. // onLoad () {},
  13. start () {
  14. this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
  15. this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
  16. this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
  17. this.cardsArr = this.node.getChildren();
  18. let card = this.cardsArr[0];
  19. // 指左侧卡牌锚点到右侧相邻卡牌边缘的距离
  20. this.CARD_DISTANCE = card.width*card.anchorX + this.node.getComponent(cc.Layout).spacingX;
  21. cc.log("CARD_DISTANCE: " + this.CARD_DISTANCE);
  22. },
  23. onTouchStart(event){
  24. let pos = event.getLocation();
  25. let beginPos = this._beginPos = this.node.convertToNodeSpaceAR(pos);
  26. this._checkSelectCard(beginPos, beginPos, true);
  27. },
  28. onTouchMove(event){
  29. let pos = event.getLocation();
  30. let movePos = this.node.convertToNodeSpaceAR(pos)
  31. // 这里确定是(movePos, movePos) 每次移动只选择右侧一张
  32. this._checkSelectCard(movePos, movePos);
  33. // 这里要传入起点和结束点,获取总的框取范围
  34. this._checkSelectCardReverse(this._beginPos, movePos);
  35. },
  36. onTouchEnd(event){
  37. this._onSelectCardEnd();
  38. },
  39. _onSelectCardEnd(){
  40. for (let card of this.cardsArr){
  41. let ctrl = card.getComponent("CardCtrl");
  42. if (ctrl.touched){
  43. ctrl.selected = !ctrl.selected;
  44. }
  45. ctrl.touched = false;
  46. }
  47. },
  48. _checkSelectCard(beginPos, endPos, isBegin){
  49. let len = this.cardsArr.length;
  50. if (isBegin){
  51. for (let i=len-1; i>=0; i--){
  52. let card = this.cardsArr[i];
  53. if (cc.rectContainsPoint(card.getBoundingBox(), beginPos)){
  54. card.getComponent('CardCtrl').touched = true;
  55. return;
  56. }
  57. }
  58. } else{
  59. let w = Math.max(1, Math.abs(beginPos.x - endPos.x));
  60. let h = Math.max(1, Math.abs(beginPos.y - endPos.y));
  61. let x = Math.min(beginPos.x, endPos.x);
  62. let y = Math.min(beginPos.y, endPos.y);
  63. let touchRect = cc.rect(x, y, w, h);
  64. for (let i=len-1; i>=0; i--){
  65. let card = this.cardsArr[i];
  66. if (cc.rectIntersectsRect(card.getBoundingBox(), touchRect)){
  67. card.getComponent('CardCtrl').touched = true;
  68. return;
  69. }
  70. }
  71. }
  72. },
  73. _checkSelectCardReverse(beginPos, endPos){
  74. let p1 = beginPos.x < endPos.x ? beginPos : endPos;
  75. let w = Math.abs(beginPos.x - endPos.x);
  76. let h = Math.abs(beginPos.y - endPos.y);
  77. let rect = cc.rect(p1.x, p1.y, w, h);
  78. let len = this.cardsArr.length;
  79. for (let i=len-1; i>=0; i--){
  80. let card = this.cardsArr[i];
  81. if (!cc.rectIntersectsRect(card.getBoundingBox(), rect)){
  82. card.getComponent('CardCtrl').touched = false;
  83. }
  84. }
  85. // 从右向左框取然后又移动回右侧则取消左侧已经选择的卡牌
  86. for (let i=0; i<len; i++){
  87. let card = this.cardsArr[i];
  88. if (p1.x - card.x >= this.CARD_DISTANCE){
  89. card.getComponent('CardCtrl').touched = false;
  90. }
  91. }
  92. }
  93. // update (dt) {},
  94. });

 

3、测试

  在场景里添加一个卡牌根节点 cardPanel, 并为它添加cc.Layout组件(自动布局),然后把DragSelect.js组件拖放到cardPanel即可。

  效果图如下

  

  Git链接:  https://github.com/sky068/dragSelectCards

 

  参考: https://blog.csdn.net/themagickeyjianan/article/details/39208463#commentBox

  

 

版权声明:本文为skyxu123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/skyxu123/p/9891207.html