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

[lua] 游戏客户端逻辑使用lua协程

2020-02-17 00:43 435 查看

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

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

转载于:https://www.cnblogs.com/AlphaAI/p/6443421.html

  • 点赞
  • 收藏
  • 分享
  • 文章举报
dikao8849 发布了0 篇原创文章 · 获赞 0 · 访问量 50 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: