Spawn Module
Creep Module - 生产 Creep 管理模块
在实现🤖️ Creep 模块之后,还需要处理该模块对外依赖的生新的Creep
模块。
该对外依赖模块可以通过一个非常简单的优先队列实现,即每 tick 轮询所有房间,构造队列放置期望生产的 Creep,按照优先级别以及能量是否足够来完成生产。
📃 具体实现
/**
* Creep 生产模块
*/
function calculateBodyCost(bodies: BodyPartConstant[]) {
let cost = 0
for ( const body of bodies )
cost += BODYPART_COST[body]
return cost
}
type RequestCreepType = {
callback: (name: string) => void,
cost: number,
body: BodyPartConstant[],
requestTick: number,
memory?: CreepMemory,
workPos?: RoomPosition
}
class CreepSpawnModule {
#repo: { [roomName: string]: { [priority: number]: RequestCreepType[] } } = {}
request(roomName: string, callback: (name: string) => void, body: BodyPartConstant[], priority: number, memory?: CreepMemory, workPos?: RoomPosition): void {
if ( !(roomName in this.#repo) ) this.#repo[roomName] = {}
if ( !(priority in this.#repo[roomName]) ) this.#repo[roomName][priority] = []
this.#repo[roomName][priority].push({ callback, cost: calculateBodyCost(body), body, requestTick: Game.time, memory, workPos })
}
constructor() {
// 轮询是否本 tick 生产新的 Creep
A.timer.add(Game.time + 1, () => {
for (const roomName in this.#repo) {
// 每 tick 只检查一次
const spawns = Game.rooms[roomName].find<FIND_MY_STRUCTURES, StructureSpawn>(FIND_MY_STRUCTURES, {filter: {structureType: STRUCTURE_SPAWN}})
const availableSpawns = _.filter(spawns, s => !s.spawning )
if ( availableSpawns.length === 0 ) continue
// 按照优先级别顺序
const priorities = _.sortBy(Object.keys(this.#repo[roomName]))
let flag = false
for (const priority of priorities) {
// 最高响应比优先调度算法
// 这里等待 tick 乘以的系数应当最好为每秒本房间
// energy 的产量
const orders = _.sortBy(this.#repo[roomName][priority], (element: RequestCreepType) => -((Game.time - element.requestTick) * 50.0 + element.cost) / element.cost)
for (const order of orders) {
// 检查是否为特定 Spawn
let spawn: StructureSpawn = null
if ( order.workPos && _.any(spawns, s => s.pos.getRangeTo(order.workPos) <= 1 ) ) {
spawn = _.select(spawns, s => s.pos.getRangeTo(order.workPos) <= 1)[0]
if ( !_.any(availableSpawns, s => s.id === spawn.id) ) continue
} else
spawn = availableSpawns[0]
// 无论能量够不够, 都不再往后检查
flag = true
if ( Game.rooms[roomName].energyAvailable >= order.cost ) {
let name = null
while ( !name || name in Game.creeps )
name = `${roomName}-${generate_random_hex(4)}`
assertWithMsg(spawn.spawnCreep(order.body, name, {
memory: order.memory,
directions: (order.workPos && spawn.pos.getRangeTo(order.workPos) <= 1)? [ spawn.pos.getDirectionTo(order.workPos) ] : []
}) === OK, `生产 Creep [${order.body}, ${roomName}] 时, 选定的 Spawn [${spawn.id}] 无法成功生产 Creep`)
A.timer.add(Game.time + 1, (name, callback) => {
if ( name in Game.creeps ) {
callback(name)
return A.timer.STOP
}
}, [ name, order.callback ], CREEP_SPAWN_TIME)
}
}
if ( flag ) break
}
}
}, [], 1)
}
}
Last updated