主站
道具百科
触发器百科
脚本API百科
创作手册
创作功能
其他
Studio百科
使用脚本实现排行榜
迷你世界 更新时间: 2024-02-01 16:27:30
本案例主要使用LUA脚本的方式实现K/V存储和排行榜保持数据功能。

游戏规则说明:

玩家进入游戏杀怪获得10分,被怪物击杀则扣5分,按照得分从高到低进行排序,排行榜展示前3名玩家信息。

 

游戏逻辑说明:

  1. 玩家进入查询自己在排行榜中的排名情况
  2. 没有排名,则查询用户信息表中存储的用户得分,排名情况
  3. 游戏开始后,每隔30秒向服务器上传数据
  4. 点击排行榜按钮,请求排行榜最新数据,展示在界面
  5. 游戏结束,或者玩家离开 将信息提交到排行榜,和用户信息表中

 

实现步骤:

1、变量库配置排行榜表,玩家信息表

在开发者工具 -> 变量库 -> 全局变量 ->新增变量 在弹窗中选择“排行榜”,“表”

 

创建排行榜:在全局变量中新增的排行榜中,将名称命名为“分数排行榜”,脚本引用名称设置为“rank_yang_001”, 后面lua脚本中将会使用它,进行获取云端排行榜数据。

 

创建玩家信息表:在全局变量中新增的表中,将名称命名为“玩家信息表”,脚本引用名称设置为“user_yang_001”,后面lua脚本中将会使用它,进行获取云端玩家信息数据。

在私有变量中创建一个数值私有变量用于存放得分,一个字符串私有变量用于存放排名名称

 

创建score得分私有变量:变量类型:数值, 变量名称设置为“score”,默认值为0。变量名score将在lua脚本中被使用
 
 
创建rank排名名次私有变量:变量类型:字符串, 变量名称设置为“rank”,默认值为"暂未上榜"。变量名rank将在lua脚本中被使用
 
 
 

2、设置界面显示

创建2个界面,一个只有排行榜操作的按钮,此处使用奖杯代替;一个是包含具体排行榜的列表。如下图

 

3、设置游戏中的击杀触发器

在触发器中,创建一个击杀触发器,用于击杀了怪物,玩家的私有变量score增加 10分

 
 
在触发器中,创建一个被击杀触发器,用于被怪物击杀时,玩家的私有变量减5分
 
此处增加了一个条件“如果我玩家的值低于5”则不用再减,避免出现负数的分数
 
 

4、开发者工具中新增脚本

在开发者工具中的脚本中,创建一个脚本,用于处理玩家进入游戏请求自己的数据,以及排行榜数据,定时30秒上传玩家数据,离开游戏,结束游戏时上传玩家数据的脚本。

详细的脚本及解释说明如下,开发者可以根据自己的情况修改脚本中的变量,以便实现自己的逻辑

--定义一个收集玩家的数组
local userAll ={}
local isOver = false
--用于记录当前进入的玩家迷你号
local current_enter_player_id = 0


--获取云服中存储的玩家用户信息回调
--ret   返回结果
--k    当前的迷你号
--v    当前的用户信息表中返回的内容,实例中的格式为: rank:2 score:120

local get_UserData_callback =  function(ret,k,v)
    if ret == true then
        
                --拿到数据后,进行字符串分割
                local myValue = v
                print('当前获取到的用户信息' ..myValue )
                
                local my_rank, my_score = string.match(myValue, 'rank:([0-9]+)score:([0-9]+)')
                
                if(my_rank == 0 and my_rank == 0 )then
                    print('用户信息表中获得到的数据得分为0,初始值不处理')
                    return
                end
                
                --当前玩家的迷你号
                local objid=tonumber(k)         
        local actionattr=3    --变量类型:数值
        --score为变量库中命名的得分,开发者可以根据自己在变量库中设定的内容,进行修改此处
        local msg="score"     
        
        --设置私有数值“score”的值为my_score
        local score_result = VarLib2:setPlayerVarByName(objid,actionattr,msg,my_score)
        if(score_result == ErrorCode.OK)then
            print('设置私有数值“score”的值为my_score  成功~~~~')
        else
             print('设置私有数值“score”的值为my_score  失败~~~~')
        end
        
                local rank_actionattr=4          --变量类型:字符串
                 --rank为变量库中声明的排行榜,开发者可以根据自己在变量库中设定的内容,进行修改此处变量名
        local rank_msg="rank"   
        
        --设置私有数值“rank”为my_rank
        local rank_result = VarLib2:setPlayerVarByName(objid,rank_actionattr,rank_msg,my_rank)
        if (rank_result ==  ErrorCode.OK)then
            print('设置私有数值“rank”为my_rank  成功~~~~')
        else
            print('设置私有数值“rank”为my_rank  失败~~~~')
        end
        else
                print('返回用户信息数据失败')
        end
end


--请求用户信息表中的数据
local getUserTableInfo = function()
    
    --user_yang_001 为变量库中 创建的 用户信息表的脚本索引名称,开发者根据自己的设定进行修改
    local libvarname = 'user_yang_001'
    --将当前进入游戏的玩家迷你号作为请求条件
    local str_player_id = tostring(current_enter_player_id)
  
    --获取玩家的用户信息
    local ret = CloudSever:getDataListByKey(libvarname,str_player_id,get_UserData_callback)
    if ret == ErrorCode.OK then
        print('game 中请求玩家用户数据成功')
    else
         print("game   请求求玩家用户数据失败")
    end
   
end



--获取自己的排名情况返回函数
--ret 返回结果
--k 是迷你号
--v  是得分
--ix 是排名

local get_my_data_callback = function(ret,k,v,ix)
   
    if ret == true then
        --获取数据成功
        local actionattr=3      --变量类型:数值
        --score为变量库中命名的得分,类型为数值
        local msg="score"--变量名
        
        --获取私有数值“数值score”的值,赋值给score_value
        local  numb_player_id = tonumber(k)
        
        local actionattr2=4--变量类型:字符串
        local msg2="rank"--变量名
        
        local my_score = v
        
        --设置当前玩家的私有变量:score得分数据,开发者可以根据自己的设定名称进行更改
        local myscore_result = VarLib2:setPlayerVarByName(numb_player_id,actionattr,msg,my_score)
        if myscore_result ==  ErrorCode.OK then
            --设置成功
            print('game 中 设置得分成功...')
        else
            --设置失败
             print('game 中 设置得分失败...')
        end
        
        local actionattr_rank=4         --变量类型:字符串
        --rank 为变量库中命名的排名,类型为字符
        local msg_rank="rank"       --变量名,可修改
        --获取私有数值“rank”的值,为myrank
        local myrank = ix
        if ix == nil or ix == 0 then
            myrank = "暂未上榜"
        end
        
        local myrand_sult = VarLib2:setPlayerVarByName(numb_player_id,actionattr_rank,msg_rank,myrank)
        if myrand_sult ==  ErrorCode.OK then
            --设置成功
             print('设置排名成功...')
        else
            --设置失败
             print('设置排名失败...')
        end
    else
        --没有获取到信息,则从用户信息表中获取
         getUserTableInfo()
    end
end


--设置目前最新的本地数据到云端排行榜
--new_value: 当前得分
--pl_id: 当前玩家迷你号

local function setNewDataToCloud(new_value,pl_id)
    local libvarname = 'rank_yang_001'
    local player_id = tostring(pl_id)
    
        local ret = CloudSever:setOrderDataBykey(libvarname,player_id,new_value)
        
    if ret == ErrorCode.OK then
                print('Game中  setNewDataToCloud设置排行榜值成功 玩家ID  = ' .. player_id .. '当前得分: ' .. new_value)
        else
                print('Game中  setNewDataToCloud设置排行榜值失败')
    end
end


--给用户信息表上传数据
--user_id  玩家迷你号
--user_rank   当前排行
--user_score    当前得分

local function setUserInfoDataCloud(user_id,user_rank, user_score)
    
    --user_yang_001 为变量库中定义的用户信息表的 脚本引用名称,开发者可以根据自己的设定,修改此名称
    local libvarname = 'user_yang_001'
    --将数据组合成 rank:20 score:120  格式进行保存
    local  m_text = 'rank:'.. user_rank .. 'score:'.. user_score
    local uid = tostring(user_id)
    --调用接口,进行保存信息到云端的用户信息表中
        local ret = CloudSever:setDataListBykey(libvarname,uid,m_text)
    if ret == ErrorCode.OK then
                print('setUserInfoDataCloud设置用户信息值成功 保存信息:' .. m_text)
        else
                print('设置用户信息值失败')
    end
end


--离开和结束公共的设置玩家信息方法
--pl  为迷你号

local function setUserInfoAll(pl)
    
    --如果传来的参数为空,则直接终止
    if pl == nil then
        return
    end
    
    local num_palyer_id = tonumber(pl)
    local actionattr=3--变量类型:数值
    --score为变量库中定义的得分,开发者可以根据自己的设定内容,进行修改此处变量名
    local msg="score"
    
    --获取私有数值“score”的值,赋值给value
    print('Game中 setUserInfoAll中  玩家迷你号==' .. num_palyer_id )
    local result,value = VarLib2:getPlayerVarByName(num_palyer_id,actionattr,msg)
    if(result == ErrorCode.ok)then
        print('Game中   setUserInfoAll中获取数据本地数据前,value==' .. value .. ' num_palyer_id==' .. num_palyer_id )
    end
    
 
    -- 获取私有排行榜
    --rank为变量库定义的排行榜,开发者可以根据自己的设定内容,进行修改此处变量名
    local msg2="rank"
    local actionattr2=4    --变量类型:字符串
    
    local result2,re_rank = VarLib2:getPlayerVarByName(num_palyer_id,actionattr2,msg2)
    if (value ~= nil and re_rank ~= nil and value ~= 0 )then
        --当前得分不是0,即不是初始值
          
        --如果自己的本地数据比最后一名的得分都高,则将分数上传到排行榜服务器.
        --如果分数小于最后一名的得分,则没有必要上传到服务器的排行榜,只需要在离开,或者游戏结束的时候将信息上传到用户信息中即可
        setNewDataToCloud(value,pl)
    
        local str_rank = re_rank
        if(re_rank == "暂未上榜")then
            str_rank = 0
        end
      
        --设置到用户信息表
        if isOver == true then
            --如果是离开游戏,或者游戏结束,则向服务器上传用户信息进行保存
            setUserInfoDataCloud(pl,str_rank, value)
        else
            print('Game中  定时器中,不需要设置用户信息,设置了排行榜就可以了')
        end
    
    else
       --这里就是初始化的时候,无需处理
       print('Game中 获取本地私有变量数据都为空的时候,说明本地没有数据' )
    end
end


--玩家进入游戏,获取排名,获取玩家信息,并设置本地数据rank,score
local function the_EnterGame_callback(e)
    
    local pl = e.eventobjid
    table.insert(userAll,pl)
    --将当前进入玩家迷你号,临时存在变量中,后面回调函数中使用
    current_enter_player_id = pl
    
 
    
   
    --rank_yang_001 为设置的排行榜中脚本的引用名称,开发者可以根据自己的设定,进行修改此命名
    local libvarname = 'rank_yang_001' 
    -- 请求当前进入玩家的排行榜数据
    local my_ret = CloudSever:getOrderDataByKey(libvarname,pl,get_my_data_callback) 
    if my_ret == ErrorCode.OK then
        print('请求自己的排行榜数据成功my_ret == ErrorCode.OK')
    else
        print("请求自己的排行榜数据失败")
        --没有自己的排行榜,则需要去用户信息表中获取信息,进行展示
        getUserTableInfo()
    end
    
end


--{{{ 游戏开始后,时钟每(30ms)执行一次 ,向服务器排行榜进行上传玩家的数据
--[==[
--]==]
--}}}

local function dingShiSetDataForCloud(e)
    local current = e.second
    
    --定时30秒上传一次数据到云端
    if(current ~= nil and current >=30  and (current- 30)%30==0) then
        
       for kv, v in ipairs(userAll)do
           
            setUserInfoAll(v)
       end
    end
end

--如果比赛结束,将玩家的信息保存到云端(排行榜和用户信息表)
local function thegame_end_callback()
   
    isOver = true
    for kv, v in pairs(userAll)do
        setUserInfoAll(v)
    end
    
end

local function the_TeaveGame_callback(e)
    local pl = e.eventobjid
    isOver = true
    setUserInfoAll(pl)
    --从本地数据中移除离开玩家的uin
    table.remove(userAll,pl)
    
end

--向服务器提交数据
ScriptSupportEvent:registerEvent("Game.RunTime",dingShiSetDataForCloud)

--监听游戏结束的事件
ScriptSupportEvent:registerEvent([=[Game.End]=], thegame_end_callback)

--监听玩家离开事件
ScriptSupportEvent:registerEvent([=[Game.AnyPlayer.LeaveGame]=], the_TeaveGame_callback)

--监听玩家进入
ScriptSupportEvent:registerEvent([=[Game.AnyPlayer.EnterGame]=], the_EnterGame_callback)

 
 

5、UI编辑器中新增脚本

在UI编辑中,在第一个仅有"奖杯"的界面的脚本中,创建一个脚本,用于处理玩家点击奖杯请求自己的排行榜情况,以及最新的排行榜数据。
 
详细的脚本及解释说明如下,开发者可以根据自己的情况修改脚本中的变量,以便实现自己的逻辑
--用于存放当前点击的玩家迷你号
local current_click_player_id = 0
--用于存放获取到的云端数据
local cloud_data = nil

--昵称文本控件ID
--开发者可以修改为自己的排行榜界面中第一、二、三...名昵称称控件ID
local txt_name_id = {
  [1] = '7124235295204530136_13',
  [2] = '7124235295204530136_16',
  [3] = '7124235295204530136_17',
}

--得分文本控件ID
--开发者可以修改为自己的排行榜界面中第一、二、三...名得分控件ID
local txt_score_id = {
  [1] = '7124235295204530136_14',
  [2] = '7124235295204530136_18',
  [3] = '7124235295204530136_19',
}



--统一设置第一名~第三名的数据展示
--开发者可以再此处设置自己的排行榜界面数据

local  function setNewDataForUI()
    if(cloud_data ~= nil)then
        local v_value = cloud_data
        local uiid="7124235295204530136" 
        --将当前点击的玩家迷你号,转换为数值类型
        local nu_current_player_id = tonumber(current_click_player_id)
        for ix,  v in ipairs(v_value) do
            local v_score = v.v
            local current_name = v.nick  --这里为获取玩家昵称,开发者可以直接通过v.nick获取到存储在排行榜中对应玩家的昵称
            Customui:setText(nu_current_player_id,uiid,txt_score_id[ix], v_score)
            Customui:setText(nu_current_player_id,uiid,txt_name_id[ix], current_name)
        end
    end
end



--请求排行榜返回的数据
local get_now_data_callback = function (ret,value) -- 返回结果不一定有排名
 
    if ret ~= false  and  value ~= nil then
        --设置排行榜中的界面数据
        --将获取到的数据进行临时存储,以便后面使用
        cloud_data = value
        
        --测试
        setNewDataForUI()
        --获取到了数据,开始将数据显示到界面层
        --setUIData()
        
        --有了数据后,显示排行榜界面
        local result = Player:openUIView(current_click_player_id,'7124235295204530136')
        
    end    
end



--设置玩家自己的数据,展示在界面

local function setMy_Data_InLocal()
    
     --当前需要设置的界面ID,7124235295204530136为排行榜所显示的界面ID,开发者根据自己的界面ID进行修改此处
     local uiid="7124235295204530136" 
     --7124235295204530136_21 为排行榜中排行的控件ID,开发者根据自己的控件ID修改此处
     local element_rank_id='7124235295204530136_21'
      --7124235295204530136_24 为排行榜中玩家的名称的控件ID,开发者根据自己的控件ID修改此处
     local element_nick_id='7124235295204530136_24'
    
 
     local numb_player_id = tonumber(current_click_player_id)
     --获取变量值
    
     local actionattr=3--变量类型:数值
     ----score为变量库中设置的得分名称,开发者可以根据自己的设置进行修改此处
     local msg="score"
     --获取私有数值“score”的值,赋值给value
     local myscore_result,value = VarLib2:getPlayerVarByName(numb_player_id,actionattr,msg)
     if (myscore_result ==  ErrorCode.OK) then
         print('请求玩家的得分数据正确,得分 ==' .. value)
     else
         print('请求玩家的得分数据出错')
     end
     
    local rank_actionattr=4    --变量类型:字符串
    --rank 为变量库中设置排行名称,开发者可以根据自己的设置进行修改此处
    local rank_msg="rank"--变量名
    
     --获取私有数值“rank”的值,赋值给value
    local my_rank_result,my_rank_value = VarLib2:getPlayerVarByName(numb_player_id,rank_actionattr,rank_msg)
    if(my_rank_result == ErrorCode.OK) then
         print('请求玩家的排名数据正确 my_rank_value==' .. my_rank_value)
         
    else
         print('请求玩家的排名数据出错')
    end
    
    
    --开始设置私有数据到界面
    --7124235295204530136_27为界面层 得分的控件ID,开发者可以根据自己的界面,设置控件ID
    local element_score_id='7124235295204530136_27'
    
    local set_score_result = Customui:setText(numb_player_id, uiid, element_score_id, value)
    if set_score_result == ErrorCode.OK then
        print('UI脚本中设置自己的得分成功score_value=' .. value)
    else
        print('UI脚本中设置自己的 得分失败 score_value=' .. value)
    end
    
    --设置名字
    local name_result, my_name = Player:getNickname(numb_player_id)
    local set_name_result = Customui:setText(numb_player_id,uiid,element_nick_id, my_name)
    if(set_name_result == ErrorCode.OK)then
        print('脚本中,设置自己的名称成功my_name ==' .. my_name)
    else
        print('脚本中,设置自己的名称成功')
    end
    
    --设置排名
    if(my_rank_value == 0  or my_rank_value == nil) then
        my_rank_value = "暂未上榜"
    end
    
    local rank_set_result = Customui:setText(numb_player_id,uiid,element_rank_id, my_rank_value)
    if rank_set_result == ErrorCode.OK then
        print('UI脚本中   自己的排行榜设置正常 rank_value .. ' .. my_rank_value)
    else
        print('UI脚本中   自己的排行榜设置失败 rank_value .. ' .. my_rank_value)
    end
    
end

--奖杯点击事件
--开发者可以设置自己的排行榜按钮事件

local function jiangbei_click(e)
    local pl = e.eventobjid
    
    --是不是自己设置的排行榜按钮,如果不是就直接不处理
    --7124254390629128152_1 为界面层上排行榜按钮,用于点击,开发者根据自己的排行榜按钮进行修改此处
    if( e.btnelenemt ~= '7124254390629128152_1')then
        return
    end
    
    --当前点击的玩家迷你号,用于回调的时候使用
    current_click_player_id = pl

    -- rank_yang_001 为变量库中设置的排行榜表的,脚本接口引用名称,开发者根据自己的设置,修改此处
    local libvarname = 'rank_yang_001' 
    

    --玩家进入游戏,请求从大到小排序的前3名的数据;如果需要从小到大的排序,则将-3修改为3. 
    --开发者可以根据自己的设置的排行榜一共是多少名来设置该数字,直接取到前面多少名。
    local ret = CloudSever:getOrderDataIndexArea(libvarname,-3,get_now_data_callback) 
    if ret == ErrorCode.OK then
        
        print('请求排行榜数据成功ret == ErrorCode.OK')
    else
        print("请求排行榜数据失败")
    end
    
    --设置进入的玩家自己的信息
    setMy_Data_InLocal()
end


--监听点击事件
ScriptSupportEvent:registerEvent([=[UI.Button.Click]=],jiangbei_click)
开发者可以按照以上步骤,拷贝相应的LUA脚本运行Demo,通过此Demo对排行榜的使用有一个更加深入的了解。在此基础之上,开发者可以设计、增加自己的游戏逻辑,使得地图玩法更加丰富。
站点有内容要更新是否更新。
更新
忽略