Skip to content

cocos2d x 3.3 018 joystick4cocos3.3

cheyiliu edited this page Feb 1, 2015 · 4 revisions

joystick

核心思想

  • 解耦,采用事件机制将joystick的事件和目标对象之间的关联进行解耦

实现思路

  • 1.继承自layer并注册监听touch event
  • 2.若touch事件在joystick的中心点触发的,则继续下面的逻辑
  • 3.更新joystick中心点的位置
  • 4.计算touch点joystick中心点的角度(角度范围,第一象限[0, 90], 第二象限[90, 180], 第三象限[-180, -90], 第四象限[-90, 0])
  • 5.发布自定义的joystick event,目前事件仅包含上面计算的角度值,可根据需要进行增改
  • 6.注册joystick event的事件监听器,并在回调函数里实现你的业务逻辑
  • 7.joystick event中的userdata的内存释放,交给auto-release-pool了, 具体见JoystickEvent的实现

核心代码

  • JoystickEvent主要是规范内存管理,严格按照cocos的'风俗'进行: 两段构造方式create+Ref+pool,使create出的对象像个栈上的局部变量。(mainLoop下次清理pool时自动删除)。
  • Joystick的核心代码

bool Joystick::init() {
	bool result = false;
	do {
		// 父类初始化
		if (!Layer::init()) {
			break;
		}
		// joystick的背景
		mJsBg = Sprite::create("joystick_bg.png");
		if (nullptr == mJsBg) {
			break;
		}
		mJsBg->setPosition(mJsPos);
		addChild(mJsBg);

		// joystick的中心点
		mJsCenter = Sprite::create("joystick_center.png");
		if (nullptr == mJsCenter) {
			break;
		}
		mJsCenter->setPosition(mJsPos);
		addChild(mJsCenter);

		// touch event监听
		auto touchListener = EventListenerTouchOneByOne::create();
		if (nullptr == touchListener) {
			break;
		}
		touchListener->setSwallowTouches(true);
		touchListener->onTouchBegan =
				CC_CALLBACK_2(Joystick::onTouchBegan, this);
		touchListener->onTouchMoved =
				CC_CALLBACK_2(Joystick::onTouchMoved, this);
		touchListener->onTouchEnded =
				CC_CALLBACK_2(Joystick::onTouchEnded, this);
		_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener,
				this);

		result = true;
	} while (0);

	return result;
}

bool Joystick::onTouchBegan(Touch *touch, Event *unused_event) {
	log("onTouchBegan");
	auto point = touch->getLocation();
	if (mJsCenter->getBoundingBox().containsPoint(point)) {
		// 若触摸点在joystick的中心点,则继续接受事件
		return true;
	}
	// 否则不接受后续事件
	return false;
}

void Joystick::onTouchMoved(Touch *touch, Event *unused_event) {
	log("onTouchMoved");

	// 1. 获得角度,
	//第一象限是0,90度
	//第二象限是90,180度
	//第三象限是-90,-180度
	//第四象限是-90,0度
	Vec2 point = touch->getLocation();
	double y = point.y - mJsPos.y;
	double x = point.x - mJsPos.x;
	double angle = atan2(y, x) * 180 / PI;
	log("------------------------------------          %f", angle);

	// 2. 更新joystick中心点位置,目的是想让中心点始终在它的背景图范围
	// joystick背景图半径
	double jsBgRadis = mJsBg->getContentSize().width * 0.5;
	//触摸点到中心点的实际距离
	double distanceOfTouchPointToCenter = sqrt(
			pow(mJsPos.x - point.x, 2) + pow(mJsPos.y - point.y, 2));
	if (distanceOfTouchPointToCenter >= jsBgRadis) {
		//利用等比关系计算delta x y
		double deltX = x * (jsBgRadis / distanceOfTouchPointToCenter);
		double deltY = y * (jsBgRadis / distanceOfTouchPointToCenter);
		mJsCenter->setPosition(Vec2(mJsPos.x + deltX, mJsPos.y + deltY));
	} else {
		mJsCenter->setPosition(point);
	}

	//	 3. 分发joystick event
	JoystickEvent* jsEvent = JoystickEvent::create();
	jsEvent->mAnagle = angle;
	Director::getInstance()->getEventDispatcher()->dispatchCustomEvent(
			JoystickEvent::EVENT_JOYSTICK, jsEvent);
}

void Joystick::onTouchEnded(Touch *touch, Event *unused_event) {
	log("onTouchEnded");
	// 事件结束,还原joystick中心点位置
	mJsCenter->setPosition(mJsPos);
}

集成到项目

  • 我以proj.linx为例
  • 拷贝相关cpp .h到工程并在CMakeLists.txt中增加cpp
set(GAME_SRC
  Classes/AppDelegate.cpp
  Classes/HelloWorldScene.cpp
  Classes/Joystick.cpp        #新增
  ${PLATFORM_SPECIFIC_SRC}
)

  • 添加joystick到场景
auto joystick = Joystick::create();
scene->addChild(joystick);
  • 注册监听joystick event
#include "Joystick.h"


    auto _listener = EventListenerCustom::create(JoystickEvent::EVENT_JOYSTICK, [=](EventCustom* event){
        JoystickEvent* jsevent = static_cast<JoystickEvent*>(event->getUserData());
        log("--------------got joystick event, %p,  angle=%f", jsevent, jsevent->mAnagle);

        // do you business you'd like to
    });

    _eventDispatcher->addEventListenerWithFixedPriority(_listener, 1);

效果图

joystick_usage_demo.gif

参考资料

Clone this wiki locally