GameApi.generateRandomInt(min, max)、generateRandom()

| Chrono Divide | 4 Reads

以下為 GameApi 中隨機數相關方法的介面定義,位於封裝後套件的 index.d.ts

/**
 * Generates a random integer in the specified [min, max] interval using the internal PRNG.
 * Must be used instead of Math.random() when computing game state to prevent desyncs between clients
 */
generateRandomInt(min: number, max: number): number;

/**
 * Generates a random float in the [0,1) interval using the internal PRNG.
 * Must be used instead of Math.random() when computing game state to prevent desyncs between clients
 */
generateRandom(): number;

其壓縮後實作顯示:若當前環境已存在內部隨機產生器,就調用該 PRNG;否則回退至 Math.random

...ai.getIni()}
generateRandomInt(e,t){
  if(Mp(this,Fp,"f"))
    return Mp(this,Lp,"f").generateRandomInt(e,t);
  var i=this.generateRandom();
  return Math.round(i*(t-e))+e
}

generateRandom(){
  return Mp(this,Fp,"f") ? Mp(this,Lp,"f").generateRandom() : Math.random()
}

專案中的使用情境

於地圖模組中,依隨機角度與半徑計算候選位置:

): Vector2 {
    // TODO: Use proper vector maths here.
    let radius = minRadius + Math.round(gameApi.generateRandom() * (maxRadius - minRadius));
    let directionToEndLocation = GameMath.atan2(endLocation.y - startLocation.y, endLocation.x - startLocation.x);
    let randomisedDirection =
        directionToEndLocation -
        (randomAngle * (Math.PI / 12) + 2 * randomAngle * gameApi.generateRandom() * (Math.PI / 12));
    let candidatePointX = Math.round(startLocation.x + GameMath.cos(randomisedDirection) * radius);
    let candidatePointY = Math.round(startLocation.y + GameMath.sin(randomisedDirection) * radius);

在攻擊任務裡以隨機方式決定目標:

try {
    const tryFocusHarvester = gameApi.generateRandomInt(0, 1) === 0;
    ...
    if (unexploredEnemyLocations.length > 0) {
        const idx = gameApi.generateRandomInt(0, unexploredEnemyLocations.length - 1);
        return unexploredEnemyLocations[idx].startLocation;
    }

基本範例

以下程式展示如何在 Bot 中使用這兩個方法產生隨機行動:

import { cdapi, Bot, GameApi } from "@chronodivide/game-api";

class RandomMoveBot extends Bot {
    onGameStart(game: GameApi) {
        const mapSize = game.mapApi.getRealMapSize();
        // 隨機取得一個可用位置
        const rx = game.generateRandomInt(0, mapSize.width - 1);
        const ry = game.generateRandomInt(0, mapSize.height - 1);
        console.log(`Target tile: (${rx}, ${ry})`);

        // 使用浮點隨機值決定是否下達額外指令
        if (game.generateRandom() < 0.3) {
            console.log("Performing a special move!");
            // ...
        }
    }
}

async function main() {
    await cdapi.init(process.env.MIX_DIR!);
    await cdapi.createGame({
        agents: [new RandomMoveBot("RNG", "Americans")],
        mapName: "mp03t4.map",
        shortGame: true,
        online: false,
    });
}

main().catch(console.error);

generateRandomInt(min, max) 回傳含頭含尾的整數,而 generateRandom() 回傳 [0,1) 區間的浮點數。官方註解強調,在可能影響遊戲狀態的邏輯中應避免直接使用 Math.random(),以免多個客戶端產生隨機結果不一致而導致不同步。此範例於遊戲啟動時隨機選擇一格位置,並依機率決定是否執行額外行動,說明了這些方法的典型用法。

 

→返回《@chronodivide/game-api 使用教學與完整 API 對照表》

This article was last edited at