Cocos2d-x游戏开发实战精解
上QQ阅读APP看书,第一时间看更新

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游戏中,还可以实现手势来完成对地图的放大、缩小等功能。