天天看點

cocos2d-x-3.3-018-遊戲搖杆joystick源碼分享joystick核心思想實作思路核心代碼內建到項目效果圖參考資料

檢視原文或更新請移步到我的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);
           

效果圖

cocos2d-x-3.3-018-遊戲搖杆joystick源碼分享joystick核心思想實作思路核心代碼內建到項目效果圖參考資料

參考資料

  • 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

繼續閱讀