您的位置:首页 > 移动开发 > Cocos引擎

cocos3.x 编写C++控件在lua上面调用(一)

2014-08-08 14:30 330 查看
由于之前的代码出现了许多不足的地方,所以花了一段时间来重写这个控件的代码。

编写cocos的控件,那么首先设计的应该是C++的类

.h文件

#ifndef __ACCORDION__
#define __ACCORDION__

#include "cocos2d.h"
#include "cocos-ext.h"
#include "GUI/CCControlExtension/CCControlButton.h"
#include "CCLuaEngine.h"
#include "CCLuaStack.h"

USING_NS_CC;
USING_NS_CC_EXT;

typedef ControlButton FRAccordionItemTitle;
typedef Node            FRAccordionItemContent;

/** Create mode模式
 */
typedef enum
{
    kFRAccordionModeCreateAll,
    kFRAccordionModeCreateDynamic,
} FRAccordionCreateMode;

/** The item pair to show in FRAccordion
 */
class FRAccordionItem : public
Node
{
    /** The item title & content
     */
    CC_SYNTHESIZE_READONLY(FRAccordionItemTitle*,
_title, Title);
    CC_SYNTHESIZE_READONLY(FRAccordionItemContent*,
_content, Content);
    CC_SYNTHESIZE(int,
_tag, Tag);
    
public:
    FRAccordionItem();
    ~FRAccordionItem();
    
    static
FRAccordionItem* create(FRAccordionItemTitle* title,
FRAccordionItemContent* content);
    
protected:
    bool init(FRAccordionItemTitle* title,
FRAccordionItemContent* content);
    
};

#define kTagNothingSelected 0

/** FRAccordion
 */
class FRAccordion : public
Layer
{
public:
FRAccordion();
    ~FRAccordion();
    
    /** Lua listener for title tapped event
     */
    void registerChangeScriptFunc(int onChangeCallback);
    void unregisterChangeScriptFunc();
    
    /** Mode FRAccordionCreateDynamic: set the displaying content
     */
    void setCurrentContent(FRAccordionItemContent* content);
    
    /** For unition of Lua usage
     */
    void setCurrentIndex(unsigned
int index);
    unsigned int getCurrentIndex();
    
    /** If using mode FRAccordionModeCreateAll, items must contain children of type FRAccordionItem*
     *  Else, if using mode FRAccordionModeCreateDynamic, items must contain children of tyoe FRAccordionTitle*
     */
    
    static FRAccordion* create(const
Size& dimension, Vector<Node*>& items,
int mode, float gap =
0.f);
    
    bool init(const
Size& dimension, Vector<Node*>& items,
int mode, float gap =
0.f);
    
   /**
鼠标点击时候的相应函数
   */
    void touchDown(cocos2d::Ref *senderz,
Control::EventType controlEvent);
    
    /**
按钮移动的函数
*/
    void moveAction();
    
    /**
lua的相应函数
      */
    void luaCallback();
    
private:
    unsigned int currentIndex;//用来保存当前点击的按钮的index
    float _gap;//用来保存按钮直接的距离
    Vector<FRAccordionItem*> vecItems;//用来保存FRAccordionitems
    Vector<FRAccordionItemTitle*> vecTitles;//用来保存FRAccordionTitle
    int modeNum;//用来保存mode模式
    int luaHandle;//用来保存lua的函数id
};

#endif

以上为类的头文件,最后一个luaHandle可能会有些疑惑的地方。其实就是lua和C++相互调用得问题了,在cocos里面有了一个封装C++类来得到一个.hpp .cpp得tolua工具,使得lua上面可以调用到C++类上面得函数。而如果C++想要调用lua上面得函数得话,就没有相应得工具,所以上面就需要一个registerChangeScriptFunc(int)得函数来得到lua函数得id。上篇文章中有个链接地址是说这个得,不明白得话可以去看一下。简单得说来,就是因为C++和lua之间只能通过栈来交互。

.c
4000
pp文件

//
//  Accordion.cpp
//  Raccordion
//
//  Created by awally on 14-8-7.
//
//

#include "Accordion.h"
#include "lua.h"

FRAccordionItem::FRAccordionItem()
:_title(nullptr)
,_content(nullptr)
,_tag(0){
    
}

FRAccordionItem::~FRAccordionItem(){
    this->_title->release();
    this->_content->release();
}

FRAccordionItem* FRAccordionItem::create(FRAccordionItemTitle *title,
FRAccordionItemContent *content){
    FRAccordionItem* accordionItem =
new FRAccordionItem();
    if (accordionItem && accordionItem->init(title, content)) {
        accordionItem->autorelease();
    }else{
        CC_SAFE_DELETE(accordionItem);
    }
    return accordionItem;
}

bool FRAccordionItem::init(FRAccordionItemTitle *title,
FRAccordionItemContent *content){
    if (!Node::create()) {
        return false;
    }
    this->_title = title;
    this->_title->retain();
    this->_content = content;
    this->_content->retain();
    this->_tag =
_tag + 1;
    return true;
}

FRAccordion::FRAccordion()
:currentIndex(0)
,_gap(0.0)
,modeNum(0)
,luaHandle(0){
    
}

FRAccordion::~FRAccordion(){
    
}

void FRAccordion::registerChangeScriptFunc(int onChangeCallback){
    this->luaHandle = onChangeCallback;
}

void FRAccordion::unregisterChangeScriptFunc(){
    this->luaHandle =
0;
    lua_State* pl = lua_open();
    lua_pop(pl, 1);
    lua_close(pl);
}

void FRAccordion::setCurrentContent(FRAccordionItemContent *content){
    content->setPosition(150,
450-58*this->currentIndex);
    if(this->getChildByTag(2)){
        this->removeChildByTag(2);
    }
    this->addChild(content,
0, 2);
}

void FRAccordion::setCurrentIndex(unsigned
int index){
    this->currentIndex = index;
}

unsigned int
FRAccordion::getCurrentIndex(){
    return
this->currentIndex;
}

FRAccordion* FRAccordion::create(const
cocos2d::Size &dimension,
Vector<cocos2d::Node *> &items,
int mode, float gap){
    FRAccordion* accordion =
new FRAccordion();
    if (accordion && accordion->init(dimension, items, mode, gap)) {
        accordion->autorelease();
    }else{
        CC_SAFE_DELETE(accordion);
    }
    return accordion;
}

bool FRAccordion::init(const
cocos2d::Size &dimension,
Vector<cocos2d::Node *> &items,
int mode, float gap){
    this->setContentSize(dimension);
    this->_gap = gap;
    if (mode == 1) {
        this->modeNum =
1;
        for (int num=0; num<items.size(); num=num+2) {
            Scale9Sprite* bgSprite =
Scale9Sprite::create("button.png");
            ControlButton* controlBtn =
ControlButton::create(items.at(num), bgSprite);
            controlBtn->setMargins(50,
12);
            controlBtn->setPosition(150,
500-58*num/2);
            this->addChild(controlBtn);
            FRAccordionItem* item =
FRAccordionItem::create(controlBtn, items.at(num+1));
            this->vecItems.pushBack(item);
            controlBtn->addTargetWithActionForControlEvents(this,
cccontrol_selector(FRAccordion::touchDown),
Control::EventType::TOUCH_DOWN);
        }
        return true;
    }else if (mode ==
2){
        this->modeNum =
2;
        for (int num=0; num<items.size(); num++) {
            Scale9Sprite* bgSprite =
Scale9Sprite::create("button.png");
            ControlButton* controlBtn =
ControlButton::create(items.at(num), bgSprite);
            controlBtn->setMargins(50,
12);
            controlBtn->setPosition(150,
500-58*num);
            this->vecTitles.pushBack(controlBtn);
            this->addChild(controlBtn);
            controlBtn->addTargetWithActionForControlEvents(this,
cccontrol_selector(FRAccordion::touchDown),
Control::EventType::TOUCH_DOWN);
        }
        return true;
    }else{
        printf("enter wrong mode");
        return false;
    }
}

void FRAccordion::touchDown(cocos2d::Ref *senderz,
Control::EventType controlEvent){
    if (this->getChildByTag(1)) {
        this->removeChildByTag(1);
    }
    if (this->modeNum ==
1) {
        for (int num=0; num<this->vecItems.size(); num++) {
            if (this->vecItems.at(num)->getTitle()==senderz) {
                this->setCurrentIndex(num);
                this->vecItems.at(num)->getContent()->setPosition(150,
450-num*58);
                this->addChild(this->vecItems.at(num)->getContent(),
0, 1);
                this->moveAction();
            }
        }
    }else{
        for (int num=0; num<this->vecTitles.size(); num++) {
            if (this->vecTitles.at(num)==senderz) {
                this->setCurrentIndex(num);
                this->moveAction();
            }
        }
    }
}

void FRAccordion::moveAction(){
    if (this->modeNum==1) {
        for (int num=0; num<this->vecItems.size(); num++) {
            if (num>this->currentIndex) {
                MoveTo* action =
MoveTo::create(0.1,
Vec2(150, 500-142-58*num));
                vecItems.at(num)->getTitle()->runAction(action);
            }else{
                MoveTo* action =
MoveTo::create(0.1,
Vec2(150, 500-58*num));
                vecItems.at(num)->getTitle()->runAction(action);
            }
            
        }
    }else{
        for (int num=0; num<this->vecTitles.size(); num++) {
            if (num>this->currentIndex) {
                MoveTo* action =
MoveTo::create(0.1,
Vec2(150, 500-142-58*num));
                vecTitles.at(num)->runAction(action);
            }else{
                MoveTo* action =
MoveTo::create(0.1,
Vec2(150, 500-58*num));
                vecTitles.at(num)->runAction(action);
            }
        }
        //这里调用lua回调函数
        this->luaCallback();
    }
}

void FRAccordion::luaCallback(){
    if (luaHandle>0) {
        LuaStack* stack =
LuaEngine::getInstance()->getLuaStack();
stack->executeFunctionByHandler(luaHandle,
0);
stack->clean();
    }
}

整体流程比较简单,主要是C++和lua交互得情况。luaCallback()正是C++通过lua的函数id(luaHandle)来调用编写在lua上面的函数。下一篇是介绍C++类怎样绑定,使得lua可以调用的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ lua cocos2d