寒假发现了一款编程版的星际争霸,叫《Screeps》
> Screeps 是一款 MMORTS (大型多人在线即时战略游戏)。游戏里有很多世界,每一个玩家都可以在包含所有玩家的**单个世界**中创建自己的领地。在领地上可以采集**资源**,建造**单位**以及占领**领土**。随着你征服的领土越来越多,势力范围越来越大,你在游戏世界中的影响力也越来越大。不过荣耀与风险并存,你的领地也同时被虎视眈眈的其他玩家盯着。
Screeps 主要是为了有**编程背景**的人设计的。和其他 RTS 游戏不同的地方在于,只要你为你的 Creep 敲好了代码,就可以让它们自动运行,不用你亲自操作。同时和其他 MMO 游戏不同之处在于你不用花费成片成片的时间去玩,只用没事的时候抽空看一看一切是否进展顺利。
Screeps目前有四个大区,也叫shard,我选择的是最老的shard0。
先走了一遍教程,然后选了一个超狗的出生点。

因为没学过JavaScript,就先用教程里的代码跑了一个晚上。发现效率有点慢,而且每个creep只做一件事,经常出现harvester挡在矿位不挖矿的情况。所以我想把harvester,upgrader,builder几个角色合并成一个worker角色,让creep尽量有事可做。
当creep库存空时,停止work并去挖矿。挖满了进入work状态,work的优先级是先装满spawn和extension(防止creep挂掉后没有能量生产新的creep),然后是build,最后是upgradeController,因为upgrade几乎是无止尽的,所以优先级排最后。
早上起来发现成了这样,所有creep围在出生点不工作。

赶紧debug,看样子应该是找矿没有加过滤,应该把矿余量为零的过滤掉。
main.js(主模块)
```javascript
var roleWorker = require('role.worker');
//将采矿、建筑、升级、维修等后勤功能整合到一个worker类型的creep上
//优先级 1放满spawn和extension 2build建筑 3升级controller
//寻矿,先找矿,没有矿再找箱子
module.exports.loop = function () {
//清理内存
for(var name in Memory.creeps) {
if(!Game.creeps[name]) {
delete Memory.creeps[name];
//console.log('Clearing non-existing creep memory:', name);
}
}
var workers = _.filter(Game.creeps, (creep) => creep.memory.role == 'worker');
if(workers.length < 20){
var newName = 'Worker' + Game.time;
Game.spawns['Spawn1'].spawnCreep([WORK,WORK,CARRY,CARRY,MOVE,MOVE,MOVE,MOVE],
newName,{memory: {role:'worker'}});
}
//spawn中显示提示
if(Game.spawns['Spawn1'].spawning) {
var spawningCreep = Game.creeps[Game.spawns['Spawn1'].spawning.name];
Game.spawns['Spawn1'].room.visual.text(
'🛠️' + spawningCreep.memory.role,
Game.spawns['Spawn1'].pos.x + 1,
Game.spawns['Spawn1'].pos.y,
{align: 'left', opacity: 0.8});
}
//遍历所有creep
for(var name in Game.creeps) {
var creep = Game.creeps[name];
if(creep.memory.role == 'worker'){
roleWorker.run(creep);
}
}
}
```
role.worker.js(worker模块)
```javascript
var roleWorker = {
//worker的memory中记录harvesting,transfering,building,upgrading
run: function(creep){
if(creep.memory.working && creep.store[RESOURCE_ENERGY] == 0) {
creep.memory.working = false;
creep.say('🔄 harvest');
}
if(!creep.memory.working && creep.store.getFreeCapacity() == 0) {
creep.memory.working = true;
creep.say('⚡ work');
}
if(creep.memory.working){
var targets = creep.room.find(FIND_STRUCTURES, {//找建筑
filter: (structure) => {//建筑类型extension或spawn
return (structure.structureType == STRUCTURE_EXTENSION || structure.structureType == STRUCTURE_SPAWN) &&
structure.store.getFreeCapacity(RESOURCE_ENERGY) > 0;//库存未满
}
});
if(targets.length > 0) {//优先充能spawn
if(creep.transfer(targets[0], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
creep.moveTo(targets[0], {visualizePathStyle: {stroke: '#ffffff'}});
}
}
else{
var targets = creep.room.find(FIND_CONSTRUCTION_SITES);
if(targets.length > 0) {
if(creep.build(targets[0]) == ERR_NOT_IN_RANGE) {
creep.moveTo(targets[0], {visualizePathStyle: {stroke: '#ffffff'}});
}
}
else{
if(creep.upgradeController(creep.room.controller) == ERR_NOT_IN_RANGE) {
creep.moveTo(creep.room.controller, {visualizePathStyle: {stroke: '#ffffff'}});
}
}
}
}
else{
var targets = creep.room.find(FIND_SOURCES,{
filter: (source) => {
return (source.energy != 0);
}
});
if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
creep.moveTo(sources[0], {visualizePathStyle: {stroke: '#ffaa00'}});
}
}
}
}
module.exports = roleWorker;
```
应该是没问题了,再观察一天吧~~~


入坑Screeps