4.2 多点触摸的羊驼游戏
在上一节中已经学习了怎样在Cocos2d-x中响应用户的单点触摸操作,在游戏的触摸控制中,除了单点触摸以外,还经常会用到多点触摸。当年红极一时的游戏《水果忍者》就是多点触摸的一个典型例子。玩家可以认真地伸出一个手指,小心地一下一下划过屏幕上的水果然后在心中赞叹一声,本大人真是文艺。也可以直接把五个爪子放到屏幕上乱画一气,前提是小心碰到游戏中的炸弹。当玩家同时将两个或两个以上的手指伸到屏幕上时,游戏对多个触摸点同时响应就叫做多点触摸。除此之外,在一些游戏中还会使用多点触控来进行一些操作(放大、缩小等),如图4-4中就列出了3种常见的手势。
图4-4 3种常见的触摸手势
在源文件当前目录下的项目ChapterFour02展示了一种使用多点触摸的方法,读者可以自行去查看完整代码,其中关键代码如范例4-3所示。
【范例4-3】在Cocos2d-x中使用多点触摸。
01 auto myListener = EventListenerTouchAllAtOnce::create(); 02 myListener->onTouchesBegan = [=](const std::vector<Touch*>& touches, Event *unused_event) 03 { 04 for (auto &item : touches) 05 { 06 auto* sprite = Sprite::create("sprite.png"); 07 sprite->setPosition(item->getLocation()); 08 sprite->setOpacity(120); 09 sprite->setScale(0.2f); 10 this->addChild(sprite); 11 } 12 }; 13 myListener->onTouchesMoved = [=](const std::vector<Touch*>& touches, Event *unused_event) 14 { 15 for (auto &item : touches) 16 { 17 int id = item->getID(); 18 auto array = this->getChildren(); 19 auto sprite = array.at(id); 20 auto point = item->getLocation(); 21 sprite->setPosition(point); 22 CCLOG("id=%d\tx=%f\ty=%f",id,point.x,point.y); 23 } 24 }; 25 myListener->onTouchesEnded = [=](const std::vector<Touch*>& touches, Event *unused_event) 26 { 27 for (auto &item : touches) 28 { 29 int id = item->getID(); 30 auto array = this->getChildren(); 31 auto sprite = array.at(id); 32 sprite->setOpacity(255); 33 auto point = item->getLocation(); 34 sprite->setPosition(point); 35 CCLOG("id=%d\tx=%f\ty=%f", id, point.x, point.y); 36 } 37 }; 38 _eventDispatcher->addEventListenerWithSceneGraphPriority(myListener, this);
由于本节所介绍的内容是多点触控,因此是无法做到在PC端用鼠标模拟手指单击效果的,因此需要在手机上进行测试,在项目目录下可以找到apk文件进行安装。安装之后运行将会看到屏幕上黑漆漆的一片,用手指单击屏幕将会有“羊驼”图案出现在屏幕上,滑动手指羊驼将跟随手指移动,同时或依次加入多个手指将会呈现出多点触摸的效果,如图4-5所示。
图4-5 3根手指同时划过手机屏幕后出现的效果
提示:实际上可以用多点触摸来实现单点触摸的一些功能。
为了在Cocos2d-x中实现多点触摸的功能,需要首先定义一个EventListenerTouchAllAtOnce类型的监听器,而不是上一节中介绍的EventListenerTouchOneByOne。从名字上就不难看出AllAtOnce就是同时处理多个的意思。观察范例可以发现,新的触发器的使用方法与单点触摸非常相似,只不过onTouchBegan等方法的名称改成了onTouchesBegan、onTouchesMoved和onTouchesEnded等。
下面再看第02~12行中对onTouchBegan方法的重写,主要内容就是当用户单击屏幕时生成一个精灵对象(即屏幕上的羊驼图案),然后加入到场景中,然而第04行中对for语句循环条件的判断,相信能让不少读者费解许久。因为这是在C++11中新定义的一种语法,也就是实现对括号内内容数组的遍历。由于多点触摸功能中许多时候系统需要同时判断多对触摸事件,因此就需要对它们编号,然后作为一个数组来传递和使用。而此处for循环的作用其实就是遍历该数组。
再看第25~37行对onTouchesMoved方法的重写,这里可以看出,第29行中就使用了getID方法来获取所对应的编号,从而知道当前所使用的是哪一次触摸(比如多个触摸点中的哪一个),然后根据这个编号来获取当前场景的子节点,从而得到对应的羊驼图案进行坐标位置的改变。
提示:虽然在用法上多点触摸相对单点触摸没有什么变化,但是由于牵扯到一些算法上的逻辑,比如在本例中需要确认找到触摸点与其对应的羊驼图案,因此相对于单点触摸实际上难度增加了不少。
至于接下来对onTouchesEnded的重写就很好理解了,找到对应的羊驼图案,将其透明度恢复为完全不透明(第32行)就算是完成任务了。
如果要开发一款类似于《水果忍者》这样的游戏,就可以在场景中先生成若干“水果”,并将它们依次与触发器绑定,然后利用多点触摸来判断是否有“水果”被切中,总的来说还是比较容易的。除此之外在一些RPG游戏中,还可以实现手势来完成对地图的放大、缩小等功能。