檢視原文或更新請移步到我的wiki: https://github.com/cheyiliu/All-in-One/wiki/cocos2d-x-3.3-018-joystick4cocos3.3
joystick
- joystick for cocos2d-x v3.3
- 完整代碼和資源 https://github.com/cheyiliu/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);
效果圖
參考資料
- https://github.com/cheyiliu/All-in-One/wiki/cocos2d-x-3.3rc2-005-cocos%E4%B8%AD%E7%9A%84%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88#%E5%B0%8F%E7%BB%93
- https://github.com/cheyiliu/All-in-One/wiki/cocos2d-x-3.3-012-%E4%BA%8B%E4%BB%B6%E5%88%86%E5%8F%91%E6%9C%BA%E5%88%B6
- http://blog.csdn.net/evankaka/article/details/42043509