您的位置:首页 > 移动开发 > Cocos引擎

Cocos2d-X游戏【泰然网《跑酷》】JS到C++移植7:Gesture Recognizer【手势识别】

2013-12-17 20:47 603 查看
尊重开发者的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/17382889

<捕鱼达人>回顾

【cocos2d-x
IOS游戏开发-捕鱼达人1】内容介绍

<城市跑酷>回顾

【cocos2d-x
IOS游戏开发-城市跑酷1】跑酷游戏介绍

上节回顾

Cocos2d-X游戏【泰然网《跑酷》】JS到C++移植6:Running This Way

到目前为止runner可以向前移动。在给runner添加用户控制前,你需要处理玩家的输入。

在游戏中我们用跳上、跳下和转圈这三个手势来控制runner。

$1 Unistroke Recognizer是一个开源库。支持包含花圈在内的16个手势识别,有javaScript版本,可以很容易的导入到Cocos2d­x JSB项目里,这也正是泰然网的处理方式。

还有一个C++版的【GeometricRecognizer】,http://depts.washington.edu/aimgroup/proj/dollar/others/cpp.bw.zip

但是它有个缺点:很难区分向上滑动和向下滑动。必须由你自己去识别这两个手势。

Simple Recognizer

Simple Recognizer可以识别简单手势包括swipe up, swipe down, swipe left and swipe right.

创建一个名为“SimpleRecognizer.cpp”的cpp文件。替代内容如下:

#include "SimpleRecognizer.h"

#define MAX_DOUBLE std::numeric_limits<double>::max();

// class define
SimpleRecognizer::SimpleRecognizer()
{
this->result = SimpleGesturesError;
}

// be called in onTouchBegan
void SimpleRecognizer::beginPoint(double x, double y)
{
this->result = SimpleGesturesError;
points.push_back(Point(x,y));
}

// be called in onTouchMoved
void SimpleRecognizer::movePoint(double x, double y)
{
points.push_back(Point(x, y));

if (result == SimpleGesturesNotSupport) {
return;
}

SimpleGestures newRtn = SimpleGesturesError;
int len = this->points.size();
//每当触点移动时,在当前触点和之前触点之间计算不同的x坐标和y坐标
double dx = this->points[len - 1].x - this->points[len - 2].x;
double dy = this->points[len - 1].y - this->points[len - 2].y;

if (abs(dx) > abs(dy)) {
//在这种情况下,运动趋势的触点在x轴方向
if (dx > 0) {
newRtn = SimpleGesturesRight;
} else {
newRtn = SimpleGesturesLeft;
}
} else {
//在这种情况下,运动趋势的触点在y轴方向
if (dy > 0) {
newRtn = SimpleGesturesUp;
} else {
newRtn = SimpleGesturesDown;
}
}

// first set result
if (result == SimpleGesturesError) {
result = newRtn;
return;
}

// if diretcory change, not support Recongnizer
if (result != newRtn) {
result = SimpleGesturesNotSupport;
}
}

SimpleGestures SimpleRecognizer::endPoint()
{
if (this->points.size() < 3) {
return SimpleGesturesError;
}
return result;
}

std::vector<Point>& SimpleRecognizer::getPoints()
{
return points;
}


然后:Integrated into the PlayLayer

定义新的类成员变量

SimpleRecognizer *recognizer;

GeometricRecognizer* geometricRecognizer;//使用GeometricRecognizer
Path2D p_2dPath;

跳转到函数init()在this->initPhysics()后面添加下面的代码
    // enable touch
    this->setTouchEnabled(true);
    // set touch mode to kCCTouchesOneByOne
    this->setTouchMode(kCCTouchesOneByOne);

//自己扩展的简单手势识别
recognizer = new SimpleRecognizer();

//加载模板然后记录触摸操作(玩家在手机上所做手势的路径)
geometricRecognizer = new GeometricRecognizer;
geometricRecognizer->loadTemplates();
You enable the touch of the layer, and set touch mode to kCCTouchesOneByOne, which receive touch point one at a time in event callbacks.

打开这个层的触摸事件,并设置为一次只反馈一个触摸点的kCCTouchesOneByOne模式。

接着扩展触屏处理,添加下面代码到PlayLayer:

bool PlayScene::ccTouchBegan(CCTouch* touch, CCEvent* event)
{
CCLOG("PlayScene::ccTouchBegan");
CCPoint pos = touch->getLocation();
recognizer->beginPoint(pos.x, pos.y);
return true;
}

void PlayScene::ccTouchMoved(CCTouch* touch, CCEvent* event)
{
//CCLOG("PlayScene::ccTouchMoved");

#if 1
CCPoint pos = touch->getLocation();
recognizer->movePoint(pos.x, pos.y);
#else
CCPoint location = touch->getLocation();
Point2D p_Point2DTemp;
p_Point2DTemp.x = location.x;
p_Point2DTemp.y = location.y;
//记录
p_2dPath.push_back(p_Point2DTemp);
#endif
}

void PlayScene::ccTouchEnded(CCTouch* touch, CCEvent* event)
{
CCLOG("PlayScene::ccTouchEnded");

#if 1
SimpleGestures rtn = recognizer->endPoint();

switch (rtn) {
case SimpleGesturesUp:
CCLOG("Runner::jump");
break;

case SimpleGesturesDown:
CCLOG("Runner::crouch");
break;

case SimpleGesturesNotSupport:
case SimpleGesturesError:
// try dollar Recognizer
// 0:Use Golden Section Search (original)
// 1:Use Protractor (faster)
CCLOG("not support or error touch,use geometricRecognizer!!");
#if 0
//通过GeometricRecognizer校准
//可以选择屏蔽玩家单击操作
if (p_2dPath.size() < 1){
return ;
}

RecognitionResult r = geometricRecognizer->recognize(p_2dPath);
if((r.name != "Unknown") && (r.score > 0.5))
{

if (r.name == "Circle")

//开启runner无敌模式//return;}#endifbreak;}#endif}
void PlayScene::ccTouchCancelled(CCTouch* touch, CCEvent* event)
{CCLOG("onTouchCancelled!!!");}


一些注意事项:

1、在初始化的地方new一个GeometricRecognizer实例recognizer_,调用recognizer_->loadTemplates()方法。注意这个函数只是测试时使用,真正设计时,其手势模板应该是从配置文件中读取。

2、在TouchMove(或者是MouseMove,依平台而定)的时候将坐标push_back到一个集合里(touch_points_)。

3、在TouchEnd的时候调用: RecognitionResult r = recognizer_->recognize(touch_points_);

    我们对其返回的结果进行判断,如果(r.name != "Unknown" && r.score > 0.5),那么这就是我们识别出来的一个手势。name是手势模板名称,score是其权重,越高则与模板越匹配。

到现在为止,你就可以支持手势识别了:

简单的识别器 识别 速度超过GeometricRecognizer。由它先识别swipe up 和 swipe down。 如果它不能识别,再使用$1 Unistroke Recognizer。

调试并运行,尝试swipe up, swipe down ,画一个圆。你将看到生成的日志。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐