対戦型ロボットゲームで楽しくJavaプログラミング学習「Robocode」(その1:準備編)
かなり昔、Javaのプログラミング教材として「Robocode」というオープンソースソフトウェアが公開されました。(Wikipediaによると初版は2001年に公開されているとのこと。もう20年以上も前ですね)
一時期はほとんど更新が止まっていたのですが、最近になって最新版が公開されていることを発見しました。
つい懐かしくなってダウンロードして遊んでみました。
Robocode とは
#Robocode は、対戦型のロボットシミュレーションゲームです。
ロボット(戦車型ロボット)をプログラミングして、他の人が作ったロボットコードと対戦させることが可能です。
ロボットを動作させるフレームワークが用意されているので、ロボットコードの作成に専念することができます。
対戦で勝ち残るために色々と工夫してプログラミングしていくことで、楽しくプログラミングが学習できるようになっています。
当初、プログラミング言語には Java が採用されていましたが、最新版では .NET(C#など)もサポートされていて、JavaScriptで作ることもできるようです。
今回は Java版を使用していきます。
また、既存のプラットフォームではなく、現在開発中である新しいプラットフォームを導入して、Robocode の世界に触れてみたいと思います。
事前準備(JDK)
#Robocode の実行にはJDK(バージョン11以降)が必要です。
各自の環境に合わせてJDKをインストールしておいてください。
(私は OpenJDK 11 をインストールしました)
Java のバージョン確認方法
java -version
環境セットアップ
#robocode-de/tank-royal から、開発中の最新版パッケージをダウンロードします。
2023/09/09時点での最新版は 0.20.0 です。
公式ドキュメントを参照して環境をインストールしていきます。
まず Robocode のGUIアプリケーションをダウンロードします。
GUIアプリケーションは最新版リリースサイトにある Assets セクションの「GUI Application (jar)」をダウンロードします。
ダウンロードした JARファイルを適当なフォルダの下に格納します。
私は Windows のドキュメントフォルダの下に「bots」フォルダを作成して、その下に JARファイルを格納しました。
C:\Users\<ユーザ名>\Documents\bots\robocode-tankroyale-gui-0.20.0.jar
次にサウンドファイルをダウンロードします。
このサウンドファイルのインストールはオプションですので、ゲームの効果音が不要な場合、セットアップしなくて大丈夫です。
サウンドファイルはRobocode音源のリリースサイトにある Assets セクションの「sounds.zip」をダウンロードします。
2023-09-09時点での最新版は 1.0.0 です。
ダウンロードした Zipファイルを解凍して取得した「sound」フォルダを、先ほど作成した「bots」フォルダの下に置きます。
(soundフォルダの下にはいくつかの wavファイルが格納されています)
C:\Users\<ユーザ名>\Documents\bots\sounds
ここまで出来たら、ロボットの実行環境を起動させてみます。
コマンドプロンプトにて、ディレクトリを「C:\Users\<ユーザ名>\Documents\bots」に移動し、次のコマンドを実行します。
java -jar robocode-tankroyale-gui-0.20.0.jar
以下のようなGUIアプリケーションが起動すれば、インストールは成功です。
環境設定にてロボットのソースコードを配置するルートフォルダを設定します。
GUIアプリケーションの「Config」-「Bot Root Directories」を選択します。
Bot Root Directories Config ダイアログが表示されるので、「Add」ボタンからルートフォルダを設定します。
(ルートフォルダは「C:\Users\<ユーザ名>\Documents\bots」とします)
「OK」ボタンを押してダイアログを閉じます。
GUIアプリケーションを終了する場合は、右上の「✕」ボタンを押して終了させます。
サンプルBotの実行
#サンプルBot は最新版リリースサイトにある Assets のセクションから「Sample bots for Java (zip)」をダウンロードします。
ダウンロードした Zipファイルを解凍し「bots」フォルダの下に置きます。
「bots」フォルダの下は以下のようになっているはずです。
以下のコマンドを実行し、GUIアプリケーションを起動します。
java -jar robocode-tankroyale-gui-0.20.0.jar
GUIアプリケーションが起動したら「Battle」-「Start Battle」を選択します。
Select Bots for Battle ダイアログが表示されます。
Bot Directories(local only)にサンプルBotたちが表示されれば、正しくサンプルBotのセットアップが出来ています。
サンプルBotの中の「MyFirstBot」と「MyFirstDroid」を選択し、「Boot」ボタンを押して、選択したBotを「Booted Bots(local only)」に入れます。
すると、BootしたBotが「Joind Bots(local/remote)」に表示されます。
「Joind Bots(local/remote)」に表示されているBotを選択し、「Add」ボタンを押して、選択したBotを「Selected Bots(battle participants)」(バトルに参加)にセットします。
バトルに参加するBotが決まると、ダイアログの一番下にある「Start Battle」ボタンが有効になるので「Start Battle」ボタンを押してバトルに参加します。
フィールドに戦車型ロボットが2台表示されます。
一台は棒立ちしていて(MyFirstDroid)、もう一台が敵戦車をスキャンしながら、砲塔から弾を発射して敵戦車を攻撃します(MyFirstBot)。
何度か攻撃して敵戦車が破壊されると、Roundが更新されて次のバトルが始まります。
バトルを一時停止する場合は「Pause」ボタンを、終了する場合は「Stop」ボタンを押します。
意外と効果音の音量が大きいので、効果音を止めたい場合は「Config」-「Sound Options」から効果音をOFFにすることが出来ます。
サンプルソースコード「MyFirstBot」を覗いてみる
#サンプルソースコードにある「MyFirstBot.java」ファイルを覗いてみます。
ソースコードは「MyFirstBot」フォルダの下にあります。
import dev.robocode.tankroyale.botapi.*;
import dev.robocode.tankroyale.botapi.events.*;
// ------------------------------------------------------------------
// MyFirstBot
// ------------------------------------------------------------------
// A sample bot original made for Robocode by Mathew Nelson.
// Ported to Robocode Tank Royale by Flemming N. Larsen.
//
// Probably the first bot you will learn about.
// Moves in a seesaw motion, and spins the gun around at each end.
// ------------------------------------------------------------------
public class MyFirstBot extends Bot {
// The main method starts our bot
public static void main(String[] args) {
new MyFirstBot().start();
}
// Constructor, which loads the bot config file
MyFirstBot() {
super(BotInfo.fromFile("MyFirstBot.json"));
}
// Called when a new round is started -> initialize and do some movement
@Override
public void run() {
// Repeat while the bot is running
while (isRunning()) {
forward(100);
turnGunRight(360);
back(100);
turnGunRight(360);
}
}
// We saw another bot -> fire!
@Override
public void onScannedBot(ScannedBotEvent e) {
fire(1);
}
// We were hit by a bullet -> turn perpendicular to the bullet
@Override
public void onHitByBullet(HitByBulletEvent e) {
// Calculate the bearing to the direction of the bullet
var bearing = calcBearing(e.getBullet().getDirection());
// Turn 90 degrees to the bullet direction based on the bearing
turnLeft(90 - bearing);
}
}
MyFirstBotは「Bot」クラスを継承して作成されています。
いくつかのメソッドがオーバーライドされています。
このあたりのメソッドに独自のコードを追加してロボットをアップデートしていくことになるようです。
まとめ
#強い戦車型ロボットを作って、世界中の人と対戦できるのはとても楽しそうですね。
次回以降、Robocode の世界をさらに探検してみようと思います。