Screeps工程化之配置化

前言

Screeps中所有代码都会在一个tick(游戏内的世间)内执行完成,想要做到代码的高度复用,和隔离各个房间creep的行为就需要将部分代码进行配置化,本文仅为作者本人的游戏思路,并不是最佳实践,如有更好的实现方法可在评论区提出。

c255bead9defcb2ee6f20768e36690ac

一、抽取配置项

以本人的一个房间配置为例,抽取配置后,有专门调用它们的方法,后文会介绍到

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
    },
}

每一项以角色为键,有每一个角色具体的配置内容

详细介绍:

  1. role:creep的角色,这个值是一个常量,它会在生成creep时传入该creep初始化的内存中

  2. 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))
    

    可以对比一下,哪种方式更加方便查看

  3. number:creep生成的数量

  4. weight:creep生成的权重,该权重主要用于生成creep的顺序,某些角色的存在是非常重要的,它的权重就应该是最高的,无论什么时候,在一定数量范围内它都应该是最先生成的。

  5. func:每一种role对应的行为逻辑方法

  6. 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的数量、生成顺序、行为逻辑都只需要在配置文件中修改就行了。

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笑的像个child

好人一生平安,先磕为敬

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值