實作最基本的開局建造順序

| Chrono Divide | 6 Reads

以下程式碼片段示範如何在 @chronodivide/game-api 中實作最基本的開局建造順序:展開基地車、建造並放置電廠 → 兵營 → 礦場 → 戰車工廠。
倉庫裡可看到 Allied 建築名稱的定義,以及展開 MCV 時呼叫 OrderType.DeploySelected 的做法。

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

import { getDefaultPlacementLocation } from "./bot/logic/building/buildingRules.js";

class BasicBuildBot extends Bot {
  private readonly buildOrder = ["GAPOWR", "GAPILE", "GAREFN", "GAWEAP"];
  private nextIndex = 0;

  // 開局展開基地車
  override onGameStart(game: GameApi) {
    const mcv = game.getVisibleUnits(this.name, "self", r => !!r.deploysInto)[0];
    if (mcv) {
      this.actionsApi.orderUnits([mcv], OrderType.DeploySelected);
    }
  }

  // 每個遊戲刻檢查建造佇列並依序建造
  override onGameTick(game: GameApi) {
    const queue = this.productionApi.getQueueData(QueueType.Structures);

    // 佇列空閒時,加入下一個建築
    if (queue.status === QueueStatus.Idle && this.nextIndex < this.buildOrder.length) {
      const buildName = this.buildOrder[this.nextIndex];
      this.actionsApi.queueForProduction(
        QueueType.Structures,
        buildName,
        ObjectType.Building,
        1
      );
    }

    // 完成建造後嘗試放置
    if (queue.status === QueueStatus.Ready && queue.items.length > 0) {
      const rules = queue.items[0].rules;
      const pos = getDefaultPlacementLocation(
        game,
        game.getPlayerData(this.name),
        game.getPlayerData(this.name).startLocation,
        rules
      );
      if (pos) {
        this.actionsApi.placeBuilding(rules.name, pos.rx, pos.ry);
        this.nextIndex++;  // 進入下一個建築
      }
    }
  }
}

// 初始化並建立離線遊戲
async function main() {
  await cdapi.init("/path/to/ra2/files");
  const game = await cdapi.createGame({ mapName: "heckcorners.map", online: false,
                                        agents: [new BasicBuildBot("AI", "Americans")] });
  while (!game.isFinished()) {
    await game.update();
  }
  game.saveReplay();
  game.dispose();
}

main().catch(console.error);

此範例僅實作最簡單的建造流程,實際使用時可依需求再擴充防禦、任務等其他邏輯。上述程式碼示範了如何透過 orderUnits 讓 MCV 展開,以及如何利用 queueForProductionplaceBuilding 按照陣列中的建築名稱逐步建造與放置。

 

目前專案supalosa-chronodivide-bot的自動建築邏輯位於 src/bot/logic/building/buildingRules.ts

函式 getDefaultPlacementLocation() 會從己方建築周圍搜尋可放置格子,再依據與指定起始點的距離排序,由近到遠逐一測試是否可以放置,找到第一個可放置的位置就回傳。

當生產隊列完成某個建築時,QueueController.getBestLocationForStructure() 會調用各建築的 getPlacementLocation()(預設即 getDefaultPlacementLocation),決定實際放置的座標,之後再呼叫 actionsApi.placeBuilding() 進行放置。

若想避免建築聚在一起,可在 getDefaultPlacementLocation() 的基礎上,新增一個搜尋「距離最遠」的版本,例如遍歷候選格子後依距離由遠到近排序,再挑第一個可放置的格子。如此即可在程式裡提供「自動最遠放置」的選項。而若要手動指定格子,只需直接呼叫 actionsApi.placeBuilding(建築名稱, rx, ry) 即可。

整體流程概述:

  1. 依需求選擇呼叫「最近」或「最遠」的尋點函式。

  2. actionsApi.placeBuilding() 用來真正把建築放到指定座標。

代碼中已有詳細的註釋與邏輯,可根據上述位置進一步閱讀或擴充。使用者也可在自己的 Bot 裡覆寫相關方法,以滿足特定的放置策略。

 

→返回《Chrono Divide Bot 開發指南》

This article was last edited at