目录
- 前言
- 一、抽取配置项
- 二、读取配置项
前言
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 = 0for (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的数量、生成顺序、行为逻辑都只需要在配置文件中修改就行了。