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

尊重开发者的劳动成果,转载的时候请务必注明出处: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();
Y ou 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 ,画一个圆。你将看到生成的日志

你可能感兴趣的:(C++,手势识别,游戏开发,cocos2d-x,跑酷)