Gettler‘s Screep World 笔记 Ⅰ

avatar
作者
筋斗云
阅读量:0

夏促时候刚刚入坑,写个笔记叭~

环境配置

参考 HoPGoldy 大佬的简书,先配置下开发环境

萌新去看大佬的详细教程,我这里比较简单,有前端基础的可以直接抄

VSCode 跳过

node 我配的是v18.18.2

换源

npm config set registry https://registry.npmmirror.com 

安装依赖

npm install @types/screeps @types/lodash@3.10.1 # 代码提示 npm install -D rollup # 代码构建工具 npm install rollup-plugin-clear rollup-plugin-screeps rollup-plugin-copy -D # 代码上传工具 npm install source-map@0.6.1 # 异常信息映射 npm install -D @rollup/plugin-node-resolve @rollup/plugin-commonjs # 模块打包工具 # 下面的ts配不配就看心情了,建议配一下 npm install --save-dev typescript rollup-plugin-typescript2 # ts编译 

根目录下创建代码构建工具的配置文件 rollup.config.js

import clear from 'rollup-plugin-clear' import screeps from 'rollup-plugin-screeps' import copy from 'rollup-plugin-copy' import resolve from '@rollup/plugin-node-resolve' import commonjs from '@rollup/plugin-commonjs'  let config // 根据指定的目标获取对应的配置项 if (!process.env.DEST) {   console.log("未指定目标, 代码将被编译但不会上传") } else if (!(config = require("./.secret.json")[process.env.DEST])) {   throw new Error("无效目标,请检查 secret.json 中是否包含对应配置") }  // 根据指定的配置决定是上传还是复制到文件夹 const pluginDeploy = config && config.copyPath ? // 复制到指定路径                      copy({                             targets: [{                               src: 'dist/main.js', dest: config.copyPath                             }, {                               src: 'dist/main.js.map',                               dest: config.copyPath,                               rename: name => name + '.map.js',                               transform: contents => `module.exports = ${contents.toString()};`                             }], hook: 'writeBundle', verbose: true                           }) : // 更新 .map 到 .map.js 并上传                      screeps({config, dryRun: !config})  export default {   input: 'src/main.js', output: {     file: 'dist/main.js', format: 'cjs', sourcemap: true   }, plugins: [// 清除上次编译成果     clear({targets: ["dist"]}), // 执行上传或者复制     // 打包依赖     resolve(),     // 模块化依赖     commonjs(),     pluginDeploy] }; 

package.json 配置

{   "name": "sc",   "version": "1.0.0",   "description": "",   "main": "rollup.config.js",   "scripts": {     "start": "rollup -cw --environment DEST:main",     "local": "rollup -cw --environment DEST:local",     "build": "rollup -cw"   },   "repository": {     "type": "git",     "url": "http://xxxxxxxx:xxxx/Gettler/screeps.git"   },   "keywords": [],   "author": "Gettler",   "license": "ISC",   "devDependencies": {     "@rollup/plugin-commonjs": "^14.0.0",     "@rollup/plugin-node-resolve": "^8.4.0",     "@types/lodash": "^3.10.1",     "@types/node": "^14.0.24",     "@types/screeps": "^3.3.8",     "rollup": "^2.22.1",     "rollup-plugin-clear": "^2.0.7",     "rollup-plugin-copy": "^3.3.0",     "rollup-plugin-screeps": "^1.0.1",     "rollup-plugin-typescript2": "^0.27.1",     "typescript": "^3.9.7"   },   "dependencies": {     "source-map": "^0.6.1"   } } 

项目根目录下配置 .secret.json 用于发布代码到游戏,token地址:https://screeps.com/a/#!/account/auth-tokens

{   "main": {     "token": "你的token",     "protocol": "https",     "hostname": "screeps.com",     "port": 443,     "path": "/",     "branch": "default"   },   "local": {     "copyPath": "本地路径,如:C:\\Users\\Gettler\\AppData\\Local\\Screeps\\scripts\\screeps.com\\default"   } } 

main.js

import {errorMapper} from "./modules/errorMapper";  module.exports.loop = errorMapper(() => { 		// 代码在这里写即可 		console.log("Power!!!") 	} ) 

errorMapper.js

/**  * 校正异常的堆栈信息  *  * 由于 rollup 会打包所有代码到一个文件,所以异常的调用栈定位和源码的位置是不同的  * 本模块就是用来将异常的调用栈映射至源代码位置  *  * @see https://github.com/screepers/screeps-typescript-starter/blob/master/src/utils/ErrorMapper.ts  */  import {SourceMapConsumer} from 'source-map'  // 缓存 SourceMap let consumer = null  // 第一次报错时创建 sourceMap const getConsumer = function () {   if (consumer == null) consumer = new SourceMapConsumer(require("main.js.map"))   return consumer }  // 缓存映射关系以提高性能 const cache = {}  /**  * 使用源映射生成堆栈跟踪,并生成原始标志位  * 警告 - global 重置之后的首次调用会产生很高的 cpu 消耗 (> 30 CPU)  * 之后的每次调用会产生较低的 cpu 消耗 (~ 0.1 CPU / 次)  *  * @param {Error | string} error 错误或原始追踪栈  * @returns {string} 映射之后的源代码追踪栈  */ const sourceMappedStackTrace = function (error) {   const stack = error instanceof Error ? error.stack : error   // 有缓存直接用   if (cache.hasOwnProperty(stack)) return cache[stack]    const re = /^\s+at\s+(.+?\s+)?\(?([0-z._\-\\\/]+):(\d+):(\d+)\)?$/gm   let match   let outStack = error.toString()   console.log("ErrorMapper -> sourceMappedStackTrace -> outStack", outStack)    while ((match = re.exec(stack))) {     // 解析完成     if (match[2] !== "main") break      // 获取追踪定位     const pos = getConsumer().originalPositionFor({                                                     column: parseInt(match[4], 10),                                                     line: parseInt(match[3], 10)                                                   })      // 无法定位     if (!pos.line) break      // 解析追踪栈     if (pos.name) outStack += `\n    at ${pos.name} (${pos.source}:${pos.line}:${pos.column})`     else {       // 源文件没找到对应文件名,采用原始追踪名       if (match[1]) outStack += `\n    at ${match[1]} (${pos.source}:${pos.line}:${pos.column})`       // 源文件没找到对应文件名并且原始追踪栈里也没有,直接省略       else outStack += `\n    at ${pos.source}:${pos.line}:${pos.column}`     }   }    cache[stack] = outStack   return outStack }  /**  * 错误追踪包装器  * 用于把报错信息通过 source-map 解析成源代码的错误位置  * 和原本 wrapLoop 的区别是,wrapLoop 会返回一个新函数,而这个会直接执行  *  * @param next 玩家代码  */ export const errorMapper = function (next) {   return () => {     try {       // 执行玩家代码       next()     } catch (e) {       if (e instanceof Error) {         // 渲染报错调用栈,沙盒模式用不了这个         const errorMessage = Game.rooms.sim ?                              `沙盒模式无法使用 source-map - 显示原始追踪栈<br>${_.escape(e.stack)}` :                              `${_.escape(sourceMappedStackTrace(e))}`          console.log(`<text style="color:#ef9a9a">${errorMessage}</text>`)       }       // 处理不了,直接抛出       else throw e     }   } } 

tsconfig.json

{   "compilerOptions": {     "target": "es2017",     "moduleResolution": "Node",     "outDir": "dist/",     "baseUrl": "./",     "sourceMap": true,     "allowSyntheticDefaultImports": true,     "paths": {       "@/*": [         "./src/*"       ]     }   },   "exclude": [     "node_modules"   ],   "include": [     "src/**/*.ts"   ] } 

至此,环境配置完成(如有问题欢迎评论区指正)

我的项目结构(已经写了一部分代码了)

image-20240715134935011

入门

新手先把官方教程的代码跑起来,在这个基础上优化,前期官方教程的代码也还够用,一定要看懂教程代码再来往下看

对照着

挖采分离

这个是我第一个想要实现的,因为我的矿可以让三个爬爬一起采,如果三个以上就会有一个爬爬闲着,等到有爬爬才玩矿运回去的时候才能有空间采矿,如果多个一起运回去好像又会损失空间,嗯。。。很浪费

实现挖采分离,就可以有三个爬爬一直挖矿,然后挖完矿扔到脚下,让别的爬爬来捡回去

思路:修改教程harvester代码,去掉运送能量到建筑的代码,去掉carry部件,编写mover

mover 的代码

if (creep.memory.role === 'mover') {   if ((creep.memory.moving !== undefined && creep.memory.moving === true) || creep.store.getFreeCapacity() === 0 || (sources.length === 0 && creep.store.getUsedCapacity() > 0)) {     creep.say("I am moving!")     creep.memory.moving = true     var targets = creep.room.find(FIND_STRUCTURES, { //找出需要补充能量的建筑       filter: (structure) => {         return (structure.structureType === STRUCTURE_EXTENSION || structure.structureType === STRUCTURE_SPAWN || structure.structureType === STRUCTURE_EXTENSION ||  structure.structureType === STRUCTURE_TOWER) && structure.store.getFreeCapacity(RESOURCE_ENERGY) > 0;       }     });     for (var tmp in Game.creeps) {       var tmpCreep = Game.creeps[tmp];       if (tmpCreep.memory.role === 'upgrader' && tmpCreep.store.getFreeCapacity() > 0) {         targets.push(tmpCreep)       } else if (tmpCreep.memory.role === 'builder' && tmpCreep.memory.building === true) {         targets.push(tmpCreep)       }     }     if (targets.length > 0) { // 需要维护的建筑数目 > 0       var res = creep.transfer(targets[creep.memory.idx % targets.length], RESOURCE_ENERGY)       if (res === ERR_NOT_IN_RANGE) {         creep.moveTo(targets[creep.memory.idx % targets.length], {visualizePathStyle: {stroke: '#ffffff'}});       } else if (res === OK) {        }     }     if (creep.store.getUsedCapacity() === 0) {       creep.memory.moving = false     }    } else if (creep.store.getFreeCapacity() > 0) {     creep.say("I am carrying!")     creep.memory.moving = false     let res = creep.pickup(sources[creep.memory.idx % sources.length])     if (res === ERR_NOT_IN_RANGE) {       creep.moveTo(sources[creep.memory.idx % sources.length], {visualizePathStyle: {stroke: '#ffaa00'}});     } else {     }   } } 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!