[网游客户端业务逻辑] unity下使用lua开发业务逻辑

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[网游客户端业务逻辑] unity下使用lua开发业务逻辑相关的知识,希望对你有一定的参考价值。

  我们的游戏有这样一种情景:客户端中角色需要用到一些公会的数据,但服务器不会在玩家(创角后)一进入到游戏里就推送给玩家,而是需要客户端自己在需要的时候向服务器请求公会的数据,之前的实现就是在请求消息的时候加一个回调函数,消息一回来就执行回调函数继续后续的业务!但后面发现存在这样的不足:

1.有时会用到好多个参数,这就需要每次都把一些无关的参数传给消息请求者,然后回调过来再把这些参数原封不动地传回来,很繁琐;

2.这样的回调写法感觉很不符合人类的顺序思维习惯,有点乱;

回调的lua代码写法类似:

--@callbackFunc带的参数可能有(self, p1, p2, ..., [最后还有allianceData, 这个是取到数据后分发时加上的])

function AllianceProxy:requestAllianceData(callbackFunc)

  --handle send request msg

  --这里使用一个uniqueKey往一个管理器中注册保存这个回调

end

function AllianceProxy:responseAllianceData(allianceData)

  --handle receive response msg

  --这里根据上面uniqueKey分发消息,执行回调, 调用类似:callbackFunc(self, p1, p2, ..., allianceData)

end

--请求公会数据的写法就是这样:

function Role:handleAllianceData()

  local function _callbackFunc(self, p1, p2, allianceData)

    --使用的到allianceData处理相关的业务逻辑

  end

  AllianceProxy:requestAllianceData(packing(_callbackFunc, self, p1, p2)) --packing返回的仍然是一个function

end

 

上述的参数self, p1, p2, ...等等完全就没必要往requestAllianceData中丢过去的,但就是因为收到回调后需要用到,作为强迫症的我,觉得这种写法很恶心,所以今天想到,这完全可以利用lua提供的协程机制来做这件事,大致思路的代码如下:(注:下面这些代码未经过编译及测试,另外还未考虑协程恢复执行时若其主函数所在table被销毁的情况, 后续会完善下面的代码)

--创建并运行一个协程
--@param mainFunc 协程主函数
function global:createAndRunningCo(mainFunc)
    self:assertFmt(type(mainFunc) == function, func=%s is not function, tostring(mainFunc))
    local co = coroutine.create(mainFunc)
    local isSuccess, errMsg = coroutine.resume(co, co)
    self:assertFmt(isSuccess, one error happened in mainFunc:%s, errMsg)
end

function global:checkCoIsRunning(co)
    self:assertFmt(type(co) == thread)
    local curCo = coroutine.running()
    self:assertFmt(co == curCo, co[%s] is not running, current running coroutine is %s, please sure that co is running, co, curCo)
end

function global:yieldAndSaveCo(key, co)
    self:assertFmt(key ~= nil)
    self:checkCoIsRunning(co)

    if coT[key] == nil then
        coT[key] = {}
    end

    table.insert(coT[key], co)

    return coroutine.yield()
end

function global:resumeAndRemoveCo(key, ...)
    if coT[key] then
        for _, co in ipairs(coT[key]) do
            if coroutine.status(co) == suspended then
                local isSuccess, errMsg = coroutine.resume(co, ...)
                self:assertFmt(isSuccess, one error happened in mainFunc:%s, errMsg)
            end
        end
        coT[key] = nil
    end
end
local global = require(global)

global:createAndRunningCo(function(co)
    local allianceData = Alliance:requestAllianceData(co)

    --do something
end)

function AllianceProxy:requestAllianceData(co)
    --send msg : request alliance Data

    return global:yieldAndSaveCo(allianceData, co)
end

function AllianceProxy:responseAllianceData(allianceData)
    --receive msg : response alliance data

    global:resumeAndRemoveCo(allianceData, allianceData)
end

需要获取公会数据的用户就使用下面这样的写法则可:

global:createAndRunningCo(function(co)
    local allianceData = Alliance:requestAllianceData(co)

    --do something
end)
然后在消息收发那里做好相应的处理就行了,这个写法跟前面的对比,很明显,我们顺序的编写相应的逻辑就行了,完全不需要像前面的说等回调过来后反过头来再执行相应的逻辑
 

以上是关于[网游客户端业务逻辑] unity下使用lua开发业务逻辑的主要内容,如果未能解决你的问题,请参考以下文章

如何评价腾讯在Unity下的xLua热更方案

Lua与Unity的内存优化技术

[Unity XLua]热更新XLua入门-俄罗斯方块实例篇

高效使用lua作为业务开发语言的秘诀在这里!

游戏开发解答Unity使用lua将table转为树结构,以多级折叠内容列表的UI形式展现(树结构 | UGUI | 折叠展开 | lua)

游戏开发解答Unity使用lua将table转为树结构,以多级折叠内容列表的UI形式展现(树结构 | UGUI | 折叠展开 | lua)