abi选择 cocos
2018-05-23 11:45:24 qq_27176027 阅读数 1468

功能需求:Cocos Creator 开发斗地主,滑动选取手上的手牌


问题:Cocos Creator没有滑动选取节点的组件,于是自己造轮子


说明:DragChoose组件用于在多个节点上滑动时,选择鼠标滑动区域内的节点,由于Cocos Creator 支持TypeScript,所以该组件由TypeScript语言编写,需要配合Layout组件使用,可以直接挂在相应的Node节点上

-------------------------------------------------------------------------------------------------------------

使用示例1:扑克根节点上需要挂上Layout组件,对子节点下的扑克牌进行排列


使用示例2:选择扑克,被选中的变成灰色

let dragChoose = this.node.addComponent(DragChoose)
dragChoose.OnMoving = (nodes) => {
for (let index = 0; index < nodes.length; index++)
        {
const poker = nodes[index];
// poker 变成灰色
}
}



使用示例3:选择扑克结束,扑克弹起

let dragChoose = this.node.addComponent(DragChoose)
dragChoose.OnEnd = (nodes) => {
for (let index = 0; index < nodes.length; index++) {
const poker = nodes[index];
// poker 弹起
}
}


-------------------------------------------------------------------------------------------------------------

组件代码如下:


const { ccclass, property } = cc._decorator;

@ccclass
export default class DragChoose extends cc.Component {
editor: {
executeInEditMode: true,
requireComponent: cc.Layout,
}

public OnMoving: Function = null;
public OnEnd: Function = null;
private mWidth: number = 0; //item的宽,所有子对象必须等宽
private mHeight: number = 0; //item的高,所有子对象必须等高
private offsetX: number = 0; //item之间的排列间距缩进
private startIndex: number = -1;
private endIndex: number = -1;
private isPressDown: false = false;//默认不按下
private nodes: Array<cc.Node> = new Array<cc.Node>(); //所有子节点的集合
private validNodes: Array<cc.Node> = new Array<cc.Node>(); //所有非隐藏(有效)的子节点的集合
private targetNodes: Array<cc.Node> = new Array<cc.Node>() //选择的节点
private get validNodesCount() { return this.validNodes.length; }

onLoad() {
//获取所有子节点
this.nodes = this.node.children;
if (!IsValidArray(this.nodes)) {
cc.error('DragChoose has no children');
return;
}
//初始化状态 与 获取参数
this.mWidth = this.nodes[0].width;
this.mHeight = this.nodes[0].height;
this.node.setContentSize(0, this.mHeight)
let layout = this.node.getComponent(cc.Layout);
if (layout != null) {
this.offsetX = layout.spacingX;
}
this.ResetValidNodes()
this.ListenEvents();
}

private ResetValidNodes() {
this.validNodes = new Array<cc.Node>();
this.validNodes = this.nodes.filter((node) => {
return node.activeInHierarchy
})
}

private ListenEvents() {
this.node.on(cc.Node.EventType.TOUCH_START, function (event) {
this.isPressDown = true;
this.OnChooseStart(event);
}, this);
this.node.on(cc.Node.EventType.TOUCH_END, function (event) {
this.OnChooseCancel(event);
}, this);
this.node.on(cc.Node.EventType.TOUCH_CANCEL, function (event) {
this.OnChooseCancel(event);
}, this);
this.node.on(cc.Node.EventType.TOUCH_MOVE, function (event) {
this.OnChooseMoveing(event)
}, this);
}

private OnChooseStart(event) {
this.startIndex = -1;
this.endIndex = -1;
this.ResetValidNodes();
var mousePos = this.node.convertToNodeSpaceAR(event.getLocation());
this.startIndex = this.GetNodeIndex(mousePos.x);
}


private OnChooseCancel(event) {
var mousePos = this.node.convertToNodeSpaceAR(event.getLocation());

//在区域内,将区域内的节点加入
if (this.CheckValidArea(mousePos.x, mousePos.y)) {
this.targetNodes = new Array<cc.Node>();
this.endIndex = this.GetNodeIndex(mousePos.x);
if ((this.startIndex >= 0 && this.endIndex >= 0)) {
let tuple = MinMax(this.startIndex, this.endIndex);
for (let i = 0; i < this.validNodes.length; i++) {
const element = this.validNodes[i];
if (i <= tuple[1] && i >= tuple[0]) {
this.targetNodes.push(element)
}
}
}
}

if (this.OnEnd != null) {
this.OnEnd(this.targetNodes);
}
this.OnReset();
}

private OnChooseMoveing(event) {
if (!this.isPressDown) {
return;
}

//将鼠标坐标转成相对于当前节点的坐标
var mousePos = this.node.convertToNodeSpaceAR(event.getLocation());
if (!this.CheckValidArea(mousePos.x, mousePos.y)) {
return;
}

this.endIndex = this.GetNodeIndex(mousePos.x);
if (this.endIndex == -1) {
return;
}

if ((this.startIndex >= 0 && this.endIndex >= 0) && this.startIndex != this.endIndex) {
let tuple: [number, number] = MinMax(this.startIndex, this.endIndex);
this.targetNodes = new Array<cc.Node>();
for (let i = 0; i < this.validNodes.length; i++) {
const element = this.validNodes[i];
if (i <= tuple[1] && i >= tuple[0]) {
this.targetNodes.push(element)
}
}
if (this.OnMoving != null) {
this.OnMoving(this.targetNodes);
}
}
}

//在有效范围内(高 和 宽)
private CheckValidArea(x, y) {
var CheckValidAreaX = (posX) => {
var areaLeft = this.validNodes[0].getPositionX() - this.mWidth / 2;
var areaRight = this.validNodes[this.validNodesCount - 1].getPositionX() + this.mWidth / 2;
return posX <= areaRight && posX >= areaLeft;
}
var CheckValidAreaY = (posY) => {
var areaTop = this.mHeight / 2;
var areaDown = - (this.mHeight / 2);
return posY <= areaTop && posY >= areaDown;
}
return CheckValidAreaX(x) && CheckValidAreaY(y);
}

private OnReset() {
this.isPressDown = false;
this.startIndex = -1;
this.endIndex = -1;
}

private GetNodeIndex(x) {
for (let i = 0; i < this.validNodesCount; i++) {
var posX = this.validNodes[i].getPositionX();
if (i == this.validNodesCount - 1) {
if (x > (posX - this.mWidth / 2) && x < (posX + this.mWidth / 2)) {
return i;
}
}

if (x > (posX - this.mWidth / 2) && x < (posX + this.mWidth / 2 + this.offsetX)) {
return i;
}
}
return -1;
}
}




2017-05-12 11:05:48 themagickeyjianan 阅读数 601
2018-03-09 01:26:00 weixin_34221773 阅读数 13

原理

1.触控事件是针对节点的

2.触控事件的冒泡,是直接关系冒泡,父子可以,孙子不行,就是不能隔代冒泡

3.父节点不响应触控事件,肯定是被孩子节点遮挡了,只要孩子节点也监听一下事件,父节点就可以响应了

4.触控位置是绝对坐标,相对于整个canvas,节点位置相对于父节点,相对位置可以与绝对坐标相互转化

5.节点是否被触控到,touch start事件可以肯定被触摸到,但是一个节点触摸到必须等待其结束,另一个节点才能响应touch事件

6.判断是否框选中,根据坐标计算相互交叉即是选中。就是说我从触控起点->触控终点 构成的矩形区域,与节点的矩形存在重叠,就是被框选。本例中,采用比较粗略的算法实现,根据横坐标的范围是否包含子节点的横坐标判断是否选中。

7.计算某个数值是否在某一范围内,首先计算出范围的最大值、最小值,然后作比较即可。

核心代码

cc.Class({
 extends: cc.Component,

 properties: {
  // foo: {
  // default: null,  // The default value will be used only when the component attaching
  //       to a node for the first time
  // url: cc.Texture2D, // optional, default is typeof default
  // serializable: true, // optional, default is true
  // visible: true,  // optional, default is true
  // displayName: 'Foo', // optional
  // readonly: false, // optional, default is false
  // },
  // ...
   poker:{
    default:null,
    type:cc.Node
   },
   cardMask:{
    default:null,
    type: cc.Prefab
   }
 },

 // use this for initialization
 onLoad: function () {
   
   //
   this.cards = this.poker.children;

   //牌初始位置
   this.cardInitY = this.cards[0].y;

   //触摸选择到的牌
   this.touchedCards = [];

   //选中的牌
   this.selectedCards = [];

   console.info(this.cards);
  },
  
  start: function () {
   // this.cards = this.poker.children;
   // console.info(this.cards);
   
   this.addTouchEvent();
  },

  /**
   * 添加事件
   */
  addTouchEvent:function(){

   //父节点监听touch事件(直接子节点必须注册同样的事件方能触发)
   this.poker.on(cc.Node.EventType.TOUCH_START, function (event) {
    console.log('poker TOUCH_START');
    
    //
    var card = event.target;
    
    //起始触摸位置(和第一张card一样,相对于poker的位置)
    this.touchStartLocation = this.cards[0].convertTouchToNodeSpace(event);
    console.log('touch start Location:'+ JSON.stringify(this.touchStartLocation));
    
    //计算牌位置
    var index = 0;
    for(var i=0;i<this.cards.length;i++){
     var c = this.cards[i];
     if(c.name == card.name){
      index = i;
      break;
     }
    }

    //暂存第一次触摸到的牌
    var touchedCard = {
     index:index,
     card:card
    };
    this.firstTouchedCard = touchedCard;
    //暂存
    this.pushTouchedCards(touchedCard.index,touchedCard.card);

   }, this);
  
   //父节点监听touch事件(直接子节点必须注册同样的事件方能触发)
   this.poker.on(cc.Node.EventType.TOUCH_MOVE, function (event) {
    console.log('poker TOUCH_MOVE');
    //先清除原先触摸到的牌
    this.clearTouchedCards();
    //保存第一张牌
    this.pushTouchedCards(this.firstTouchedCard.index,this.firstTouchedCard.card);

    //触摸点转换为card节点坐标
    var nodeLocation = this.cards[0].convertTouchToNodeSpace(event);
    console.log('touch nodeLocation:'+ JSON.stringify(nodeLocation));
    var x = nodeLocation.x;
    var y = nodeLocation.y; 

    //找到当前选中的牌
    var currentCard = null;
    for(var i=0;i< this.cards.length;i++){
     var card = this.cards[i];
     var cardX = card.x;
     var cardY = card.y;
     console.log('card x='+cardX+',y='+cardY);


     //某张牌范围包括了鼠标位置,选中此牌与触摸开头的所有牌
     var cardWidth = i==5 ? card.width:19;
     var cardHeight = card.height;
     if(cardX<=x && x <= cardX+cardWidth && cardY<=y && y<= cardY+cardHeight){
      currentCard = card;
    
      //暂存触摸到的牌
      this.pushTouchedCards(i,card);
      
      break;
     }
    }
    
    //添加开头与此牌直接的所有牌
    var startTouchLocation = this.touchStartLocation;
    for(var i=0;i< this.cards.length;i++){
     var card = this.cards[i];
     var cardX = card.x;
     //框选的范围包括了的牌
     var min,max;
     if(startTouchLocation.x < nodeLocation.x){
      min = startTouchLocation.x;
      max = nodeLocation.x;
     }else{
      min = nodeLocation.x;
      max = startTouchLocation.x;
     }
     console.log('min='+min+', max='+max);

     if(min <= cardX && cardX <= max){
      //暂存触摸到的牌
      this.pushTouchedCards(i,card);
     }
    }
    

   }, this);
  
  //父节点监听touch事件(直接子节点必须注册同样的事件方能触发)
  this.poker.on(cc.Node.EventType.TOUCH_END, function (event) {
   console.log('poker TOUCH_END');
   this.doSelectCard();
  }, this);
  
  //父节点监听touch事件(直接子节点必须注册同样的事件方能触发)
  this.poker.on(cc.Node.EventType.TOUCH_CANCEL, function (event) {
   console.log('poker TOUCH_CANCEL');
   this.doSelectCard();
  }, this);
  
  //给所有的牌注册事件,会自动冒泡到poker节点
  for(var i=0;i< this.cards.length;i++){
   var cards = this.cards;
   //闭包传递i值
   (function(i){
    var card = cards[i];
    card.on(cc.Node.EventType.TOUCH_START, function (event) {
     console.log('card TOUCH_START');
    }, card);
    
    card.on(cc.Node.EventType.TOUCH_MOVE, function (event) {
     console.log('card TOUCH_MOVE');
    }, card);

    card.on(cc.Node.EventType.TOUCH_END, function (event) {
     console.log('card TOUCH_END');
    }, card);
 
    card.on(cc.Node.EventType.TOUCH_CANCEL, function (event) {
     console.log('card TOUCH_CANCEL');
    }, card);

   
   })(i)
   
  }
  
 },

 /**
  * 暂存触摸到的牌
  */
 pushTouchedCards:function(index,card){
  //构造牌对象
  var cardObj = {
   index:index,
   name:card.name,
   isSelected:card.y==this.cardInitY?false:true //高度不一样,表示选中
  };
  
  //防止重复添加
  var existCard = this.touchedCards.find(function(obj){
   if(obj.name == card.name){
    return obj;
   }else{
    return null;
   }
  });
  if(!existCard){
   //添加暂存
   this.touchedCards.push(cardObj);

   //包含提示
   this.addCardMask(card);
  }
 },

 /**
  * 清除原先暂存的触摸到的牌
  */
 clearTouchedCards:function(){
  for(var i=0;i<this.touchedCards.length;i++){
   var cardIndex = this.touchedCards[i].index;
   var card = this.cards[cardIndex];
   card.removeChild(card.children[0]);
  }
  this.touchedCards = [];
 },

 /**
  * 选择牌
  */
 doSelectCard:function(){
  this.selectedCards = [];

  console.log(this.touchedCards);

  //改变牌状态
  for(var i = 0; i< this.touchedCards.length;i++){
   var cardObj = this.touchedCards[i];
   var card = this.cards[cardObj.index];
   if(cardObj.isSelected){ //如果是选中改为不选中
    card.y = card.y - 30;
   }else{ //不选中改为选中状态
    card.y = card.y + 30;
   }
  }

  //重置
  this.clearTouchedCards();

  //显示选中的牌
  this.showSelectedCards();
 },

 /**
  * 包含牌遮罩
  */
 addCardMask:function(card){
  var cardMask = cc.instantiate(this.cardMask);
  cardMask.setPosition(cc.p(0, 0));
  card.addChild(cardMask);
  },

 /**
 * 显示选中的牌
 */
 showSelectedCards:function(){
  this.selectedCards = [];
  for(var i=0;i< this.cards.length;i++){
   var card = this.cards[i];
   var isSelected = card.y==this.cardInitY?false:true;
   if(isSelected){
    this.selectedCards.push(card.name);
   }
  }
  //输出
  console.info("selected cards is: "+ JSON.stringify(this.selectedCards));
 },

 
 // called every frame, uncomment this function to activate update callback
 // update: function (dt) {

 // },
});

效果

以上这篇cocos creator Touch事件应用(触控选择多个子节点的实例)就是小编分享给大家的全部内容了

2015-09-10 23:36:23 luoyikun 阅读数 701

2.4.2 待选择植物卡片管理器类

此类管理所有本关卡能选择的卡片。

//从关卡配置文件中读取坐标,卡片名并显示出来
bool CWaitChooseCardMgr::levelConfigLoad()
{
	Json::Value root = CGlobalComm::getInstance()->getRootLevelConfig(); 
	int iLevel = CGlobalComm::getInstance()->getiGameLevel();//得到现在在运行的关卡,由前面关卡选择决定
	int index = CGlobalComm::getInstance()->cardChooseNumGet(iLevel);//获得一共有多少张植物卡
	m_iCanChooseNum = CGlobalComm::getInstance()->cardChooseNumGet(iLevel); //获得可以选择卡片数量
	for (int i = 0; i < index; i++)
	{
		CWaitChooseCard*  waitCard = CWaitChooseCard::create();
		std::string strNum = StringUtils::format("%d", i);
		waitCard->setsName(root[iLevel][strNum]["Name"].asString());
		waitCard->createByName(root[iLevel][strNum]["Name"].asString());//根据名字显示哪张卡片
		int iXpos = i % CardNumInALine;
		int iYpos = i / CardNumInALine;
		waitCard->setPosition(Point(X_CARD_INIT+iXpos*X_CARD_CNT, Y_CARD_INIT - iYpos*Y_CARD_CNT));
		this->addChild(waitCard);
		m_listWaitCard.pushBack(waitCard);//把得到待选卡片加入到待选容器中
	}  
	touchDeal();
	NOTIFY->addObserver(this, callfuncO_selector(CWaitChooseCardMgr::OnReduceChooseCard), NOTIFY_ReduceChooseCard, NULL);
	return true;
}

1.读取当前关一共有多少张植物卡片;2读取当前关可选多少张卡片;3.for循环创建待选择的植物卡片,并且把待选择卡片对象加入到待选容器中

触摸处理判断出点击到哪张待选的植物

//查找哪张待选卡片被点击了,返回被点击的卡片的对象
CWaitChooseCard* CWaitChooseCardMgr::findClickWaitCard(Point pos)
{
	for (auto waitCard : m_listWaitCard)
	{
		if (waitCard->clickJudge(pos) == true)
			return waitCard;
	}
	return NULL;
}

这里遍历待选卡片容器,当传入坐标被包含在某个卡片对象精灵的范围内,返回该植物卡片对象。clickJudge是卡片父类CEntity的方法,能够判断当前点是否落在了该实体绑定的精灵的范围内。

/**************************************************
函数作用:实体是否被点击,也可以用作碰撞的判定
**************************************************/
bool CEntity::clickJudge(Point pos)
{
	Size sizePic = this->getContentSize();//得到绑定图片的大小
	Point posPic = getPosition();//得到图片的中心位置
	//得到绑定图片的左上角与右下角
	Point srcPos = Point(posPic.x - sizePic.width / 2, posPic.y + sizePic.height / 2);
	Point destPos = Point(posPic.x + sizePic.width / 2, posPic.y - sizePic.height / 2);
	//判断点的坐标时否是在图片的范围内
	if (m_bCanClickFlg == true)
	{
		if (pos.x >= srcPos.x && pos.x <= destPos.x && pos.y <= srcPos.y && pos.y >= destPos.y)
		{
			return true;
		}
	}
	return false;
}

当确实点击到植物卡片身上,要做以下事情:1.本身要变成灰色显示;2.发布已经选择某张卡片的通知,传递的参数为卡片的名字

//根据触摸传过来的坐标,判断是按了那个卡片
void CWaitChooseCardMgr::cardClickDeal(Point pos)
{
	CWaitChooseCard* clickCard = findClickWaitCard(pos);

	if (clickCard == NULL) {
		return;
	}
	else
	{
		int iHaveChoose = CGlobalComm::getInstance()->getiHaveChoose();//得到已经选择的卡片数量
		if (iHaveChoose < m_iCanChooseNum)//如果选择次数满了
		{
			std::string sFilePath = StringUtils::format("%sG.png", (clickCard->getsName()).c_str());//特别注意这是格式化是c风格,要使用c_str()转化为c
			Sprite* sprCard = Sprite::createWithSpriteFrameName(sFilePath.c_str());
			clickCard->spriteBind(sprCard);//待选面板卡片绑定黑色的图片
			clickCard->setbCanClickFlg(false);

 			NOTIFY->postNotification(NOTIFY_AddChooseCard, (Ref*)((clickCard->getsName()).c_str()));//发布选择植物卡片的消息
			NOTIFY->postNotification(NOTIFY_HaveChooseNumChange, (Ref*)1);//发布增加已选卡片数量通知
		}
	}
}

实现效果



2018-09-14 14:20:00 weixin_34004750 阅读数 40

 

APP ABI 选项对应的是设备的 CPU 架构。勾选不同的值,编译出来的 apk 可以适用于不同的设备。勾选的越多,适配的机器越多。但是相应的 apk 包体越大。

需要根据自己的项目实际情况决定要编译哪些 APP ABI。如果都不勾选的话,那么默认与 proj.android/jni/Application.mk 中 APP_ABI 的值一致(Android Studio 项目的话,是 proj.android-studio/app/jni/Applicaition.mk 文件)

cocos植物大战僵尸(四)选择植物卡片:植物卡片类

阅读数 985

2.4 选择植物卡片在播完地图滚动后出现选择植物卡片层。能够选择相应的植物进行游戏。2.4.1 植物卡片类植物卡片是实体类的子类。实体类是游戏中一切能看到的,可操作的游戏元素。植物卡片具备以下功能:点击自身判断;根据名字读json显示花费阳光值,冷却时间;冷却跑秒。classCWaitChooseCard:publicCEntity{public: CWaitChoos

博文 来自: luoyikun

Cocos开发VR菜鸟宝典 第七讲:平台的选择与接入

阅读数 6719

火云开发课堂开讲啦!Cocos开发VR菜鸟宝典                          本套课程分为基础班和高级班两种,基础班主要在CSDN上推出视频,学员自学为主。高级班在此基础上再进行项目实训(包含Cocos3D,Shader基础班和VR设备学习套装)有兴趣参加高级班的可以加我QQ:285421210.第七章:平台的选择与接入视频地址:http://edu.csdn.net/cour

博文 来自: honghaier

Cocos开发VR菜鸟宝典 第二讲:VR设备选择

阅读数 6120

火云开发课堂开讲啦!              Cocos开发VR菜鸟宝典                          本套课程分为基础班和高级班两种,基础班主要在CSDN上推出视频,学员自学为主。高级班在此基础上再进行项目实训(包含Cocos3D,Shader基础班和VR设备学习套装)。有兴趣参加高级班的可以加我QQ:285421210.                    第二讲:V

博文 来自: honghaier

Cocos2d-JS中使用Cocos Studio资源04:关卡选择界面

阅读数 741

转:http://cn.cocos2d-x.org/tutorial/show?id=28201.cocosstudio中编辑界面:左下角 资源栏,导入图片资源,然后在Layer.csd中编辑图片,按钮等所有界面中用到的资源,在MainScene.csd中编辑与外部界面的位置信息等:中间最大的图形界面,可以对图片,按钮进行拖动,缩放等操作:右边是对应的属性值的配

博文 来自: chuanyu

初学者使用cocos creator制作第一个小游戏以及脚本编辑器的选择

阅读数 8061

这是一个官方文档的补充版,以官方文档的快速上手:制作第一个游戏为基础,整合了其他文档内容,同时添加一下自己学习文档的理解,不仅能复习一下自己学到的知识,也帮助新人学习开发更加简单,好了,话不多说,进入正题。ps:1.观看这篇的博客的读者都默认掌握了Javascript基础知识2.直到编写主角脚本部分之前都基本是官方文档的内容,从编写主角脚本部分开始会在官方文档的基础上加入自己的理解以及

博文 来自: stillwater123
没有更多推荐了,返回首页