权重随机算法,解决游戏中一切可控随机(刷怪、掉宝、转盘、抽卡等等)

分享个权重算法吧,使用场景还是比较多的。
例如:游戏里有狮子、老虎、毒蛇、大象、鳄鱼5种怪物,每次刷怪都是按照概率随机。
权重算法可以随心所欲得控制每种怪物的刷新概率,做法如下:
1、设置每种怪物的权重,例如:
狮子5,老虎8,毒蛇12,大象3,鳄鱼17
2、计算权重之和
5+8+12+3+17 = 45
3、想象一把全长45的尺子,上面有5个刻度
image
5,13,25,28,45(每两个刻度之间的距离,刚好是权重)
4、随机一个0~45的数字,落在哪个刻度区间,就随出哪个怪物。
每种怪的刷新概率,完全与权重大小成正比。
5、改变怪物权重,可以随时改变他的刷新概率


例如:第二关想增加难度,就把老虎的权重从8增加到18
那么尺子就变长了,老虎的刻度也变长了,老虎刷新概率提高了。

使用方法:
1、初始化权重
let wt = weight();
wt.add(‘狮子’,5);
wt.add(‘老虎’,8);
wt.add(‘毒蛇’,12);
wt.add(‘大象’,3);
wt.add(‘鳄鱼’,17);
2、根据权重,获取随机ID
let enemy = wt.get();
这个enemy就是随机刷出的怪物名称
3、要增加毒蛇的刷新概率
wt.add(‘毒蛇’,10); //这样毒蛇的权重 = 12+10 = 22
4、要减少鳄鱼的刷新概率
wt.add(‘鳄鱼’,-15); //这样鳄鱼的权重 = 17-15 = 2
权重算法适用于任何精准操控概率的随机场景,例如刷怪、掉宝、怪物AI等等。
以下是可复制的源码:

export class Weight {

    total: number = 0;

    keys: string[] = [];

    values: number[] = [];

    add(key: string, value: number) {

        let len = this.keys.length

        for (let i = 0; i < len; ++i) {

            if (this.keys[i] === key) {

                if (value < 0) {

                    let wt = i === 0 ? this.values[i] : this.values[i] - this.values[i - 1];

                    if (wt < -value) {

                        value = -wt;

                    }

                }

                for (let j = i; j < len; ++j) {

                    this.values[j] += value;

                }

                this.total += value;

                return;

            }

        }

        value = Math.max(value, 0);

        this.keys[len] = key;

        this.values[len] = this.total + value;

        this.total += value;

    }

    get(): string {

        let rd = gi.random(this.total);

        for (let i = 0, len = this.keys.length; i < len; ++i) {

            if (rd < this.values[i]) {

                return this.keys[i];

            }

        }

        return null;

    }

}

export function weight(obj?: Object): Weight {

    let ret = new Weight();

    if (obj) {

        ret.keys = Object.keys(obj);

        for (let i = 0, len = ret.keys.length; i < len; ++i) {

            ret.values[i] = ret.total + obj[ret.keys[i]];

            ret.total += obj[ret.keys[i]];

        }

    }

    return ret;

}
2赞

gi.random是什么库?

【包教包会】CocosCreator怎么用namespace实现类似于cc的全局变量
这里

:ok_hand:收到

优化了一版,功能不变,但更简洁。
export class Weight {
private items: any[] = [];
private weights: number[] = [];
private totalWeight: number = 0;
add(item: any, weight: number) {
let id = this.items.indexOf(item);
if (id === -1) {
weight = Math.max(weight, 0);
this.items.push(item);
this.weights.push(weight);
} else {
weight = Math.max(-this.weights[id], weight);
this.weights[id] += weight;
}
this.totalWeight += weight;
}
get(): any {
let rd = Math.random() * this.totalWeight;
for (let i = 0, len = this.items.length; i < len; ++i) {
if (rd < this.weights[i]) {
return this.items[i];
}
rd -= this.weights[i];
}
return null;
}
}

5赞

马克巴卡巴卡

/**
 * 从对象池里抽出N个对象,每个对象抽取的概率有它自身权重决定。
 * @param arr 需要操作的对象池
 * @param count 需要取的个数
 * @returns 抽取到的对象数组
 */
static weight(arr: {weight?: number; [other: string]: any}[], count: number = 1){
    let tempArr:{weight?: number}[] = []
    for (let e of arr){
        if (e.weight){
            tempArr.push(e)
        }
    }
    // tempArr.push(...arr)

    if (tempArr.length == 0){
        cc.error("arr.length == 0")
        return [];
    }

    let newArr:{weight?: number; [other: string]: any}[] = []

    let curCount: number = 0;
    while(curCount < count && tempArr.length > 0){
        let totalWeight = 0;
        for (let e of tempArr){
            totalWeight += (e.weight || 1) ;
        }

        for (let i = 0; i < tempArr.length; i++){
            if ( this.weightBingo(tempArr[i].weight || 1, totalWeight) ){
                newArr.push(tempArr[i]);
                tempArr.splice(i, 1)
                break;
                // return tempArr[i];
            }
            else{
                totalWeight -= (tempArr[i].weight || 1);
            }
        }
        curCount++;
    }

    if (newArr.length == 0){
        cc.error("weight error", newArr)
    }
    return newArr;
}

我感觉我这样更好用

有句话叫“母不嫌子丑” :laughing: