cocos2dx lua android按键反馈的消耗机制实现

在使用cocos2dx制作游戏的时候,为了提高android用户的使用,添加了android的按键监听,并且所有的界面联动都监听了bank按键。但是在使用的时候发现,两个layer监听实体键之后都收到了实体键返回。cocos并没有对实体键的反馈做事件消耗。好吧,引擎不做的只好自己实现了。

参考网页

感谢大神c++实现方案
cocos2dx-3.0+的按键事件处理还是不尽如人意–cocoachina
本文主要是实现lua层和对大神方案的补充,如果有错误还请各位路过大神指点指点,本人将不胜感激

实现

按大神指导修改文件

  • CCEventListener.h
bool init(Type t, const ListenerID& listenerID, const std::function<bool(Event*)>& callback);//修改
std::function<bool(Event*)> _onEvent;   //修改
  • CCEventListener.cpp
bool EventListener::init(Type t, const ListenerID& listenerID, const std::function<bool(Event*)>& callback)//修改
  • CCEventDispatcher.cpp
void EventDispatcher::dispatchEvent(Event* event)
{
    if (!_isEnabled)
        return;

    updateDirtyFlagForSceneGraph();


    DispatchGuard guard(_inDispatch);

    if (event->getType() == Event::Type::TOUCH)
    {
        dispatchTouchEvent(static_cast(event));
        return;
    }

    auto listenerID = __getListenerID(event);

    sortEventListeners(listenerID);

    auto pfnDispatchEventToListeners = &EventDispatcher::dispatchEventToListeners;
    if (event->getType() == Event::Type::MOUSE) {
        pfnDispatchEventToListeners = &EventDispatcher::dispatchTouchEventToListeners;
    }
    auto iter = _listenerMap.find(listenerID);
    if (iter != _listenerMap.end())
    {
        auto listeners = iter->second;

        auto onEvent = [&event](EventListener* listener) -> bool{
            event->setCurrentTarget(listener->getAssociatedNode());
            //listener->_onEvent(event);//修改位置
            //return event->isStopped();
            return listener->_onEvent(event) || event->isStopped();
        };

        (this->*pfnDispatchEventToListeners)(listeners, onEvent);
    }

    updateListeners(event);
}
  • CCEventListenerKeyboard.h
std::function<void(EventKeyboard::KeyCode, Event*)> onKeyReleased;//修改
  • CCEventListenerKeyboard.cpp
bool EventListenerKeyboard::init()
{
    auto listener = [this](Event* event)->bool{//修改位置
        auto keyboardEvent = static_cast(event);
        if (keyboardEvent->_isPressed)
        {
            if (onKeyPressed != nullptr)
               onKeyPressed(keyboardEvent->_keyCode, event);
        }
        else
        {
            if (onKeyReleased != nullptr)
                return onKeyReleased(keyboardEvent->_keyCode, event);//修改位置
        }
        return false;//修改位置
    };

    if (EventListener::init(Type::KEYBOARD, LISTENER_ID, listener))
    {
        return true;
    }

    return false;
}
  • CCEventListenerAcceleration.cpp
bool EventListenerAcceleration::init(const std::function<void(Acceleration*, Event* event)>& callback)
{
    auto listener = [this](Event* event)->bool{//修改位置
        auto accEvent = static_cast(event);
        this->onAccelerationEvent(&accEvent->_acc, event);
        return event->isStopped();//修改位置
    };

    if (EventListener::init(Type::ACCELERATION, LISTENER_ID, listener))
    {
        onAccelerationEvent = callback;
        return true;
    }

    return false;
}
  • CCEventListenerController.cpp
bool EventListenerController::init()
{
    auto listener = [this](Event* event)->bool{//修改位置
        auto evtController = static_cast(event);
        switch (evtController->getControllerEventType())
        {
        case EventController::ControllerEventType::CONNECTION:
            if (evtController->isConnected())
            {
                if (this->onConnected)
                    this->onConnected(evtController->getController(), event);
            }
            else
            {
                if (this->onDisconnected)
                    this->onDisconnected(evtController->getController(), event);
            }
            break;
        case EventController::ControllerEventType::BUTTON_STATUS_CHANGED:
            {
                const auto&  keyStatus = evtController->_controller->_allKeyStatus[evtController->_keyCode];
                const auto&  keyPrevStatus = evtController->_controller->_allKeyPrevStatus[evtController->_keyCode];

                if (this->onKeyDown && keyStatus.isPressed && !keyPrevStatus.isPressed)
                {
                    this->onKeyDown(evtController->_controller, evtController->_keyCode, event);
                }
                else if (this->onKeyUp && !keyStatus.isPressed && keyPrevStatus.isPressed)
                {
                    this->onKeyUp(evtController->_controller, evtController->_keyCode, event);
                }
                else if (this->onKeyRepeat && keyStatus.isPressed && keyPrevStatus.isPressed)
                {
                    this->onKeyRepeat(evtController->_controller, evtController->_keyCode, event);
                }
            }
            break;
        case EventController::ControllerEventType::AXIS_STATUS_CHANGED:
            {
                if (this->onAxisEvent)
                {
                    this->onAxisEvent(evtController->_controller, evtController->_keyCode, event);
                }
            }
            break;
        default:
            CCASSERT(false, "Invalid EventController type");
            break;
        }
        return event->isStopped();//修改位置
    };

    if (EventListener::init(EventListener::Type::GAME_CONTROLLER, LISTENER_ID, listener))
    {
        return true;
    }
    return false;
}
  • CCEventListenerCustom.cpp
bool EventListenerCustom::init(const ListenerID& listenerId, const std::function<void(EventCustom*)>& callback)
{
    bool ret = false;

    _onCustomEvent = callback;

    auto listener = [this](Event* event)->bool {//修改位置
        if (_onCustomEvent != nullptr)
        {
            _onCustomEvent(static_cast(event));
        }
        return event->isStopped();//修改位置
    };

    if (EventListener::init(EventListener::Type::CUSTOM, listenerId, listener))
    {
        ret = true;
    }
    return ret;
}
  • CCEventListenerFocus.cpp
bool EventListenerFocus::init()
{
    auto listener = [this](Event* event)->bool{//修改位置
        auto focusEvent = static_cast(event);
        onFocusChanged(focusEvent->_widgetLoseFocus, focusEvent->_widgetGetFocus);
        return event->isStopped();//修改位置
    };
    if (EventListener::init(Type::FOCUS, LISTENER_ID, listener)) {
        return true;
    }
    return false;
}
  • CCEventListenerMouse.cpp
bool EventListenerMouse::init()
{
    auto listener = [this](Event* event)->bool{//修改位置
        auto mouseEvent = static_cast(event);
        switch (mouseEvent->_mouseEventType)
        {
            case EventMouse::MouseEventType::MOUSE_DOWN:
                if(onMouseDown != nullptr)
                    onMouseDown(mouseEvent);
                break;
            case EventMouse::MouseEventType::MOUSE_UP:
                if(onMouseUp != nullptr)
                    onMouseUp(mouseEvent);
                break;
            case EventMouse::MouseEventType::MOUSE_MOVE:
                if(onMouseMove != nullptr)
                    onMouseMove(mouseEvent);
                break;
            case EventMouse::MouseEventType::MOUSE_SCROLL:
                if(onMouseScroll != nullptr)
                    onMouseScroll(mouseEvent);
                break;
            default:
                break;
        }
        return event->isStopped();//修改位置
    };

    if (EventListener::init(Type::MOUSE, LISTENER_ID, listener))
    {
        return true;
    }

    return false;
}
  • CCInputDelegate.h
virtual bool onKeyReleased(cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event* event) { return false; }; //修改
  • UIWidget.cpp
bool onKeypadKeyPressed(EventKeyboard::KeyCode, Event*);//修改
bool Widget::FocusNavigationController::onKeypadKeyPressed(EventKeyboard::KeyCode  keyCode, Event *event)
{
    if (_enableFocusNavigation && _firstFocusedWidget)
    {
        if (keyCode == EventKeyboard::KeyCode::KEY_DPAD_DOWN)
        {
            _firstFocusedWidget = _firstFocusedWidget->findNextFocusedWidget(Widget::FocusDirection::DOWN, _firstFocusedWidget);
        }
        if (keyCode == EventKeyboard::KeyCode::KEY_DPAD_UP)
        {
            _firstFocusedWidget = _firstFocusedWidget->findNextFocusedWidget(Widget::FocusDirection::UP, _firstFocusedWidget);
        }
        if (keyCode == EventKeyboard::KeyCode::KEY_DPAD_LEFT)
        {
            _firstFocusedWidget = _firstFocusedWidget->findNextFocusedWidget(Widget::FocusDirection::LEFT, _firstFocusedWidget);
        }
        if (keyCode == EventKeyboard::KeyCode::KEY_DPAD_RIGHT)
        {
            _firstFocusedWidget = _firstFocusedWidget->findNextFocusedWidget(Widget::FocusDirection::RIGHT, _firstFocusedWidget);
        }
    }
    return event->isStopped();//修改位置
}
  • CCLayer.h
virtual bool onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event);//修改
  • CCLayer.cpp
bool Layer::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* unused_event)
{
    CC_UNUSED_PARAM(unused_event);
#if CC_ENABLE_SCRIPT_BINDING
    if(kScriptTypeNone != _scriptType)
    {
        KeypadScriptData data(keyCode, this);
        ScriptEvent event(kKeypadEvent,&data);
        return ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&event);//修改位置
    }
#endif
    return false;//修改位置
}
  • lua_cocos2dx_manual.cpp
static int lua_cocos2dx_Layer_setKeyboardEnabled(lua_State* L)
{
    if (nullptr == L)
        return 0;

    int argc = 0;
    Layer* self = nullptr;

#if COCOS2D_DEBUG >= 1
    tolua_Error tolua_err;
    if (!tolua_isusertype(L,1,"cc.Layer",0,&tolua_err)) goto tolua_lerror;
#endif

    self = static_cast(tolua_tousertype(L,1,0));

#if COCOS2D_DEBUG >= 1
    if (nullptr == self) {
        tolua_error(L,"invalid 'self' in function 'lua_cocos2dx_Layer_setKeyboardEnabled'\n", NULL);
        return 0;
    }
#endif

    argc = lua_gettop(L) - 1;
    if (1 == argc)
    {
#if COCOS2D_DEBUG >= 1
        if (!tolua_isboolean(L, 2, 0, &tolua_err))
            goto tolua_lerror;
#endif
        bool enabled = tolua_toboolean(L, 2, 0);
        auto dict = static_cast<__Dictionary*>(self->getUserObject());
        if (dict == nullptr)
        {
            dict = __Dictionary::create();
            self->setUserObject(dict);
        }

        dict->setObject(__Bool::create(enabled), "keyboardEnabled");

        auto keyboardListener = static_cast(dict->objectForKey("keyboardListener"));

        auto dispatcher = self->getEventDispatcher();
        dispatcher->removeEventListener(keyboardListener);
        if (enabled)
        {
            auto listener = EventListenerKeyboard::create();
            listener->onKeyPressed = [self](EventKeyboard::KeyCode keyCode, Event* event){

            };
            listener->onKeyReleased = [self](EventKeyboard::KeyCode keyCode, Event* event){
                KeypadScriptData data(keyCode, self);
                ScriptEvent scriptEvent(kKeypadEvent,&data);
                return ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&scriptEvent);//修改位置
            };
            CCLOG("come in the keyboardEnable");
            dispatcher->addEventListenerWithSceneGraphPriority(listener, self);

            dict->setObject(listener, "keyboardListener");
        }
        return 0;
    }

    luaL_error(L, "%s has wrong number of arguments: %d, was expecting %d\n", "cc.Layer:setKeyboardEnabled", argc, 1);
    return 0;

#if COCOS2D_DEBUG >= 1
tolua_lerror:
    tolua_error(L,"#ferror in function 'lua_cocos2dx_Layer_setKeyboardEnabled'.",&tolua_err);
    return 0;
#endif
}
static void cloneKeyboardHandler(const EventListenerKeyboard* src,EventListenerKeyboard* dst,  ScriptHandlerMgr::HandlerType type)
{
    if (nullptr == src || nullptr == dst)
        return;

    LUA_FUNCTION handler = ScriptHandlerMgr::getInstance()->getObjectHandler((void*)src, type);
    if (0 != handler)
    {
        int newscriptHandler = cocos2d::ScriptEngineManager::getInstance()->getScriptEngine()->reallocateScriptHandler(handler);

        ScriptHandlerMgr::getInstance()->addObjectHandler((void*)dst, newscriptHandler, type);
        switch (type)
        {
            case ScriptHandlerMgr::HandlerType::EVENT_KEYBOARD_PRESSED:
                {
                    dst->onKeyPressed = [=](EventKeyboard::KeyCode keyCode, Event* event){
                        LuaEventKeyboarData listenerData((int)keyCode, event);
                        BasicScriptData data((void*)dst,(void*)&listenerData);
                        LuaEngine::getInstance()->handleEvent(type, (void*)&data);
                    };
                }
                break;
            case ScriptHandlerMgr::HandlerType::EVENT_KEYBOARD_RELEASED:
                {
                    dst->onKeyReleased = [=](EventKeyboard::KeyCode keyCode, Event* event){
                        LuaEventKeyboarData listenerData((int)keyCode, event);
                        BasicScriptData data((void*)dst,(void*)&listenerData);
                        return LuaEngine::getInstance()->handleEvent(type, (void*)&data);//修改位置
                    };
                }
                break;
            default:
                break;
        }
    }
}
static int tolua_cocos2dx_EventListenerKeyboard_registerScriptHandler(lua_State* tolua_S)
{
    if (nullptr == tolua_S)
        return 0;

    int argc = 0;
    EventListenerKeyboard* self = nullptr;
#if COCOS2D_DEBUG >= 1
    tolua_Error tolua_err;
    if (!tolua_isusertype(tolua_S, 1, "cc.EventListenerKeyboard", 0, &tolua_err))  goto tolua_lerror;
#endif

    self = static_cast(tolua_tousertype(tolua_S,1,0));
#if COCOS2D_DEBUG >= 1
    if (nullptr == self) {
        tolua_error(tolua_S,"invalid 'self' in function 'tolua_cocos2dx_EventListenerKeyboard_registerScriptHandler'\n", nullptr);
        return 0;
    }
#endif
    argc = lua_gettop(tolua_S) - 1;

    if (argc == 2)
    {
#if COCOS2D_DEBUG >= 1
        if (!toluafix_isfunction(tolua_S,2,"LUA_FUNCTION",0,&tolua_err) ||
            !tolua_isnumber(tolua_S, 3, 0, &tolua_err))
        {
            goto tolua_lerror;
        }
#endif

        LUA_FUNCTION handler = toluafix_ref_function(tolua_S,2,0);
        ScriptHandlerMgr::HandlerType type = static_cast((int)tolua_tonumber(tolua_S, 3, 0));
        switch (type)
        {
            case ScriptHandlerMgr::HandlerType::EVENT_KEYBOARD_PRESSED:
                {
                    ScriptHandlerMgr::getInstance()->addObjectHandler((void*)self, handler, type);
                    self->onKeyPressed = [=](EventKeyboard::KeyCode keyCode, Event* event){
                        LuaEventKeyboarData listenerData((int)keyCode, event);
                        BasicScriptData data((void*)self,(void*)&listenerData);
                        LuaEngine::getInstance()->handleEvent(type, (void*)&data);
                    };
                }
                break;
            case ScriptHandlerMgr::HandlerType::EVENT_KEYBOARD_RELEASED:
                {
                    ScriptHandlerMgr::getInstance()->addObjectHandler((void*)self, handler, type);
                    self->onKeyReleased = [=](EventKeyboard::KeyCode keyCode, Event* event){
                        LuaEventKeyboarData listenerData((int)keyCode, event);
                        BasicScriptData data((void*)self,(void*)&listenerData);
                        return LuaEngine::getInstance()->handleEvent(type, (void*)&data);//修改位置
                    };
                }
                break;
            default:
                break;
        }

        return 0;
    }

    luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n", "cc.EventListenerKeyboard:registerScriptHandler", argc, 2);
    return 0;

#if COCOS2D_DEBUG >= 1
tolua_lerror:
    tolua_error(tolua_S,"#ferror in function 'tolua_cocos2dx_EventListenerKeyboard_registerScriptHandler'.",&tolua_err);
    return 0;
#endif
}

代码修改完成,快去试试效果吧!

你可能感兴趣的:(cocos2dx)