Screeps:Arena チュートリアル訳文

本テキストは備忘録であり、翻訳の正確性を保証するものではありません
また、まだ日本語の文章チェックしてないので駄文!!!!!

Screeps:Arena Steamストアページ
https://store.steampowered.com/app/1137320/Screeps_Arena/

Loop and import

チュートリアルへようこそ!ここであなたはScreeps Arenaをコーディングによってプレイする方法の基礎について学びます!!!!

Introduction

「Screeps」は「Script + Creeps(忍びよる)」の造語です
ゲームは本物のJavascriptをユニットやcreepsの行動をスクリプトするためのプログラミング言語として使用します
本チュートリアルではJavaScriptの解説はしません、このゲームをマスターしたいのであれば基本から始め、JavaScriptに慣れておくのがいいでしょう
このゲームはローカルフォルダ内のファイルでコードを書いてプレイします
ゲーム内にはコードエディタが存在しないので、外部のコードエディタを利用することをお勧めします
ソースファイルはPLAYボタンがクリックされたときにサーバーに送信されます
コードの中に構文エラーなどがないなら、ゲームが実行され、その結果が確認できるようになります
新たなゲームが始まるときにしかコードは変更できず、ゲーム中は干渉できません
ゲームは数秒で終了しますが、それを任意のスピードで観戦することができます

Script loop

すべてのターン(これはtickとも呼ばれます)で、ゲームは「loop()」と呼ばれるメイン関数を実行します
loop関数はあなたのmain.mjsで既に定義されています

export function loop({
    // Your code goes here
}

この関数内のすべてのものはゲームが終了するまで繰り返し実行されます
しかし、ここではコマンドの実行を予約するだけで、それらはloop関数が終了した後で実行されます

Import stuff

getTicks()という関数が存在します。それは現在のtickが何なのかを知るためにあります
getTicks()を呼び出すためには、/game/utilsからコードにインポートする必要があります

import { getTicks } from '/game/utils';

export function loop({
    console.log('Current tick:', getTicks());
}

このようにしてインポートできるたくさんのオブジェクトとメソッドがあります
documentationに一覧が存在します

cnosole.logに注目してください それはデバッグや実行中のコードの確認のために任意の値を出力することができます
この関数はグローバルにあるのでインポートする必要はありません

Let's begin

最初のステップでは、ゲームオブジェクトはなく、マップ上も空っぽです
このステップを完了するためには、コンソールにいくつかの情報を表示するためにconsole.logをloop関数内で使用するだけです
サンプルコードをmain.mjsファイルにコピー&ペーストし、PLAYをクリックしてください

Simple move

デフォルトのスクリプトフォルダはステップごとに違うため、今回は違う場所のファイルを編集するということを覚えておいてください
フォルダはいつでも変更することができます

これから、ユニットやCreepsに会いに行きましょう
ドキュメントから確認できるように、すべてのcreepは様々なアクションをとることができますし、もちろん動くことができます

creep.moveTo(target);

このコマンドはcreepをターゲットに向かって1ステップ動かします
毎回のloopで繰り返しこの関数を実行した場合、creepは目的地までのすべての道のりを動きます
creepは関数が呼ばれてすぐには動きません、loop関数が終了した後に実行されます
※console.logなどの関数はその場で実行されますが、ゲームで定義されている関数はLoopが終了してから実行されるため、表示されている内容が1ループ分ずれるなどします

どのようにしてコードからcreepsにアクセスするのでしょうか?getObjectsByPrototype()と呼ばれる関数があります
この関数はゲームオブジェクトの配列をプロトタイプやクラスとともに返します
以下のようにしてゲーム内のすべてのCreepsを指定することができます

import { getObjectsByPrototype } from '/game/utils';
import { Creep } from '/game/prototypes';

export function loop({
    var creeps = getObjectsByPrototype(Creep);
}

このステップではFlagというオブジェクトと名前が存在します
目的 : creepはFlagに向けて進めるためにmoveTo関数を使用します

import { getObjectsByPrototype } from '/game/utils';
import { Creep, Flag } from '/game/prototypes';

export function loop() {
    var creeps = getObjectsByPrototype(Creep);
    var flags = getObjectsByPrototype(Flag);
    creeps[0].moveTo(flags[0]);
}

First attack

Screeps Arenaはマルチプレイヤーのpvpゲームです
あなたのCreepsは対戦相手のCreepsと戦います.
ここではそれを学びましょう

どのCreepsがあなたのものでしょうか?
JavaScriptの標準機能である Array.filter()  か Array.find() メソッドは与えられた基準をもとに配列の要素を返します
今回のケースでは、基準はCreepsのmyというプロパティとなります

import { getObjectsByPrototype } from '/game/utils';
import { Creep } from '/game/prototypes';

export function loop({
    var myCreep = getObjectsByPrototype(Creep).find(creep => creep.my);
    var enemyCreep = getObjectsByPrototype(Creep).find(creep => !creep.my);
}

敵を倒すために attack というメソッドを使うことができます
これはターゲットに届かなかったとき、 ERR_NOT_IN_RANGE というエラーを返します。そのため、最初に moveTo を使う必要があります

if(myCreep.attack(enemyCreep) == ERR_NOT_IN_RANGE) {
    myCreep.moveTo(enemyCreep);
}

目標:敵creepを倒す

import { getObjectsByPrototype } from '/game/utils';
import { Creep } from '/game/prototypes';
import { ERR_NOT_IN_RANGE } from '/game/constants';

export function loop({
    var myCreep = getObjectsByPrototype(Creep).find(creep => creep.my);
    var enemyCreep = getObjectsByPrototype(Creep).find(creep => !creep.my);
    if(myCreep.attack(enemyCreep) == ERR_NOT_IN_RANGE) {
        myCreep.moveTo(enemyCreep);
    }
}

Creeps bodies

あなたは他のCreepの機能を使用することができます。しかし、それらのすべてを敵creepに使用できるわけではありません
creepが使用できるアクションはボディーパーツに依存し、それらはbodyプロパティから確認することができます
これはそれぞれの要素が、特定の種類の一つのボディーパーツを表す配列です

  • MOVE - creepの移動を有効にします

  • ATTACK - 近接攻撃ができます

  • RANGE_ATTACK - 3タイル分離れた位置から攻撃することができます

  • HEAL - 自分自身、もしくはほかのcreepを回復させることができます

  • WORK - ワーカーcreepは構造物を建築したり、エネルギーを回収したりできます

  • CARRY - creepのリソース運搬能力を増加させます

  • TOUGH - いかなる効果も持っていません

if(creep.body.some(bodyPart => bodyPart.type == ATTACK)) {
    // this creep has ATTACK body parts
}

すべてのボディーパーツはcreepのhits(HP)を100増やします
creepがダメージを受けたとき、ボディーパーツも同様にダメージを受け、パーツのカウンターが0になった時、機能しなくなります
同じタイプのボディーパーツが多いほど、それぞれの効果は強くなります

このステップではATTACK, RANGE_ATTACK,HEALの3種類のcreepが存在します
あなたはこれらのユニットの行動を調整し、敵を倒すことのみができます

これを行うには、前回のチュートリアルと同じように、しかしボディーパーツごとに異なる行動をとる必要があります
攻撃するユニットはattack,rangeattackのそれぞれの方法で攻撃する必要があり、ヒーラーはhealメソッドを行う必要があります

目標:敵creepを撃破する

import { getObjectsByPrototype } from '/game/utils';
import { Creep } from '/game/prototypes';
import { ERR_NOT_IN_RANGE, ATTACK, RANGED_ATTACK, HEAL } from '/game/constants';

export function loop({
    var myCreeps = getObjectsByPrototype(Creep).filter(creep => creep.my);
    var enemyCreep = getObjectsByPrototype(Creep).find(creep => !creep.my);

    for(var creep of myCreeps) {
        if(creep.body.some(bodyPart => bodyPart.type == ATTACK)) {
            if(creep.attack(enemyCreep) == ERR_NOT_IN_RANGE) {
                creep.moveTo(enemyCreep);
            }
        }
        if(creep.body.some(bodyPart => bodyPart.type == RANGED_ATTACK)) {
            if(creep.rangedAttack(enemyCreep) == ERR_NOT_IN_RANGE) {
                creep.moveTo(enemyCreep);
            }
        }
        if(creep.body.some(bodyPart => bodyPart.type == HEAL)) {
            var myDamagedCreeps = myCreeps.filter(i => i.hits < i.hitsMax);
            if(myDamagedCreeps.length > 0) {
                if(creep.heal(myDamagedCreeps[0]) == ERR_NOT_IN_RANGE) {
                    creep.moveTo(myDamagedCreeps[0]);
                }
            }
        }
    }
}

Store and transfer

アリーナごとに利用できるそれぞれのリソースがあります
しかし、基本の資源はRESOURCE_ENERGYの一種類のみです
それは、あなたが構造物を建築したり、creepをスポーンさせたり、そのほかいくつかのアクションに利用します。
このチュートリアルではTowerをチャージし、遠方の敵を撃破するのに利用します
Towerは50タイルの射程がありますが、距離減衰があります

tower.attack(target);

ショットごとに10ユニットのエネルギーをstoreから消費します
エネルギーをtransferするcreepを使うことで、チャージすることができます

creep.transfer(towerRESOURCE_ENERGY);

いくらかのエネルギーを持ったコンテナがstoreの近くにあります
あなたはそれにcreepを動かしwithdrawでエネルギーを引き出すことができます

creep.withdraw(containerRESOURCE_ENERGY);

タワーにエネルギーがチャージされたら、ターゲットを攻撃し、破壊します

今回のサンプルコードでは、import文の書き方を/gameからいくつかの名前空間を取得する方法に書き換えてあります
今までの方法とこの方法、使いやすい方を使ってみてください

目標:敵を撃破する

import { prototypes, utils, constants } from '/game';

export function loop({
    const tower = utils.getObjectsByPrototype(prototypes.StructureTower)[0];
    if(tower.store[constants.RESOURCE_ENERGY] < 10) {
        var myCreep = utils.getObjectsByPrototype(prototypes.Creep).find(creep => creep.my);
        if(myCreep.store[constants.RESOURCE_ENERGY] == 0) {
            var container = utils.getObjectsByPrototype(prototypes.StructureContainer)[0];
            myCreep.withdraw(container, constants.RESOURCE_ENERGY);
        } else {
            myCreep.transfer(tower, constants.RESOURCE_ENERGY);
        }
    } else {
        var target = utils.getObjectsByPrototype(prototypes.Creep).find(creep => !creep.my);
        tower.attack(target);
    }
}

Terrain

ゲーム内には5つのterrain(地形)があります

  • 平地

  • 自然の壊れない壁

  • 建設された、破壊可能な壁

  • 沼地

  • 道路

沼地と道路ではcreepsの重量の概念が働きます
MOVEを除くすべてのボディーパーツはcreepsの重量を増加させます
空のCARRYボディーパーツは重量を追加しませんが、資源が積み込まれている場合は重量が追加されます
MOVEボディーパーツはcreepの移動速度を増加させます
MOVEボディーパーツとほかのボディーパーツの割合が同じとき、creepは平地の上を毎tickごとに動くことができます
そうでない場合、creepはfatigue(疲労?)を蓄積し、動けないtickが発生します

しかし、先ほどと同じボディーパーツの状態で沼地の上にいるときには、creepはさらなるfatigueを蓄積し、5tickに一度しか移動できなくなります。
沼地の上で毎tick行動したい場合、MOVEパーツを5倍以上にしてください

道路の上では、必要なMOVEパーツは半分になります
たとえば、10の重さのパーツを持つばあい、5のMOVEパーツがあれば毎tick移動できます

このステップでは、すべてのcreepを対応するflagに移動させるだけです
ボディーパーツと地形に依存して移動速度が変わることに注意してください

findClosetByPathという関数を使うことができます
これはパスファインディングアルゴリズムによって最も近いオブジェクトを配列の中から取得することができます

var flags = getObjectsByPrototype(Flag);
svar closestFlag = creep.findClosestByPath(flags);

目標:すべてのcreepsがflagにたどり着く

import { getObjectsByPrototype, findClosestByPath } from '/game/utils';
import { Creep, Flag } from '/game/prototypes';

export function loop({
    var creeps = getObjectsByPrototype(Creep).filter(i => i.my);
    var flags = getObjectsByPrototype(Flag);
    for(var creep of creeps) {
        var flag = creep.findClosestByPath(flags);
        creep.moveTo(flag);
    }
}

Spawn creeps

Spawn施設を使ってArenaで遊ぶとき、spawnCreepメソッドを利用してcreepsを作り出すことができます
あなたは新しいcreepsのボディーをボディーパーツの配列を使って定義する必要があります
より大きなcreepをスポーンさせたいとき、storeからより大きなエネルギーを消費します
コストは以下の通りです

  • MOVE - 50 energy

  • WORK - 100 energy

  • CARRY- 50 energy

  • ATTACK- 80 energy

  • RANGE_ATTACK - 150 energy

  • HEAL - 250 energy

  • TOUGH - 10 energy

spawnCreepメソッドはcreepインスタンスを返します

var creep = mySpawn.spawnCreep([MOVE, ATTACK]).object;

そして、loop外で変数を定義して、tickのなかで使用することができます

var creep;
export function loop({
    if(!creep) {
        creep = mySpawn.spawnCreep([MOVE, ATTACK]).object;
    }
}

この場合のcreep変数には任意のプロパティを割り当てることができます
これはいくつかのターゲット、ロール、そのほかのデータ等creepに割り当てるのに役立ちます

creep.target = flag;

このステップにはSpawnと2つのflagがあります

目的:二つのcreepをスポーンさせそれぞれのcreepをフラッグに移動させる

import { getObjectsByPrototype } from '/game/utils';
import { Creep, Flag, StructureSpawn } from '/game/prototypes';
import { MOVE } from '/game/constants';

var creep1, creep2;

export function loop({
    var mySpawn = getObjectsByPrototype(StructureSpawn)[0];
    var flags = getObjectsByPrototype(Flag);

    if(!creep1) {
        creep1 = mySpawn.spawnCreep([MOVE]).object;
    } else {
        creep1.moveTo(flags[0]);

        if(!creep2) {
            creep2 = mySpawn.spawnCreep([MOVE]).object;
        } else {
            creep2.moveTo(flags[1]);
        }
    }
}

Harvest energy

エネルギーリソースは様々な形で利用できます
それはコンテナの中に保存されますが、Sourcesから掘り出すこともできます
もしcreepがWORKボディーパーツを持っている場合、harvest関数によってsourceからエネルギーを抽出することができます

creep.harvest(source);

creepはこのアクションをとるために、resourceの近くで停止する必要があります
より多くのWORKボディパーツがある場合、tickごとにより多くのエネルギーを抽出できます
sourceのエネルギーは無尽蔵で、ワーカーのcreepの容量が許すかぎり抽出することができます

目標:エネルギーを抽出してspawnに1000運ぶ

import { prototypes, utils, constants } from '/game';

export function loop({
    var creep = utils.getObjectsByPrototype(prototypes.Creep).find(i => i.my);
    var source = utils.getObjectsByPrototype(prototypes.Source)[0];
    var spawn = utils.getObjectsByPrototype(prototypes.StructureSpawn).find(i => i.my);

    if(creep.store.getFreeCapacity(constants.RESOURCE_ENERGY)) {
        if(creep.harvest(source) == constants.ERR_NOT_IN_RANGE) {
            creep.moveTo(source);
        }
    } else {
        if(creep.transfer(spawn, constants.RESOURCE_ENERGY) == constants.ERR_NOT_IN_RANGE) {
            creep.moveTo(spawn);
        }
    }
}

Construction

あなたができることはcreepをスポーンさせることだけではありません、建築物を建てることもできます
それを行うためには、いくつかのエネルギーとワーカーのcreepが必要です

まず、createConstructionSite関数を使ってConstructionSiteと呼ばれるおbyジェクトをゲーム中のいずれかの場所に設置します
そのためには、建てたい建築物のprototypeと座標を指定する必要があります

import { createConstructionSite } from '/game/utils';
import { StructureTower } from '/game/prototypes';

export function loop({
    var constructionSite = createConstructionSite({x50y55}, StructureTower);
}

エネルギーがチャージされたcreepが建築場所に近づき、build関数で建築する必要があります

creep.build(constructionSite);

建築用のすべてのアクションは成功時にcreepのstoreからエネルギーを消費します、そのため、creepは建設場所とエネルギー供給場所を往復する必要があります
作業が完了すると、新たな建造物が現れます

目標:タワーを建築する

import { prototypes, utils } from '/game';
import { RESOURCE_ENERGY, ERR_NOT_IN_RANGE } from '/game/constants';

export function loop({
    const creep = utils.getObjectsByPrototype(prototypes.Creep).find(i => i.my);
    if(!creep.store[RESOURCE_ENERGY]) {
        const container = utils.findClosestByPath(creep, utils.getObjectsByPrototype(prototypes.StructureContainer));
        if(creep.withdraw(container, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
            creep.moveTo(container);
        }
    } else {
        const constructionSite = utils.getObjectsByPrototype(prototypes.ConstructionSite).find(i => i.my);
        if(!constructionSite) {
            utils.createConstructionSite(50,55, prototypes.StructureTower);
        } else {
            if(creep.build(constructionSite) == ERR_NOT_IN_RANGE) {
                creep.moveTo(constructionSite);
            }
        }
    }
}

Final test

ここまででcreepsを制御する方法、敵を攻撃する方法、エネルギーを使って仕事をする方法、creepsをスポーンさせる方法、建築物を建てる方法について学びました
最後の試練に立ち向かう準備はできました!

このステップであなたははSpawnとSourceを持っています
さらに、敵のパーティがマップの隅から攻撃しにくるため、ワーカーのcreepをスポーンさせ、エネルギーを抽出し、さらにcreepsを生み出し、それらを撃退する必要があります
今回はサンプルコードはありません

このチュートリアルが終わった時、PvPアリーナに参加し、ほかの人と戦うことができます
楽しんでください!

目標:攻撃から生存し、すべての敵creepを撃破しチュートリアルをクリアする


この記事が気に入ったらサポートをしてみませんか?