MapApi.getTileResourceData(tile) / getAllTilesResourceData()

| Chrono Divide | 6 Reads

MapApi.getTileResourceData(tile)getAllTilesResourceData() 均由套件 @chronodivide/game-api 提供,用來查詢地圖上資源(礦石、寶石或礦井)的資訊。

在型別定義檔可看到這兩個方法的宣告,回傳型別為 TileResourceData

isVisibleTile(tile: Tile, playerName: string, tileElevation?: number): boolean;
getTileResourceData(tile: Tile): TileResourceData | undefined;
getAllTilesResourceData(): TileResourceData[];

TileResourceData 結構包含資源位置與數量等欄位:

export declare interface TileResourceData {
    tile: Tile;
    /** Number of gem bails */
    gems: number;
    /** Number of ore bails */
    ore: number;
    /** Is this a mining drill? (tiberium tree) */
    spawnsOre: boolean;
}

實作摘要

在編譯後的程式碼中,getTileResourceData 會先檢索目標格上的物件,只要該物件是資源覆蓋層(Tiberium overlay)或會產生資源的地形,即會將其轉換成 TileResourceData;若找不到則回傳 undefinedgetAllTilesResourceData 則遍歷全地圖所有物件並收集上述資料:

...getTileResourceData(e){
    e = Op(this,Cp,"f").getObjectsOnTile(e)
        .find(e => e.isOverlay() && e.isTiberium() || e.isTerrain() && e.rules.spawnsTiberium);
    return e ? Op(this,Ap,"m",Bp).call(this,e) : void 0;
}

getAllTilesResourceData(){
    var e;
    let t = [];
    for (e of Op(this,Ip,"f").getWorld().getAllObjects()) {
        var i = Op(this,Ap,"m",Bp).call(this,e);
        i && t.push(i);
    }
    return t;
}

Bp = function(t){
    let i;
    if (t.isOverlay() && t.isTiberium()) {
        let e = t.traits.get(Qa);
        var s = e.getTiberiumType(), r = e.getBailCount();
        i = {
            tile: t.tile,
            ore: s === la.Ore ? r : 0,
            gems: s === la.Gems ? r : 0,
            spawnsOre: !1
        };
    } else if (t.isTerrain() && t.rules.spawnsTiberium) {
        i = {
            tile: t.tile,
            ore: 0,
            gems: 0,
            spawnsOre: !0
        };
    }
    return i;
}

使用實例

本專案在尋找最近的礦石位置時,會先取得全部資源資料並比對距離:

var closeOre: Tile | undefined;
var closeOreDist: number | undefined;
let allTileResourceData = game.mapApi.getAllTilesResourceData();

for (let i = 0; i < allTileResourceData.length; ++i) {
    let tileResourceData = allTileResourceData[i];
    if (tileResourceData.spawnsOre) {
        let dist = GameMath.sqrt(
            (selectedLocation.x - tileResourceData.tile.rx) ** 2 +
            (selectedLocation.y - tileResourceData.tile.ry) ** 2,
        );
        if (closeOreDist == undefined || dist < closeOreDist) {
            closeOreDist = dist;
            closeOre = tileResourceData.tile;
        }
    }
}

簡易 bot 範例

下例說明如何在遊戲開始時取得指定格子的資源資料,以及列出全地圖的資源分布:

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

class ResourceScannerBot extends Bot {
    onGameStart(game: GameApi) {
        const tile = game.mapApi.getTile(40, 30);
        if (tile) {
            const data = game.mapApi.getTileResourceData(tile);
            if (data) {
                console.log(`(40,30) ore=${data.ore}, gems=${data.gems}, spawner=${data.spawnsOre}`);
            } else {
                console.log("No resource on (40,30)");
            }
        }

        const all = game.mapApi.getAllTilesResourceData();
        console.log(`Total resource tiles: ${all.length}`);
        all.forEach(d => {
            if (d.spawnsOre) {
                console.log(`Spawning tile at (${d.tile.rx},${d.tile.ry})`);
            }
        });
    }
}

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

getTileResourceData 讓 bot 能直接檢查某格是否含有礦物或是否為「礦脈」生成格;
getAllTilesResourceData 則一次列出地圖上所有相關地塊,適合在建造礦場或搜尋最佳採集地點時使用。
兩者搭配可迅速掌握資源分布,並據此做出戰略規劃。

 

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

This article was last edited at