目录
- 前言
- 一、抽取配置项
- 二、读取配置项
前言
Screeps中所有代码都会在一个tick(游戏内的世间)内执行完成,想要做到代码的高度复用,和隔离各个房间creep的行为就需要将部分代码进行配置化,本文仅为作者本人的游戏思路,并不是最佳实践,如有更好的实现方法可在评论区提出。
一、抽取配置项
以本人的一个房间配置为例,抽取配置后,有专门调用它们的方法,后文会介绍到
import {BUILDER, HARVERSTER, LINKHARVERSTER, REPAIRER, TRANSPORTER, UPGRADER} from "../../../constant/roleConstant.js";
import {transporterRun} from "../../../action/creep/transport.js";
import {upgraderRun} from "../../../action/creep/upgrader.js";
import {repairerRun} from "../../../action/creep/repairer.js";
import {harvesterRun} from "../../../action/creep/harvester.js";
import {builderRun} from "../../../action/creep/builder.js";
import {linkHarvesterRun} from "../../../action/creep/linkTransport.js";
/**
* 3号房间
*/
export const E42N24 = {
"transporter": {
role: TRANSPORTER,
bodys: Array(0).fill(WORK)
.concat(Array(2).fill(CARRY))
.concat(Array(1).fill(MOVE)),
number: 2,
weight: 2,
func: transporterRun,
sourcesIndex: 1
},
"upgrader": {
role: UPGRADER,
bodys: Array(3).fill(WORK)
.concat(Array(3).fill(CARRY))
.concat(Array(3).fill(MOVE)),
number: 2,
weight: 2,
func: upgraderRun,
sourcesIndex: 0
},
"repairer": {
role: REPAIRER,
bodys: Array(3).fill(WORK)
.concat(Array(3).fill(CARRY))
.concat(Array(3).fill(MOVE)),
number: 1,
weight: 3,
func: repairerRun,
sourcesIndex: 1
},
"harvester": {
role: HARVERSTER,
bodys: Array(5).fill(WORK)
.concat(Array(1).fill(MOVE)),
number: 1,
weight: 2,
func: harvesterRun,
sourcesIndex: 0
},
"builder": {
role: BUILDER,
bodys: Array(3).fill(WORK)
.concat(Array(3).fill(CARRY))
.concat(Array(3).fill(MOVE)),
number: 1,
weight: 4,
func: builderRun,
sourcesIndex: 0
},
"linkHarvester": {
role: LINKHARVERSTER,
bodys: Array(5).fill(WORK)
.concat(Array(0).fill(CARRY))
.concat(Array(1).fill(MOVE)),
number: 1,
weight: 1,
func: linkHarvesterRun,
sourcesIndex: 1
},
}
每一项以角色为键,有每一个角色具体的配置内容
详细介绍:
-
role:creep的角色,这个值是一个常量,它会在生成creep时传入该creep初始化的内存中
-
bodys:creep的身体组件,没有将所有组件存入一个数组的原因是,这样更加方便查看
const bodys1=[WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,CARRY,CARRY,CARRY,MOVE,MOVE,MOVE,MOVE,MOVE] const bodys2=Array(5).fill(WORK) .concat(Array(5).fill(CARRY)) .concat(Array(5).fill(MOVE))
可以对比一下,哪种方式更加方便查看
-
number:creep生成的数量
-
weight:creep生成的权重,该权重主要用于生成creep的顺序,某些角色的存在是非常重要的,它的权重就应该是最高的,无论什么时候,在一定数量范围内它都应该是最先生成的。
-
func:每一种role对应的行为逻辑方法
-
sourcesIndex:需要开采能量的索引值(我承认这个是一个失败的设计,因为有些role不会去挖矿,而是直接从storage或container中取,但是为了预防一个房间的所有存储建筑崩盘的情况,能过够让每一种role都可以自给自足。)
二、读取配置项
将所有的房间配置在整合到一个配置中
import {E43N24} from "./room/E43N24.js";
import {E43N25} from "./room/E43N25.js";
import {E42N24} from "./room/E42N24.js";
export const creepNumConfig = {
"E43N24": E43N24,
"E43N25": E43N25,
"E42N24": E42N24
}
使用特定的方法调用这些配置
import {creepNumConfig} from "./creepNumConfig.js";
/**
* creep生成方法
* @param {StructureSpawn} spawn
* @param {string} role
* @param {string} roomKey
*/
export const creatCreep = (spawn, roomKey, role) => {
const date = new Date()
const name = `xl-${roomKey}-${date.getHours()}-${date.getMinutes()}-${date.getSeconds()}`
//判断是否有足够的能量
if (useEnergy(roomKey, role) <= Game.rooms[roomKey].energyAvailable) {
const result_code = spawn.spawnCreep(creepNumConfig[roomKey][role].bodys, `${name}-${role}`, {
memory: {
role: role,
workState: false
}
})
console.log(`创建了${name}-${role}::${result_code}`)
}
}
/**
* @param {string} role 角色
* @param {string} roomKey 房间号
* @returns {number}
*/
export const creepNum = (role, roomKey) => {
return creepNumConfig[roomKey][role].number
}
/**
* @description 组装成新的role列表并通过权重字段来排序
* @param {string} roomKey 房间号
* @param {string[]} excludeRoles 要排除的角色,部分角色不走正常的生成模块,比如防御者只在战争模块生成
* @return {string[]} 角色数组
*/
export const getSortedRolesByWeight = (roomKey, ...excludeRoles) => {
// 获取指定房间的配置
const roomConfig = creepNumConfig[roomKey];
// 创建角色信息列表
const roles = Object.keys(roomConfig)
.map((key) => {
return {
role: roomConfig[key].role,
weight: roomConfig[key].weight,
};
})
.filter((item) => !excludeRoles.includes(item.role));
// 按权重从低到高排序
roles.sort((a, b) => a.weight - b.weight);
// 返回排序后的角色列表(只包含 role 字段)
return roles.map((item) => item.role);
};
/**
* 角色执行逻辑
* @param {string} roomKey
* @param {Creep} creep
* @param {string} role
*/
export const roleRun = (roomKey, creep, role) => {
if (creepNumConfig[roomKey][role]) {
creepNumConfig[roomKey][role].func(creep, creepNumConfig[roomKey][role].sourcesIndex)
}
}
/**
* 计算生成一个creep需要多少能量
* @param {string} roomKey
* @param {string} role
* @return {number}
*/
const useEnergy = (roomKey, role) => {
let sum = 0
for (const body of creepNumConfig[roomKey][role].bodys) {
if (body === MOVE || body === CARRY) {
sum += 50
}
if (body === WORK) {
sum += 100
}
if (body === ATTACK) {
sum += 80
}
if (body === RANGED_ATTACK) {
sum += 150
}
if (body === HEAL) {
sum += 250
}
if (body === CLAIM) {
sum += 600
}
if (body === TOUGH) {
sum += 10
}
}
return sum
}
房间的配置项就只在这个文件中调用,而各个模块只需要调用这个文件中的方法就行了。
游戏过程中,各个房间的creep的数量、生成顺序、行为逻辑都只需要在配置文件中修改就行了。