返回

JavaScript 幸运掉落系统:高效提升稀有物品概率

javascript

JavaScript物品掉落系统中引入幸运值

一个常见的问题是在物品掉落系统中,如何有效地引入幸运值,让玩家在运气加成下获得更好奖励。本文将探讨这个问题,分析几种解决方案,并提供实现的代码示例。

问题剖析

现有的掉落系统基于一个概率分布。每个物品都有一个掉落几率,当随机数小于某个累计概率时,就掉落对应物品。期望增加“幸运值”能让高稀有物品的出现概率增高,而非仅仅增加掉落的总数量。目前的方案,例如多次 Math.random() 取最大值的方式,在高幸运值情况下会出现性能问题,影响游戏体验。核心问题是找到一种更平滑、更高效地方式提升稀有物品掉落概率。

解决方案一:概率缩放

一种常见做法是根据幸运值,动态缩放物品的概率。当幸运值高时,高稀有度物品的掉落概率增加的幅度应该大于低稀有度物品。这样既能保证概率相对平衡,又不会让高幸运值产生过于悬殊的掉落差异。具体做法是,为每个物品引入一个与幸运值相关的概率放大系数。

const blocks = [
    {
        name: "Iron",
        ratio: 1 / 2,
        luckModifier: 0.5  // 影响概率放大的系数,0.5代表影响较小
    },
    {
        name: "Gold nugget",
        ratio: 1 / 4,
        luckModifier: 0.7  // 中等影响
    },
    {
        name: "Green Amulet",
        ratio: 1 / 10,
        luckModifier: 1.0 // 较大影响
    },
    {
        name: "Red Gem",
        ratio: 1 / 20,
        luckModifier: 1.3 // 很大影响
    },
    {
        name: "Diamond",
        ratio: 1 / 100,
        luckModifier: 1.5 // 极大影响
    }
];


function rollItem(luckIncreasePercentage = 0) {
    const modifiedBlocks = blocks.map(block => {
        const adjustedRatio = block.ratio * (1 + luckIncreasePercentage * block.luckModifier);
        return { ...block, adjustedRatio};
    })
    const totalAdjustedRatio = modifiedBlocks.reduce((sum, item) => sum + item.adjustedRatio, 0);
    let roll = Math.random();
    let cumulativeChance = 0;
     for (let i = 0; i < modifiedBlocks.length; i++) {
         cumulativeChance += modifiedBlocks[i].adjustedRatio/ totalAdjustedRatio;
        if (roll <= cumulativeChance) {
            return modifiedBlocks[i];
        }
    }
}

// 调用示例
console.log(rollItem(0.1)) // 10% 的幸运值

上述代码为每个物品新增 luckModifier 属性,代表幸运值对概率的影响系数。在 rollItem 函数中,我们首先根据幸运值百分比和 luckModifier 调整原始概率,计算出调整后的 adjustedRatio ,然后基于新的概率分布进行抽奖。这样就能在概率层面平滑地增加稀有物品的掉落率。

安全建议luckModifier 的数值应该仔细调整,避免出现过度增幅或无效的加成。通过合理地设置这些系数,可以创建有趣的掉落平衡。同时需要注意:即使使用了“概率缩放”,也需要检查浮点数计算中的精度问题,特别是当幸运值非常高的时候。可以考虑对 adjustedRatio 的极值进行限制。

解决方案二:权重调整

另一种方法是根据幸运值动态调整各个物品的权重。我们可以为每个物品分配一个权重,在抽奖时,根据这个权重选择物品。通过根据幸运值修改每个物品的权重,就可以增加或者减少该物品的掉落概率。这种方式相对于“概率缩放”更灵活, 可以根据特定游戏规则做特殊设置。

const blocks = [
    {
        name: "Iron",
        weight: 100
    },
    {
        name: "Gold nugget",
       weight: 40
    },
    {
        name: "Green Amulet",
        weight: 15
    },
    {
        name: "Red Gem",
        weight: 10
    },
    {
        name: "Diamond",
         weight: 1
    }
];

function rollItemWithWeight(luckIncreasePercentage = 0) {

    const weightedBlocks = blocks.map(block => {
          const adjustedWeight = block.weight * (1+ luckIncreasePercentage * (1/ (blocks.indexOf(block) +1 ) ));
          return {...block, adjustedWeight }
     });
     let totalWeight = weightedBlocks.reduce((sum, item)=>sum +item.adjustedWeight,0)
    let randomNumber = Math.random()*totalWeight
     let currentWeight =0;
     for(let i =0; i< weightedBlocks.length; i++) {
      currentWeight+= weightedBlocks[i].adjustedWeight;
      if(randomNumber <= currentWeight){
        return weightedBlocks[i];
      }
    }
}

//调用示例
console.log(rollItemWithWeight(0.1)) //10%的幸运值

在上述代码中,每个物品有一个 weight 属性。我们根据幸运值百分比动态地修改这些权重。稀有物品的调整系数,相较于普通物品,应当更大,保证在幸运值提升的情况下,获得稀有物品的可能性更大。在抽取物品时,产生一个0到所有调整后的权重的总和的随机数,并通过逐步递增累计权重,直到找到对应的物品。

安全建议: 权重的设定需要小心谨慎,应当防止极少数物品在低幸运值情况下无法掉落或者在高幸运值下总是掉落,避免数值计算溢出。可以尝试使用标准化权重值或调整权重放大公式来保证系统稳定和公平。同时要留意高幸运值带来的副作用,做好防溢出设计,确保即使在高幸运值下,掉落也始终是平缓且有意义的,不要出现非常极端情况。