Screeps: World Guide

[日本語]Screepsの基本[JPN] for Screeps: World

[日本語]Screepsの基本[JPN]

Overview

公式ドキュメントやAPIリファレンスを見てもよく分からない………。そんな、あなたにこのガイド!プログラミングをした事がない?大丈夫!このScreepsというゲームを遊ぶために必要な最低限の知識を提供します。

はじめに

公式ドキュメントページ[docs.screeps.com]
公式APIリファレンスページ[docs.screeps.com]

ドキュメントには、このゲームのルール(仕様)が説明されています。読む意義は大いにあります。読みましょう。

APIリファレンスには、このゲーム中で使うスクリプトの関数や定数の仕様が書かれています。基本的にゲーム中に分からないことがあれば、このAPIリファレンスページを見ることになるでしょう。ドキュメントよりお世話になる頻度が高いです。

このゲームのスクリプトは9割8分7里、「Game.」から始まります。とりあえず「Game.」と記述をすれば迷うことはないはずです。

CPU LimitとMemory

このゲームではCPUとメモリーの仕様ついて少しだけ知っておく必要があります。

・CPU Limitについて
ゲームを買った人はCPU Limitに20という制限がかかっています。
この20という数字はスクリプトを動かすときに使用可能な時間の最大値を表していて単位はmsです。
つまり、1ループ中に20ms以内で処理できるスクリプトを記述する必要があります。
また、20ms以内にスクリプト実行が終わらなかった場合、強制的にスクリプトが止まります。
ただしこのCPU Limitは課金することでLimit上限を解除することができます。

・Memoryについて
プレイヤーは2048KBのメモリー(記憶領域)を持っています。
このMemoryにはゲーム中の情報を一時保存するために使います。
ただし、完全なゲームオブジェクトや関数を直接保存することは禁止されています。
ゲームオブジェクトを保存する場合は、getObjectById()関数などを用いて保存します。

・使われなかったCPU Limitの持ち越し
CPU Limitが20でスクリプト実行で使用したのが2msだった場合、差分の18msは次回のスクリプト実行に持ち越されます。貯蓄は最大10000までです。
また、貯蓄されたLimitを一回のスクリプト実行で使用できるCPU Limitは最大500です。

スクリプティングの基本

・比較演算子

== 同じなら != 同じでないなら && かつ || または > 超過 >= 以上 < 未満 <= 以下

比較演算子とは、名のごとく数値を比較します。

・文字列/文字

‘abcdefg’

シングルクォーテーションで囲みます。
C系統言語とは違うので注意。

・var(変数宣言)

var a;

aという変数を宣言します。

・if文

if(a == b){ }

aとbを比較します。
a == bの場合、aがbと同じなら{ }の中身を処理します。

・for文

for(var a in b){ }

bをaに代入し、bが存在するだけ{ }の中身を繰り返します。
C++でいう範囲for的な使い方が多いです。

・Loop関数

module.exports.loop = function (){ }

{ }の中を繰り返し(ループ)します。
1ループの長さは1ティックというゲーム内時間に依存します。

Creepの生産

ゲーム開始時に存在するモジュール(ファイル)は「main」のみで、中には一切の記述がありません。
この何も書かれていない「main」にスクリプトを記述していきます。

では早速、ユニットを生産するスクリプトを記述します。

Game.spawns[‘MainSpawn’].spawnCreep( [WORK, CARRY, MOVE], ‘test_creep’ );

つまり、直訳すると
「MainSpawnがtest_creepという名前のCreepを生産せよ。」
となります。

しばらく待つと一体のCreepがMainSpawnの上に出現します。

Creepの移動

Creepの生産の項目でユニット(Creep)の生産をすることが出来ました。
次はCreepを移動させます。
今回は目標地点にたどり着くまで繰り返し移動する必要があるのでLoop処理を行います。

module.exports.loop = function(){ var right_exit = Game.creeps[‘test_creep’].room.find(FIND_EXIT_RIGHT); Game.creeps[‘test_creep’].moveTo(right_exit[0]); }


直訳すると、「現在いる部屋の右側の出口を探してそこまで移動しろ。」です。

MainSpawnに帰りたいときは、

module.exports.loop = function(){ Game.creeps[‘test_creep’].moveTo(Game.spawn[‘MainSpawn’]); }

と記述をすれば帰ってくれます。

Creepの行動

ここではCreepでよく使う頻度が高いコマンド(命令や処理)を紹介します。
FIND_**などの定数は公式APIリファレンスを参照してください。
公式APIリファレンス定数一覧ページ[docs.screeps.com]

・moveTo(target)関数
targetに向かって最適最短距離で移動します。

Game.creeps[‘name’].moveTo(target);


・harvest(target)関数
targetから資源を採取します。

Game.creeps[‘name’].harvest(target);


・transfer(target, RESOURCE_**)関数
クリープ’name’が持つ資源をtargetへ移動させます。2つ目の引数にはRESOURCE_ENEGYなどのRESORCE_**定数を指定します。

Game.creeps[‘name’].transfer(target, RESOURCE_**);


・room.find(FIND_**)関数
現在いる部屋(room)からFIND_**定数で指定したオブジェクトを探します。例えばFIND_SOURCESを指定すれば資源を探します。

Game.creeps[‘name’].room.find(FIND_**);

Creepの自動化

creepがエネルギ資源を採取してキャリーが一杯になったらMainSpawnに帰る、という処理を行います。

module.exports.loop = function(){ for(var name in Game.creeps) { var creep = Game.creeps[name]; var sources = creep.room.find(FIND_SOURCES); if(creep.store.getFreeCapacity() == 0) { creep.moveTo(Game.spawns[‘MainSpawn’]); creep.transfer(Game.spawns[‘MainSpawn’], RESOURCE_ENERGY); } else { if(sources == null) { var all_exit = creep.room.find(FIND_EXIT); creep.moveTo(all_exit[0]); } else { creep.moveTo(sources[0]); creep.harvest(sources[0]); } } } }


注意:if(sources == null)について。
   ドキュメントやAPIリファレンスを見ましたが、nullでいいのか分かりませんでした。
   ただ、APIリファレンス上だと配列に対して何もないときはnullで判定しているっぽいの
   でnullを入れています。もしかしたら0かもしれないしー1かもしれないし定数がある
   かもしれないです。
   仕様を知っている人、コメントお願いします。

モジュールを分ける

ずっと「main」モジュールに記述を加えていけば行数がとてつもない量になってしまい大変視認性が悪くなります。
そこで別のモジュールを作成し、そこから「main」モジュールへと組み込む事で視認性を上げ、スクリプトの管理を容易にします。
簡単に言えば、ファイル分けです。

エディターの左側にある「new module name …」に「worker」と記入し「Add normal module」をクリックします。
すると、「worker」の名前で新しくモジュール(ファイル)が作成されます。

新しく作成されたモジュールには簡単な使い方が書かれています。
が、気にしなくて大丈夫です。

そんなこんなで、「Creepを自動化」の項目で記述したスクリプトを「worker」モジュールに移します。

//workerモジュールへの記述 var worker = { run: function(creep) { if(creep.store.getFreeCapacity() == 0) { creep.moveTo(Game.spawns[‘MainSpawn’]); creep.transfer(Game.spawns[‘MainSpawn’], RESOURCE_ENERGY); } else { var sources = creep.room.find(FIND_SOURCES); if(sources == null) { var all_exit = creep.room.find(FIND_EXIT); creep.moveTo(all_exit[0]); } else { creep.moveTo(sources[0]); creep.harvest(sources[0]); } } } } module.exports = worker;

前の項目と少し記述が変わっていますが動作に変化はあまりありません。

簡単に解説します。
run: function(creep)はrun()という関数を作るための記述です。これは、workerモジュール外でworkerモジュールを使う際に必要になります。
そして、module.exports = worker;はシステム側にモジュールの存在を教えます。

これで、モジュールを使う準備が整いました。
次は、「main」モジュールから「worker」モジュールを呼び出します。

//mainモジュールへの記述 var worker_task = require(‘worker’); module.exports.loop = function(){ for(var name in Game.creeps) { var creep = Game.creeps[name]; //worker task if( creep.name == ‘worker’) { worker_task.run(creep); } } }

一行目のvar worker_task = require(‘worker’);で「worker」モジュールを使う事を宣言しています。
そして、var creep = Game.creeps[name];で現存するCreepを取得します。
そのあとCreepの名前が’worker’の場合のみ、「worker」モジュールで作成したrun()関数を実行するようにしています。
なお、この「モジュールを分ける」項目ではCreepを生産する処理を記述していないので、別途記述する必要があります。

※この項目でのCreepの名前はworkerです。つまりGame.creeps[‘worker’]としてスクリプトを記述しています。

エラー定数の使い方

このゲームではユニットが行動した際にできなかった事をエラーで返します。
そしてそのエラーを定義するERR_**定数は複数あります。

例えば、

if( creep.harvest(sources[0]) == ERR_NOT_IN_RANGE ) { }

と、記述をすれば問題はありませんが

if( creep.harvest(sources[0]) != ERR_NOT_IN_RANGE ) { }

と記述をしてしまうと予期せぬ結果を生む可能性が高いです。
「ERR_NOT_IN_RANGEではない時」というのは「ERR_NOT_IN_RANGE以外のERR_**定数の時」とも捉えることが出来てしまいます。
定数の扱いはなるべくピンポイントに指定することを心がけましょう。

Creepの役割分担

Creepには名前の他に役職を設定することが出来ます。

役職名は

Game.creeps[‘test_creep’].memory.role = ‘harvester’;

のように設定します。
‘harvester’の部分は自分の好きな名前で構いません。

for(var name in Game.creeps) { var creep = Game.creeps[name]; //creepの役職名と’harvester’が一緒なら if(creep.memory.role == ‘harvester’) { //ここに処理を書く } }

使い方は単純で、creepに対してmemory.roleに設定してある役職名とを比較して同じ名前であれば処理を開始するだけです。

SteamSolo.com