Screeps工程化之配置化

news2024/11/26 0:26:49

目录

  • 前言
  • 一、抽取配置项
  • 二、读取配置项

前言

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1660112.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文读懂开源大数据OLAP

企业需要从海量数据中提取有价值的信息&#xff0c;以支持决策制定和提高运营效率&#xff0c;数据已成为企业最宝贵的资产之一。OLAP&#xff08;在线分析处理&#xff09;技术&#xff0c;作为数据仓库解决方案的核心组成部分&#xff0c;提供了一种强大的工具&#xff0c;帮…

python爬虫入门(所有演示代码,均有逐行分析!)

爬虫的初学者们&#xff0c;只看这一篇就够了&#xff0c;看到就是赚到&#xff01; 目录 1.爬虫简介 2.版本及库的要求 3.爬虫的框架 4.HTML简介 5.爬虫库及演示 &#xff08;1&#xff09;requests库&#xff08;网页下载器&#xff09; &#xff08;2&#xff09;Beau…

Verilog复习(三)| Verilog语言基础

四种基本的逻辑值 0&#xff1a;逻辑0或“假”1&#xff1a;逻辑1或“真”x&#xff1a;未知z&#xff1a;高阻 三类常量 整型数&#xff1a;简单的十进制格式&#xff0c;基数格式&#xff08;5’O37&#xff0c;4’B1x_01&#xff09; 格式&#xff1a; <size><’b…

AI中转站计费平台系统源码一站式解决方案安装说明

AI中转站计费平台系统源码一站式解决方案安装说明 功能 | Features AI 联网功能 AI online searching service 多账户均衡负载 Multi-account load balancing HTTP2 Stream 实时响应功能 HTTP2 Stream real-time response function 节流和鉴权体系 Throttling and authenticati…

PCB打标机3段翻板和2段翻板的区别

随着电子技术的发展&#xff0c;电子产品的更新换代速度越来越快&#xff0c;对PCB打标机的需求也越来越大。PCB打标机是一种用于在PCB板上刻划文字、图案、条形码等信息的设备&#xff0c;广泛应用于FPC、LED灯、电源板等领域。其中&#xff0c;3段翻板和2段翻板是两种常见的P…

DBCHM 数据库 CHM 文档生成工具

介绍 DBCHM 是一款数据库文档生成工具&#xff01; 该工具从最初支持chm文档格式开始&#xff0c;通过开源&#xff0c;集思广益&#xff0c;不断改进&#xff0c;又陆续支持word、excel、pdf、html、xml、markdown等文档格式的导出。 支持的数据库 SqlServerMySQLOraclePos…

Java入门基础学习笔记2——JDK的选择下载安装

搭建Java的开发环境&#xff1a; Java的产品叫JDK&#xff08;Java Development Kit&#xff1a; Java开发者工具包&#xff09;&#xff0c;必须安装JDK才能使用Java。 JDK的发展史&#xff1a; LTS&#xff1a;Long-term Support&#xff1a;长期支持版。指的Java会对这些版…

3. 多层感知机算法和异或门的 Python 实现

前面介绍过感知机算法和一些简单的 Python 实践&#xff0c;这些都是单层实现&#xff0c;感知机还可以通过叠加层来构建多层感知机。 2. 感知机算法和简单 Python 实现-CSDN博客 1. 多层感知机介绍 单层感知机只能表示线性空间&#xff0c;多层感知机就可以表示非线性空间。…

TCP是如何实现可靠传输的 UDP面向报文 TCP面向字节流是什么意思 TCP和UDP分别适用于什么场合

UDP是用户数据报协议&#xff0c;它是一种无连接的传输层协议&#xff0c;它面向报文&#xff0c;也就是说&#xff0c;UDP对应用层交下来的报文&#xff0c;在添加UDP头之后直接发送出去&#xff0c;不会对数据进行拆分和合并。因此&#xff0c;UDP传输的数据单位是报文&#…

STM32编译前置条件配置

本文基于stm32f104系列芯片&#xff0c;记录编程代码前需要的操作&#xff1a; 添加库文件 在ST官网下载标准库STM32F10x_StdPeriph_Lib_V3.5.0&#xff0c;解压后&#xff0c;得到以下界面 启动文件 进入Libraries&#xff0c;然后进入CMSIS&#xff0c;再进入CM3&#xff…

RERCS系统-WDA+BOPF框架实战例子 PART 1-新建List UIBB(列表组件)并分配Feeder Class和Node Element

需求背景&#xff1a; 已有的项目主数据功能&#xff0c;新增一个列表UIBB显示主数据额外的关联数据明细。 1、Fiori页面通过右键-技术帮助打开对应的组件配置&#xff1b; 2、双击对应的组件配置&#xff0c;调整对应的页面新建UIBB&#xff1b; 3、填写对应的UIBB属性字段&a…

【数据结构】 二叉树的顺序结构——堆的实现

普通的二叉树是不适合用数组来存储的&#xff0c;因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储 。 一、堆的概念及结构 父节点比孩子结点大 是大堆 父节点比孩子结点小 是小堆 堆的性质 堆中某…

世界上知名度最高的人物颜廷利:精神与物质的对岸有五种类型的人

世界上知名度最高的人物颜廷利&#xff1a;精神与物质的对岸有五种类型的人 面对现实生活中的物质生活和精神生活而言&#xff0c;确切的说&#xff0c;实际上总共可以划分为五种类型的人&#xff1a; 第一种&#xff0c;隔河观望的人&#xff0c;他们总是以‘物质’&#xff0…

Matlab: ode45解微分方程——以弹簧振子模型为例

简介&#xff1a; 在科学和工程中&#xff0c;我们经常遇到描述事物变化的微分方程。这些方程可以帮助我们理解从行星运动到药物在体内的扩散等各种现象。但是&#xff0c;很多微分方程非常复杂&#xff0c;手动求解几乎不可能。这时&#xff0c;我们就可以使用像 ode45这样的…

【Linux】冯诺依曼体系

冯诺依曼体系 冯诺依曼体系结构是我们计算机组成的基本架构 中央处理器&#xff08;CPU&#xff09;&#xff1a; 中央处理器是冯诺伊曼体系的核心部分&#xff0c;负责执行计算机程序中的指令。它包括算术逻辑单元&#xff08;ALU&#xff09;和控制单元&#xff08;CU&#x…

【JavaWeb】网上蛋糕商城后台-商品管理

概念 本文讲解和实现网上蛋糕商城的后台管理系统中的商品管理功能。 商品列表 点击后台管理系统的head.jsp头部的“商品管理”功能选项&#xff0c;向服务器发送请求/admin/goods_list 因此需要在servlet包中创建AdminGoodsListServlet类&#xff0c;用于获取商品信息列表 …

拷贝构造、赋值运算符、运算符重载

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

二叉树的广度优先遍历 - 华为OD统一考试(D卷)

OD统一考试(D卷) 分值: 200分 题解: Java / Python / C++ 题目描述 有一棵二叉树,每个节点由一个大写字母标识(最多26个节点)。 现有两组字母,分别表示后序遍历(左孩子->右孩子->父节点)和中序遍历(左孩子->父节点->右孩子)的结果,请输出层次遍历的结…

视频号小店应该怎么去做呢?新手必看!一篇详解!

大家好&#xff0c;我是电商小V 视频号小店就是腾讯推出的新项目&#xff0c;目前正处于红利期&#xff0c;现在也是入驻的好时机&#xff0c;背靠腾讯平台&#xff0c;是为商家提供商品信息展示&#xff0c;商品交易&#xff0c;支持商家在视频号场景内开店经营的官方平台&…

六、Redis五种常用数据结构-zset

zset是Redis的有序集合数据类型&#xff0c;但是其和set一样是不能重复的。但是相比于set其又是有序的。set的每个数据都有一个double类型的分数&#xff0c;zset正是根据这个分数来进行数据间的排序从小到大。有序集合中的元素是唯一的&#xff0c;但是分数(score)是可以重复的…