1.开始创建一个工作的creep
Game.spawns['Spawn1'].spawnCreep( [WORK, CARRY, MOVE], 'Harvester1' );
2.开始让工作的creep去进行采矿
module.exports.loop = function () {
var creep = Game.creeps['Harvester1'];
var sources = creep.room.find(FIND_SOURCES);
if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
creep.moveTo(sources[0]);
}
}
3.踩过矿后进行搬运的操作
module.exports.loop = function () {
var creep = Game.creeps['Harvester1'];
if(creep.store.getFreeCapacity() > 0) {
var sources = creep.room.find(FIND_SOURCES);
if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
creep.moveTo(sources[0]);
}
}
else {
if( creep.transfer(Game.spawns['Spawn1'], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE ) {
creep.moveTo(Game.spawns['Spawn1']);
}
}
}
4.用for循环来控制每一个creeps
module.exports.loop = function () {
for(var name in Game.creeps) {
var creep = Game.creeps[name];
if(creep.store.getFreeCapacity() > 0) {
var sources = creep.room.find(FIND_SOURCES);
if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
creep.moveTo(sources[0]);
}
}
else {
if(creep.transfer(Game.spawns['Spawn1'], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
creep.moveTo(Game.spawns['Spawn1']);
}
}
}
}
5.可以进行代码块来进行调用
var roleHarvester = {
/** @param {Creep} creep **/
run: function(creep) {
if(creep.store.getFreeCapacity() > 0) {
var sources = creep.room.find(FIND_SOURCES);
if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
creep.moveTo(sources[0]);
}
}
else {
if(creep.transfer(Game.spawns['Spawn1'], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
creep.moveTo(Game.spawns['Spawn1']);
}
}
}
};
module.exports = roleHarvester;
6.主项目中开始调用创建好的代码块
var roleHarvester = require('role.harvester');
module.exports.loop = function () {
for(var name in Game.creeps) {
var creep = Game.creeps[name];
roleHarvester.run(creep);
}
}
7.升级控制器的creep(不进行为0时候失去房间的控制权)
Game.spawns['Spawn1'].spawnCreep( [WORK, CARRY, MOVE], 'Upgrader1' );
8.给不同的creep分配不同的工作
Game.creeps['Harvester1'].memory.role = 'harvester';
Game.creeps['Upgrader1'].memory.role = 'upgrader';
9.给升级的creep创建代码块
var roleUpgrader = {
/** @param {Creep} creep **/
run: function(creep) {
if(creep.store[RESOURCE_ENERGY] == 0) {
var sources = creep.room.find(FIND_SOURCES);
if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
creep.moveTo(sources[0]);
}
}
else {
if(creep.upgradeController(creep.room.controller) == ERR_NOT_IN_RANGE) {
creep.moveTo(creep.room.controller);
}
}
}
};
module.exports = roleUpgrader;
10.不同的角色干不同的事情
var roleHarvester = require('role.harvester');
var roleUpgrader = require('role.upgrader');
module.exports.loop = function () {
for(var name in Game.creeps) {
var creep = Game.creeps[name];
if(creep.memory.role == 'harvester') {
roleHarvester.run(creep);
}
if(creep.memory.role == 'upgrader') {
roleUpgrader.run(creep);
}
}
}
11.用于建造建筑的creep
Game.spawns['Spawn1'].spawnCreep( [WORK, CARRY, MOVE], 'Builder1',
{ memory: { role: 'builder' } } );
12.
和之前一样,我们把这个角色放到单独的模块 role.builder
中。建造是通过对建筑工地执行 Creep.build
方法进行的,而工地则可以通过 Room.find(FIND_CONSTRUCTION_SITES)
搜索得到。建造建筑需要能量,您的 creep 应该自己去采集它们。
为了避免由于身上资源耗尽而频繁的来回移动,让我们通过添加一个新的布尔变量 creep.memory.building
来增强一下代码,这个变量将会告诉 creep 应该何时切换任务。我们还调用了 creep.say
并且在 moveTo
方法中添加了 visualizePathStyle
选项来可视化 creep 的移动路径。
var roleBuilder = {
/** @param {Creep} creep **/
run: function(creep) {
if(creep.memory.building && creep.store[RESOURCE_ENERGY] == 0) {
creep.memory.building = false;
creep.say('🔄 harvest');
}
if(!creep.memory.building && creep.store.getFreeCapacity() == 0) {
creep.memory.building = true;
creep.say('🚧 build');
}
if(creep.memory.building) {
var targets = creep.room.find(FIND_CONSTRUCTION_SITES);
if(targets.length) {
if(creep.build(targets[0]) == ERR_NOT_IN_RANGE) {
creep.moveTo(targets[0], {visualizePathStyle: {stroke: '#ffffff'}});
}
}
}
else {
var sources = creep.room.find(FIND_SOURCES);
if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
creep.moveTo(sources[0], {visualizePathStyle: {stroke: '#ffaa00'}});
}
}
}
};
module.exports = roleBuilder;
13.
让我们在 main 模块中引用新的角色并瞧瞧会发生什么。
通过在新 creep 上应用 role.builder
模块来建造全部 5 个 extension。
var roleHarvester = require('role.harvester');
var roleBuilder = require('role.builder');
module.exports.loop = function () {
for(var name in Game.creeps) {
var creep = Game.creeps[name];
if(creep.memory.role == 'harvester') {
roleHarvester.run(creep);
}
if(creep.memory.role == 'builder') {
roleBuilder.run(creep);
}
}
}
14.主界面调用开始使其工作
var roleHarvester = require('role.harvester');
var roleBuilder = require('role.builder');
module.exports.loop = function () {
for(var name in Game.creeps) {
var creep = Game.creeps[name];
if(creep.memory.role == 'harvester') {
roleHarvester.run(creep);
}
if(creep.memory.role == 'builder') {
roleBuilder.run(creep);
}
}
}
15.想要维护 extension,您需要教会您的采集单位把能量运输到 extension 而不仅仅是 spawn。为此,您需要使用 Game.structures
对象或者在对应的房间执行 Room.find(FIND_STRUCTURES)
方法进行搜索。无论使用哪种方式,您都需要用判断条件 structure.structureType == STRUCTURE_EXTENSION
(或者 structure instanceof StructureExtension
)对结果列表进行筛选,还有别忘了检查它们存有多少能量(就像之前检查 creep 一样)。
var roleHarvester = {
/** @param {Creep} creep **/
run: function(creep) {
if(creep.store.getFreeCapacity() > 0) {
var sources = creep.room.find(FIND_SOURCES);
if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
creep.moveTo(sources[0], {visualizePathStyle: {stroke: '#ffaa00'}});
}
}
else {
var targets = creep.room.find(FIND_STRUCTURES, {
filter: (structure) => {
return (structure.structureType == STRUCTURE_EXTENSION || structure.structureType == STRUCTURE_SPAWN) &&
structure.store.getFreeCapacity(RESOURCE_ENERGY) > 0;
}
});
if(targets.length > 0) {
if(creep.transfer(targets[0], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
creep.moveTo(targets[0], {visualizePathStyle: {stroke: '#ffffff'}});
}
}
}
}
};
module.exports = roleHarvester;
16.
想要了解房间里总共有多少能量可以用于孵化,您可以使用 Room.energyAvailable
属性。让我们把这个属性输出到控制台中以便在 extension 填充期间对其进行追踪。
找到全部的 5 个 extension 以及 spawn 并填充能量。
var roleHarvester = require('role.harvester');
var roleBuilder = require('role.builder');
module.exports.loop = function () {
for(var name in Game.rooms) {
console.log('Room "'+name+'" has '+Game.rooms[name].energyAvailable+' energy');
}
for(var name in Game.creeps) {
var creep = Game.creeps[name];
if(creep.memory.role == 'harvester') {
roleHarvester.run(creep);
}
if(creep.memory.role == 'builder') {
roleBuilder.run(creep);
}
}
}
17.
现在我们的 spawn 和 extension 中总共有 550 点能量。这已经足够建造一个身体部件为 [WORK,WORK,WORK,WORK,CARRY,MOVE,MOVE]
的 creep 了。这个 creep 的效率是普通工作单位的 4 倍。但是这也让它变得更重,所以我们给它添加了额外的 MOVE
部件。但是,两个 MOVE
也没办法让它跑得像小 creep 那样快,除非我们给他添加 4 个 MOVE
或者修一条路。
孵化一个身体部件为 [WORK,WORK,WORK,CARRY,MOVE,MOVE]
,名称为 HarvesterBig
的 creep 并且设为 harvester
角色。
Game.spawns['Spawn1'].spawnCreep( [WORK,WORK,WORK,WORK,CARRY,MOVE,MOVE],
'HarvesterBig',
{ memory: { role: 'harvester' } } );
18.打印日志看creep生命
var harvesters = _.filter(Game.creeps, (creep) => creep.memory.role == 'harvester');
console.log('Harvesters: ' + harvesters.length);
19.
假设我们最少需要维持两个采集单位(harvester),最简单的办法就是:每当我们发现它们的数量小于这个值时,就执行 StructureSpawn.spawnCreep
方法。您可能还没想好它们应该叫什么(这一步我们会自动给它们起名字),但是不要忘了给他们设置需要的角色(role)。
我们还会添加一些新的 RoomVisual
来显示当前正在孵化的 creep。
在您的 main 模块中添加 StructureSpawn.spawnCreep
相关逻辑。
var roleHarvester = require('role.harvester');
var roleUpgrader = require('role.upgrader');
module.exports.loop = function () {
var harvesters = _.filter(Game.creeps, (creep) => creep.memory.role == 'harvester');
console.log('Harvesters: ' + harvesters.length);
if(harvesters.length < 2) {
var newName = 'Harvester' + Game.time;
console.log('Spawning new harvester: ' + newName);
Game.spawns['Spawn1'].spawnCreep([WORK,CARRY,MOVE], newName,
{memory: {role: 'harvester'}});
}
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});
}
for(var name in Game.creeps) {
var creep = Game.creeps[name];
if(creep.memory.role == 'harvester') {
roleHarvester.run(creep);
}
if(creep.memory.role == 'upgrader') {
roleUpgrader.run(creep);
}
}
}
20.还有一件事,由于死亡 creep 的内存我们之后可能会用到,所以它们并不会被自动清除。如果您每次都用随机名称去孵化新 creep 的话,内存可能会因此溢出,所以您需要在每个 tick 开始的时候将它们清除掉(creep 创建代码之前)。
var roleHarvester = require('role.harvester');
var roleUpgrader = require('role.upgrader');
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 harvesters = _.filter(Game.creeps, (creep) => creep.memory.role == 'harvester');
console.log('Harvesters: ' + harvesters.length);
if(harvesters.length < 2) {
var newName = 'Harvester' + Game.time;
console.log('Spawning new harvester: ' + newName);
Game.spawns['Spawn1'].spawnCreep([WORK,CARRY,MOVE], newName,
{memory: {role: 'harvester'}});
}
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});
}
for(var name in Game.creeps) {
var creep = Game.creeps[name];
if(creep.memory.role == 'harvester') {
roleHarvester.run(creep);
}
if(creep.memory.role == 'upgrader') {
roleUpgrader.run(creep);
}
}
}
21.激活安全模式
Game.spawns['Spawn1'].room.controller.activateSafeMode();
22.
防御塔(tower)是防御房间最简单直接的手段。它们可以消耗能量来治疗或攻击房间中的任何 creep。治疗/攻击效果取决于 tower 和目标之间的直线距离。
首先,让我们给新 tower 打好地基。您可以在墙壁之内的任何位置放置 tower 的工地,通过顶部面板中的 “建造” 按钮找到它。
23.tower 需要能量,所以让我们改造一下 harvester 角色,让其可以把能量带到 tower 和其他建筑中。想要实现这个功能,您需要将 STRUCTURE_TOWER
常量添加到用于筛选您采集单位目标的 filter 中。
var roleHarvester = {
/** @param {Creep} creep **/
run: function(creep) {
if(creep.store.getFreeCapacity() > 0) {
var sources = creep.room.find(FIND_SOURCES);
if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
creep.moveTo(sources[0], {visualizePathStyle: {stroke: '#ffaa00'}});
}
}
else {
var targets = creep.room.find(FIND_STRUCTURES, {
filter: (structure) => {
return (structure.structureType == STRUCTURE_EXTENSION ||
structure.structureType == STRUCTURE_SPAWN ||
structure.structureType == STRUCTURE_TOWER) &&
structure.store.getFreeCapacity(RESOURCE_ENERGY) > 0;
}
});
if(targets.length > 0) {
if(creep.transfer(targets[0], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
creep.moveTo(targets[0], {visualizePathStyle: {stroke: '#ffffff'}});
}
}
}
}
};
module.exports = roleHarvester;
24
就像 creep 一样,tower 也有几个类似的方法:attack
- 攻击,heal
- 治疗,以及 repair
- 维修。每个操作都会消耗 10 点能量。一旦发现了敌人,我们就需要使用 attack
方法攻击距离最近的敌方 creep。请记住,距离非常重要:在相同的能量消耗下,操作带来的效果可能会有好几倍的差距。
想要获取 tower 的对象,您可以使用它的 ID(右侧面板中)以及 Game.getObjectById
方法。
var roleHarvester = require('role.harvester');
var roleUpgrader = require('role.upgrader');
var roleBuilder = require('role.builder');
module.exports.loop = function () {
var tower = Game.getObjectById('693092d10bdaba0a44c94e45');
if(tower) {
var closestHostile = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS);
if(closestHostile) {
tower.attack(closestHostile);
}
}
for(var name in Game.creeps) {
var creep = Game.creeps[name];
if(creep.memory.role == 'harvester') {
roleHarvester.run(creep);
}
if(creep.memory.role == 'upgrader') {
roleUpgrader.run(creep);
}
if(creep.memory.role == 'builder') {
roleBuilder.run(creep);
}
}
}
25
creep 和 tower 都可以修复受损的建筑,这次让我们用 tower 来试一下。使用 repair
方法可以完成这个任务。除此之外,您还需要使用 Room.find
方法和一个 filter 去筛选除那些受损的墙壁(wall)。
请注意,由于墙壁不属于任何玩家,所以我们需要使用 FIND_STRUCTURES
常量进行搜索而不是 FIND_MY_STRUCTURES
。
var roleHarvester = require('role.harvester');
var roleUpgrader = require('role.upgrader');
var roleBuilder = require('role.builder');
module.exports.loop = function () {
var tower = Game.getObjectById('693092d10bdaba0a44c94e45');
if(tower) {
var closestDamagedStructure = tower.pos.findClosestByRange(FIND_STRUCTURES, {
filter: (structure) => structure.hits < structure.hitsMax
});
if(closestDamagedStructure) {
tower.repair(closestDamagedStructure);
}
var closestHostile = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS);
if(closestHostile) {
tower.attack(closestHostile);
}
}
for(var name in Game.creeps) {
var creep = Game.creeps[name];
if(creep.memory.role == 'harvester') {
roleHarvester.run(creep);
}
if(creep.memory.role == 'upgrader') {
roleUpgrader.run(creep);
}
if(creep.memory.role == 'builder') {
roleBuilder.run(creep);
}
}
}