抽卡系统-欧皇还是非酋?

前言

万恶的抽卡系统到底怎么回事?为啥我什么都抽不到?抽到都是蓝天白云,什么时候是闪光最佳抽卡时机,SSR,SP为何与我无缘?一位从业多年,头发渐无的老者来解析其中缘由。

随机机制

所有的抽卡逻辑都是写在服务端,服务端一般会有全服统一的一个随机数生成器,我们这里的随机数生成器本身就是伪随机。开服时,一般以时间作为随机种子。策划会对所有可以抽出来的道具设置权重,比如某个池子一共只有A,B,C三个道具,权重为10,20,70,先计算总权重为100,然后随机一个[0,100)的数,[0,10)区间是A道具,[10,30)区间为B道具,[30,100)为C道具。参考lua代码如下:

math.randomseed(os.time())
local function draw_card(item_libs,probs,count)
    if not count then
        count = 1
    end
    assert(#item_libs == #probs, "item list length must equal to probs length")
    local sum = 0
    for _, prob in pairs(probs) do
        sum = sum + prob
    end
    local result = {}
    for _ = 1, count do
        local rand_value = math.random() * sum -- [0,sum)
        local s = 0
        local select_index = 1
        for index, prob in pairs(probs) do
            s = s + prob
            if rand_value < s then
                select_index = index
                break
            end
        end
        table.insert(result, item_libs[select_index])
    end
    return result
end
local result = draw_card({"A","B","C"},{10,20,70},10)

大致的流程是这样,不过,里面的花样繁多,最终的实际概率基本和游戏中显示的抽卡概率不一致。
根据不同的花样,我大致分为以下几类:

  1. 限量抽取
  2. 分库抽取
  3. 保底机制
  4. 老虎机
  5. 限时UP
  6. 全凭人品
  7. 诺亚幻想大建

限量抽取

什么是限量抽取?比如某个道具A,策划限定每天全服务器最多出10个,每个抽出来概率为0.1%,那么玩家把10个都抽完之后,每个抽出来概率就为0了,后面的玩家怎么抽都不会抽到。这种情况下,如果想抽到,那么必须在刷新后马上抽。一般刷新时间为凌晨0点,或者早上6点,不同的游戏不一样,一个游戏玩的久了大家就都清楚刷新时间了。一些限量的周边或者极其稀有的道具抽取活动会采用此类抽卡方式。限量抽取参考lua代码如下:

local item_limit = {A = 1} -- 全服当天只能抽取一个A
math.randomseed(os.time())
local function draw_card(item_libs,probs,count)
    if not count then
        count = 1
    end
    assert(#item_libs == #probs, "item list length must equal to probs length")
    local sum = 0
    for _, prob in pairs(probs) do
        sum = sum + prob
    end
    local result = {}
    for _ = 1, count do
        local rand_value = math.random() * sum -- [0,sum)
        local s = 0
        local select_index = 1
        for index, prob in pairs(probs) do
            s = s + prob
            if rand_value < s then
                select_index = index
                break
            end
        end
        local item = item_libs[select_index]
        if item_limit[item] > 0 then -- 判断是否抽完了
            item_limit[item] = item_limit[item] - 1
        else
            item = draw_card(item_libs, probs, 1) -- 重新抽取
        end
        table.insert(result, item)
    end
    return result
end
local result = draw_card({"A","B","C"},{10,20,70},10)

分库抽取

这里的库,就是英雄池了,拿《剑与远征》举例,有种族库,紫卡库,神魔库,先随机一次,根据随机结果决定去哪个库,然后再随机一次,决定随出库中的哪个英雄。不同的英雄在库中设计的权重也不一样,还有可能随时调整,调整了玩家也不知道。所以,强力的英雄最终抽到的概率会很低。分库抽取参考lua代码如下:

local all_libs = {
    lib1 = {A = 10,B = 20,C = 70},
    lib2 = {D = 10,E = 20,F = 70},
    lib3 = {G = 10,H = 20,I = 70},
}
local libs_probs = {lib1 = 5,lib2 = 10,lib3 = 85}
math.randomseed(os.time())
local function draw(libs,probs,count)
    if not count then
        count = 1
    end
    assert(#libs == #probs, "item list length must equal to probs length")
    local sum = 0
    for _, prob in pairs(probs) do
        sum = sum + prob
    end
    local result = {}
    for _ = 1, count do
        local rand_value = math.random() * sum -- [0,sum)
        local s = 0
        local select_index = 1
        for index, prob in pairs(probs) do
            s = s + prob
            if rand_value < s then
                select_index = index
                break
            end
        end
        local item = libs[select_index]
        table.insert(result, item)
    end
    return result
end

local function get_lib_probs(lib_probs)
    local libs = {}
    local probs = {}
    for k,v in pairs(lib_probs) do
        table.insert(libs,k)
        table.insert(probs,v)
    end
    return libs, probs
end

local function draw_with_lib(lib_probs)
    local libs,probs = get_lib_probs(lib_probs)
    local lib = draw(libs,probs)
    local result = {}
    for _, v in pairs(lib) do
        local item_lib = all_libs[v]
        local item_libs, item_probs = get_lib_probs(item_lib)
        local single_result = draw(item_libs, item_probs)
        table.insert(result, single_result[1])
    end
    return result
end

local result = draw_with_lib(libs_probs)

保底机制

保底我相信大家都很熟悉了,这个是专为非酋玩家准备的,脸比较黑的玩家真的是抽不到好东西,为了优化玩家整体抽卡体验,很多游戏都推出了保底机制,比如50连保底,解释为连续49次未抽中,则第50次必定出。这里必定出,是出什么呢,有可能是出固定的英雄库,也有可能是必出某个英雄。在程序中,会有一个计数器,计数玩家当前的抽卡未中次数,一般很有可能有多个计数器,每个英雄池子单独计数,并且,只要抽中了,那么计数就会清零。现在,问题来了。

  • 正常抽中概率1%,50次保底,假设玩家抽无限次,那么抽到的平均概率是多少?

上代码:

math.randomseed(os.time())
local LUCKY_LIMIT = 50
local lucky_count_map = { A = 0} -- 保底计数
local bingle_count = 0 -- 抽到A的总次数
local draw_count = 10000000 -- 总共抽1千万次
local function draw_card(item_libs,probs,count)
    if not count then
        count = 1
    end
    assert(#item_libs == #probs, "item list length must equal to probs length")
    local sum = 0
    for _, prob in pairs(probs) do
        sum = sum + prob
    end
    -- local result = {}
    for _ = 1, count do
        local rand_value = math.random() * sum -- [0,sum)
        local s = 0
        local select_index = 1
        for index, prob in pairs(probs) do
            s = s + prob
            if rand_value < s then
                select_index = index
                break
            end
        end
        local item = item_libs[select_index]
        if item == "A" then
            lucky_count_map.A = 0
            bingle_count = bingle_count + 1
        else
            lucky_count_map.A = lucky_count_map.A + 1
            if lucky_count_map.A == LUCKY_LIMIT then
                item = "A"
                bingle_count = bingle_count + 1
                lucky_count_map.A = 0
            end
        end
        -- table.insert(result, item)
    end
    -- return result
end
draw_card({"A","B","C"},{1,29,70},draw_count)
print(bingle_count / draw_count)

运行结果 0.025303,加上保底后平均概率约为 2.53%,由此可见,保底机制大大增加了抽卡抽到的概率,有保底机制的游戏大大的良心。再拿《剑与远征》举例,游戏内公示的概率为:
卡池概率
注意,这里是卡池的概率,是上一小节介绍的分库抽取的模式,不过不影响保底的计算。我们可以用程序反推其英雄卡池的权重。已知精英级英雄30连保底,精英级英雄卡池概率4.61%,稀有级43.70%,普通级英雄51.69%,求所有卡池的整数权重(策划一般都是配置的整数)。我的计算结果为:1587 1342 71,怎么得出来的呢?我试出来的,用牛顿逼近法。。这个概率用公式我还不知道怎么计算。如果有朋友知道,麻烦在评论区留言,非常感谢。

老虎机

老虎机是一种赌博的机器,这种机器有一种机制,它会慢慢吃掉你的筹码,然后累计到一定量,然后吐出来一部分。这一部分占多少比例呢?每个老虎机可以自己设置,比如吃掉1000,吐50。稳赚不赔。
在游戏里面,抽卡也有老虎机模式:全服玩家抽卡花掉的钻石总数达到一个配置的上限,才会吐出来SSR,SP,在这之前,不好意思,抽出来概率为0.
这种机制虽然比较恶心,但是初期一般都看不出来,需要比较多的抽之后,慢慢才会被玩家发现。玩家发现之后,一般都是,看到系统公告,有人出SSR了,就马上去抽。错过了就充当垫子了。
玩家还是比较讨厌这种机制的,那为啥很多游戏还是用老虎机模式呢?我个人认为,老虎机可以保证稳定的收益计算,策划设计起来更省事。
老虎机模式可以看作是动态版本的限量抽取,收到一定钻石之后,限量值会动态变化一次,这时候就是限量放送,限量值为0后,又需要等待下一次的钻石累计,如此循环。
参考lua代码如下:

local item_limit = {A = 0}
local diamond_sum = 0 -- 钻石累计
local diamond_limit = 100000  -- 钻石收到10万后放送
local bingle_count = 0
math.randomseed(os.time())
local function draw_card(item_libs,probs,count)
    if not count then
        count = 1
    end
    assert(#item_libs == #probs, "item list length must equal to probs length")
    local sum = 0
    for _, prob in pairs(probs) do
        sum = sum + prob
    end
    local result = {}
    for _ = 1, count do
        diamond_sum = diamond_sum + 300
        if diamond_sum > diamond_limit then
            item_limit.A = 10
            diamond_sum = 0
        end
        local rand_value = math.random() * sum -- [0,sum)
        local s = 0
        local select_index = 1
        for index, prob in pairs(probs) do
            s = s + prob
            if rand_value < s then
                select_index = index
                break
            end
        end
        local item = item_libs[select_index]
        if item_limit[item] then
            if item_limit[item] > 0 then -- 判断是否抽完了
                item_limit[item] = item_limit[item] - 1
            else
                item = draw_card(item_libs, probs, 1) -- 重新抽取
            end
        end
        if item == "A" then
            bingle_count = bingle_count + 1
        end
        table.insert(result, item)
    end
    return result
end
draw_card({"A","B","C"},{10,20,70},1000)
print(bingle_count)

限时UP

限时UP一般出现在活动中,分两种,一种是卡池的概率UP,一种是卡池内部特定英雄的概率UP。两种都是在原有的权重基础上乘以一个参数。一般活动描述的XXX英雄概率提升100%,那么就是权重提高2倍。这个很好理解,代码上修改也比较简单,这里就不贴代码了。

全凭人品

有些游戏,一点花样都没有,非常干净,这就是全凭人品。不过我这个标题还有另一个意思,只要不是老虎机,欧皇永远是欧皇,这个非酋真没法比。还有就是,网上流传的伪随机初始号,每个号的人品都不一样,这种说法。是谣言,在服务器程序里,每个号都是平等的。

诺亚幻想大建

这个标题有点奇怪,因为诺亚幻想的抽卡机制是另类的,特殊的,居然还受玩家控制的!!详情请查看诺亚幻想抽卡系统

总结

很多游戏里面都是以上各种花样的结合体,希望对大家有所帮助。如果还有我没见过的花样,欢迎大家留言告知。祝大家抽卡顺利,游戏愉快。

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值