您的位置:首页 > 编程语言 > Lua

2dx-lua游戏震屏效果&简单的lua-binding

2016-05-20 12:14 330 查看
--1.首先要说的是,我这里震屏功能是在c++代码里写的,然后用lua掉用c++代码。其实用lua完全可以实现功能,这里贴上代码:(想看lua掉用c++的,直接看--4.之后)

--

-- Author: Evan

--

local ScreenShaker = class("ScreenShaker")

local scheduler = require("src.framework.scheduler")

function ScreenShaker:ctor(target, time)
self.init_x = 0       --[[初始位置x]]
self.init_y = 0       --[[初始位置y]]
self.diff_x = 0       --[[偏移量x]]
self.diff_y = 0       --[[偏移量y]]
self.diff_max = 8     --[[最大偏移量]]
self.interval = 0.01  --[[震动频率]]
self.totalTime = 0    --[[震动时间]]
self.time = 0         --[[计时器]]

self.target = target
self.init_x = target:getPositionX()
self.init_y = target:getPositionY()
self.totalTime = time

end

function ScreenShaker:run()
self.scheduler = scheduler.scheduleGlobal(function (ft)

    self:shake(ft)

    end, self.interval)

end

function ScreenShaker:shake(ft)
if self.time >= self.totalTime then
self:stop()
return
end
self.time = self.time+ft
self.diff_x = math.random(-self.diff_max, self.diff_max)*math.random()
self.diff_y = math.random(-self.diff_max, self.diff_max)*math.random()
self.target:setPosition(cc.p(self.init_x+self.diff_x, self.init_y+self.diff_y))

end

function ScreenShaker:stop()
self.time = 0

    scheduler.unscheduleGlobal(self.scheduler)

    self.target:setPosition(cc.p(self.init_x, self.init_y))

end

return ScreenShaker

--2.这样写的问题是游戏暂停的时候,屏幕还会继续震动,解决方法是将震屏类设置为一个变量,想震的时候掉用一下run()方法,并给震屏类添加标志暂停标志为,暂停的时候不走shake()方法。

--3.也可以在lua里继承cc.ActionInterval类,为2dx添加新的动作,这里代码省略:

local ScreenShakerA = class("ScreenShakerA", cc.ActionInterval)

--4.接下来说我用的lua掉用c++代码实现游戏震屏效果的方式:

c++代码:

-----1.添加ScreenShaker,因为同样是动作,所以代码我加到了2d/actions/cc.ActionInterval.h 里,写在了文件的最后:

/**

 * @class ScreenShaker

 * @EvanJobs

 */

class CC_DLL ScreenShaker :public
ActionInterval

{

public:

    ScreenShaker();

    

    // Create the action with a time and a strength (same in x and y)

    static ScreenShaker* actionWithDuration(float dt,float strength );

    

    // Create the action with a time and strengths (different in x and y)

    static ScreenShaker* actionWithDuration(float dt,float strength_x,
float strength_y );

    

    bool initWithDuration(float dt,float strength_x,
float strength_y );

    

    virtual void startWithTarget(Node *pTarget);

    virtual void update(float dt);

    virtual
void stop(void);

    

protected:

    // Initial position of the shake node

    float _initial_x, _initial_y;

    // Strength of the action

    float _strength_x, _strength_y;

};

-----2.方法实现,代码添加到2d/actions/cc.ActionInterval.cpp 里:

//Not really used but added for completeness

ScreenShaker::ScreenShaker() : _strength_x(0),_strength_y(0),_initial_x(0),_initial_y(0)

{

}

ScreenShaker* ScreenShaker::actionWithDuration(float dt,
float strength )

{

    // call other construction method with twice the same strength

    

    return actionWithDuration( dt, strength, strength );

}

ScreenShaker* ScreenShaker::actionWithDuration(float dt,float strength_x,
float strength_y)

{

    ScreenShaker *p_action =new
ScreenShaker();

    p_action->initWithDuration(dt, strength_x, strength_y);

    p_action->autorelease();

    

    return p_action;

}

bool ScreenShaker::initWithDuration(float dt,float strength_x,
float strength_y)

{

    if (ActionInterval::initWithDuration(dt))

    {

        _strength_x = strength_x;

        _strength_y = strength_y;

        return true;

    }

    

    return
false;

}

// Helper function. I included it here so that you can compile the whole file

// it returns a random value between min and max included

float fgRangeRand(
float min, float max )

{

    float rnd = ((float)rand()/(float)RAND_MAX);

    return rnd*(max-min)+min;

}

void ScreenShaker::update(float dt)

{

    float randx =fgRangeRand( -_strength_x,_strength_x
);

    float randy =fgRangeRand( -_strength_y,_strength_y
);

    

    _target->setPosition(Vec2(_initial_x,_initial_y)
+ Vec2( randx, randy));

    

}

void ScreenShaker::startWithTarget(Node *pTarget)

{

    ActionInterval::startWithTarget( pTarget );

    

    // save the initial position

    _initial_x = pTarget->getPosition().x;

    _initial_y = pTarget->getPosition().y;

}

void ScreenShaker::stop(void)

{

    // Action is done, reset clip position

    _target->setPosition(Vec2(
_initial_x,_initial_y ) );

    

    ActionInterval::stop();

}

-----3.接下来是注册lua掉用c++的方法,修改:lua_cocos2dx_auto.cpp。(这里顺便说一下,这里可以看到cocos2dx,lua掉用c++的所有基本类的方法,包括ref,node,sprite,touch,texture2D,action等等。该cpp快10w行代码了..)

-----4.frameworks/cocos2d-x/cocos/scripting/lua-bindings/auto/lua_cocos2dx_auto.hpp:

不用修改,该类就一句话:

int register_all_cocos2dx(lua_State* tolua_S);
-----5.frameworks/cocos2d-x/cocos/scripting/lua-bindings/auto/lua_cocos2dx_auto.cpp:(我把代码加到了MoveTo一系列方法后)

/*

 *****************************************************************************************

 *EvanJobs

 */

int lua_cocos2dx_Shaker_actionWithDuration(lua_State* tolua_S)

{

    int argc = 0;

    bool ok  = true;

#if COCOS2D_DEBUG >= 1

    tolua_Error tolua_err;

#endif

    

#if COCOS2D_DEBUG >= 1

    if (!tolua_isusertable(tolua_S,1,"cc.ScreenShaker",0,&tolua_err)) goto tolua_lerror;

#endif

    

    argc = lua_gettop(tolua_S)-1;

    

    do

    {

        if (argc == 2)

        {

            double arg0;

            ok &= luaval_to_number(tolua_S, 2,&arg0, "cc.ScreenShaker:actionWithDuration");

            if (!ok) { break; }

            double arg1;

            ok &= luaval_to_number(tolua_S, 3, &arg1, "cc.ScreenShaker:actionWithDuration");

            if (!ok) { break; }

            cocos2d::ScreenShaker* ret = cocos2d::ScreenShaker::actionWithDuration(arg0,
arg1);

            object_to_luaval<cocos2d::ScreenShaker>(tolua_S, "cc.ScreenShaker",(cocos2d::ScreenShaker*)ret);

            return 1;

        }

    } while (0);

    ok  = true;

    do{

        if (argc == 3) {

            double arg0;

            ok &= luaval_to_number(tolua_S, 2,&arg0, "cc.ScreenShaker:actionWithDuration");

            

            if (!ok) { break; }

            double arg1;

            ok &= luaval_to_number(tolua_S, 3, &arg1, "cc.ScreenShaker:actionWithDuration");

            

            if (!ok) { break; }

            double arg2;

            ok &= luaval_to_number(tolua_S, 3, &arg2, "cc.ScreenShaker:actionWithDuration");

            

            if (!ok) { break; }

            cocos2d::ScreenShaker* ret = cocos2d::ScreenShaker::actionWithDuration(arg0,
arg1, arg2);

            object_to_luaval<cocos2d::ScreenShaker>(tolua_S, "cc.ScreenShaker",(cocos2d::ScreenShaker*)ret);

            return 1;

        }

    }while (0);

    ok  = true;

    luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d", "cc.MoveTo:create",argc, 2);

    return 0;

#if COCOS2D_DEBUG >= 1

tolua_lerror:

    tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_MoveTo_create'.",&tolua_err);

#endif

    return 0;

}

int lua_register_cocos2dx_Shaker(lua_State* tolua_S)

{

    tolua_usertype(tolua_S,"cc.ScreenShaker");

    tolua_cclass(tolua_S,"ScreenShaker","cc.ScreenShaker","cc.ActionInterval",nullptr);

    

    tolua_beginmodule(tolua_S,"ScreenShaker");

    tolua_function(tolua_S,"actionWithDuration",lua_cocos2dx_Shaker_actionWithDuration);

    tolua_endmodule(tolua_S);

    std::string typeName = typeid(cocos2d::ScreenShaker).name();

    g_luaType[typeName] = "cc.ScreenShaker";

    g_typeCast["ScreenShaker"] = "cc.ScreenShaker";

    return 1;

}

/*

 *********************************************************************************************

 */
-----6.添加lua_register_cocos2dx_Shaker()

在 TOLUA_API int register_all_cocos2dx(lua_State*
tolua_S)方法中添加 

lua_register_cocos2dx_Shaker(tolua_S);

我是添加在了MoveTo(toll_S);后面,你们随意。

-----7.lua掉用代码:

    local ss = cc.ScreenShaker:actionWithDuration(0.5, 5)

    self:runAction(ss)

--5.一些注意事项&遇到问题:

-----1.首先说下tolua_cclass(tolua_S,"ScreenShaker","cc.ScreenShaker","cc.ActionInterval",nullptr);

中的”cc.ScreenShaker“,这里最好是写成与c++的类名一致,避免出错。一开始我为了方便写的“cc.Shaker”,后来在lua中"cc.Shaker:actionWithDuration()"之后报错说找不到“cc.Shaker” 。

-----2.lua掉用c++后报参数错误

#if COCOS2D_DEBUG >= 1

    if (!tolua_isusertable(tolua_S,1,"cc.ScreenShaker",0,&tolua_err)) goto tolua_lerror;

#endif
中的tolua_isusertable要根据情况来改变,我这里是需要返回new之后的该类,所以用这个,我之前是复制的代码,用的tolua_isusertype这个,然后lua里会报参数错误。
-----3.这里只是非常简单的lua-binding,因为我把ScreenShaker C++的代码写到了之前已经存在的ActionInterval里,而且lua掉用c++的代码也是写在了lua_cocos2dx_auto.cpp中,省去了很多lua-binding的中间步骤,还是比较简单易懂的。对于想要在cocos2dx引擎上扩展一些相似功能的,或者是给一些类扩展一些方法的,这种做法足够了。

-----4.具体详细的lua-binding步骤还需要自己写一些类似lua_module_register()这种的方法,并且新建的文件也要做一些处理,这里不多做介绍,给上一个比较易懂的地址:
http://www.aichengxu.com/view/45851
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  2dx lua 震屏 binding 效果