- http://www.youtube.com/watch?v=dqHmp_kMz-U-デュエル
- http://www.youtube.com/watch?v=eqlPbtO3rQY-デュエル
- http://www.youtube.com/watch?v=zx7xFJiBGZQ-戦い、2つのロボット、それぞれ自分用
- http://www.youtube.com/watch?v=EJPskFGvGi8-戦い、Portiaロボット(ターコイズ)に注意してください -これはこのカテゴリーで最高の戦闘機の1つです
はじめに
この記事では、読者はアルゴリズムとオブジェクト指向プログラミングの一般原則に精通しているだけでなく、Java言語に精通している、または他の言語の知識をそれに投影できることを意味します。
Robocodeには4つの公式トーナメントがあります。
- 決闘、フィールドに2台のロボット800〜600
- ファイト(近接)、フィールド上で10個のロボット、1000個ごとに1000個
- チーム、1200〜1200のフィールドごとに5ロボットの2チーム
- ダブルデュエル(TwinDuel)、フィールドに2台のロボットからなる2チーム800〜800
決闘と戦いには4つのウェイトカテゴリがあります。
- Nano <= 249バイトの実行可能コード
- マイクロ<= 749バイトの実行可能コード
- ミニ<= 1499バイトの実行可能コード
- メガ(一般)-無制限
一般的な重量のカテゴリで決闘のロボットを書く最初のステップを検討します。 実際、この記事のロボットはミクロのカテゴリーに当てはまりますが、バイトコードサイズの最適化は科学全体であり、その知識は成功したナノボットの開発に必要であり、この記事では一切開示されていません。
準備する
チャンピオンのプログラミングを開始するには、少なくともダウンロードしてインストールする必要があります。
- Javaの最新バージョン(ただし、現時点ではゲームは公式にJava 6のみをサポートしているため、このバージョン用にロボットをコンパイルする必要があります)
- Robocodeの最新バージョン(ここでも、公式大会では最新バージョンがサポートされていないため、ロボットが現在サポートされているバージョンにないAPIを使用しないようにしてください)。
また、ダウンロードとインストールを強くお勧めします。
- 最新のJava IDEの最新バージョン(質問がある場合はPMでお願いします)
- Antビルドシステム
ゲーム物理学
なぜなら このセクションとともに、記事は非常に大きくなり、このセクションは非常に高度であるため、最初のステップを実行するために読んで理解する必要はありません。別の記事に掲載します。
UPD:物理学に関する記事を公開http://habrahabr.ru/post/147956/
ロボット制御と外界との相互作用
一般的に、ゲームにはクラスの階層全体があり、そこから継承してロボットを作成できます。 一度に1つのコマンドのみを実行できる「単純な」robocode.Robotクラスがあります。 移動、回転、または撃ちます(ただし、ボーナスがあります-そのようなロボットは壁との衝突によるダメージを受けません)。 しかし、私の意見では、そのようなロボットのプログラミングはより逆であり、私はrobocode.AdvancedRobotクラスから継承することをお勧めします(将来的にはあなたが私の推奨に従ったという仮定から進めます)。 robocode.TeamRobotクラスも面白くないため、コマンドを作成できますが、これは別の記事の別のトピックです。
ロボットは多くのコマンドで制御されますが、最も重要なもののみを示します。
- setAhead-指定したピクセル数だけ最大速度で前進します(ロボットが現在後退している場合は減速します)。 引数が負の場合、ロボットは戻ります
- setFireとsetFireBullet-与えられた力で撃ちます。
- setTurnRightRadians、setTurnLeftRadians、setTurnGunRightRadians、setTurnGunLeftRadians、setTurnRadarRightRadians、setTurnRadarLeftRadians-対応する方向にラジアンで指定された角度だけ対応する部分を回転します(ラジアン単位のメソッドはありません)。 * RightRadians-対応する部分を時計回りに回転します* LeftRadians、それぞれ反時計回りに回転します。
各ターンの開始時に、ロボットは最後のコマンドの実行中に発生した一連のイベントを受け取ります。 多くのイベントがありますが、最も重要なイベントのみを紹介します。
- StatusEvent-ロボットの状態(位置、速度、部品の方向など)。
- DeathEvent-ロボットは破壊されたばかりです。
- BulletHitEvent-ロボットの弾丸が別のロボットに当たりました。
- HitByBulletEvent-敵の弾丸がロボットに当たります。
- HitRobotEvent-敵との衝突が発生しました。
- HitWallEvent-壁の衝突が発生しました。
- ScannedRobotEvent-最後の動きが敵によって検出されました。 このイベントには、敵に関するいくつかの情報が含まれています(敵の位置、エネルギー、動きの方向を計算するために必要なすべての情報)。
組立準備
何らかの理由でアセンブリにantを使用しないことに決めた場合は、このセクションをスキップできます。 ここからリポジトリをダウンロードできます: https : //github.com/aleksey-zhidkov/HabrahabrTutorial 、または自分の手で次のフォルダー構造を作成します。
/ HabrahabrTutorial +-/ src -build.properties -build.xml
build.propertiesファイルの内容は次のとおりです。
bin.dir = bin builds.dir =ビルド robocode.dir =; Robocodeホームディレクトリへのパス、デフォルトではC:\\ Robocode(Javaプロパティ形式に注意を払う必要があり、スラッシュはエスケープする必要があります) robocode.jar = $ {robocode.dir} \\ libs \\ robocode.jar
build.xmlファイルの内容は次のとおりです。
<?xml version="1.0" encoding="UTF-8"?> <project name="HabrahabrTutorial" basedir="." default="release"> <property file="build.properties"/> <property name="robot.version" value="0.1"/> <property name="robot.package" value="ru.jdev.habrahabr"/> <property name="robot.path" value="ru/jdev/habrahabr"/> <property name="robot.name" value="HabrahabrTutorial"/> <path id="src.files"> <pathelement location="src"/> </path> <target name="init"> <mkdir dir="${bin.dir}"/> </target> <target name="compile" depends="init" description="Compiles source files"> <javac destdir="${bin.dir}" debug="on" debuglevel="lines,vars,source" optimize="yes" target="1.6"> <src refid="src.files"/> <classpath> <pathelement location="${robocode.jar}"/> </classpath> </javac> </target> <target name="clean" description="Deletes all previous build artifacts"> <delete dir="${bin.dir}"/> </target> <target name="release" depends="clean, compile"> <copy todir="${bin.dir}"> <fileset dir="src"/> </copy> <echo file="${bin.dir}/${robot.path}/${robot.name}.properties">robocode.version=1.7.3 robot.java.source.included=true robot.version=${robot.version} robot.author.name=Alexey jdev Zhidkov robot.classname=${robot.package}.${robot.name} robot.name=${robot.name} robot.description=Tutorial robot for habrahabr.ru </echo> <jar destfile="${builds.dir}\${robot.package}.${robot.name}_${robot.version}.jar" compress="true"> <fileset dir="${bin.dir}"/> </jar> <copy todir="${robocode.dir}\robots\"> <fileset file="${builds.dir}\${robot.package}.${robot.name}_${robot.version}.jar"/> </copy> <delete includeEmptyDirs="true"> <fileset dir="${bin.dir}" includes="**/*"/> </delete> </target> </project>
すべてを正しく行った場合、プロジェクトのルートでantコマンドを実行すると、HabrahabrTutorial \ builds \ ru.jdev.habrahabr.HabrahabrTutorial_0.1.jarファイルが表示されるはずです。このファイルには、ru \ jdev \ habrahabr \ HabrahabrTutorial.propertiesファイルが含まれているはずです。 (Javaから遠く離れている人のために、jarは任意のアーカイバで開くことができる通常のzipアーカイブであることを説明します)。
ロボットを作成する
前のセクションのディレクトリで選択した開発環境でプロジェクトを作成し、ライブラリ$ {robocode_home} /libs/robocode.jarをそれに接続します。 次に、ロボット自体を含むフォルダーにコードをコンパイルするか、アセンブリ中に前のセクションのスクリプトを使用するように環境を構成します。 最後に、次のコードで新しいクラスru.jdev.habrahabr.HabrahabrTutorialを作成します。
package ru.jdev.habrahabr; import robocode.AdvancedRobot; public class HabrahabrTutorial extends AdvancedRobot { @Override public void run() { while (true) { /** * , * */ execute(); } } }
ゲームを起動し、[バトル]-> [新規]を選択し、ru.jdev.habrahabr.HabrahabrTutorialがロボットのリストに表示されることを確認します。
ステップ1:死後に退出し、敵の位置を計算し、レーダーを制御して引きます。
コードを次の形式にします(ここで、すべてのコメントはコードで直接指定されます。また、以降、追加された行またはメソッドはコメント/ * + * /でマークされ、変更された行またはメソッドはコメント/ *〜* /でマークされます):
package ru.jdev.habrahabr; import robocode.AdvancedRobot; import robocode.DeathEvent; import robocode.ScannedRobotEvent; import robocode.util.Utils; import java.awt.*; import java.awt.geom.Point2D; import static java.lang.Math.signum; import static java.lang.Math.toRadians; public class HabrahabrTutorial extends AdvancedRobot { /*+*/private static final double RADIANS_5 = toRadians(5); /*+*/private boolean isAlive = true; /*+*/private double enemyX = -1; /*+*/private double enemyY = -1; @Override public void run() { /*+*/setTurnRadarRightRadians(Double.POSITIVE_INFINITY); // /*~*/while (isAlive) { // true, /*+*/if (enemyX > -1) { // /*+*/final double radarTurn = getRadarTurn(); /*+*/setTurnRadarRightRadians(radarTurn); /*+*/} /** * , * */ execute(); } } /*+*/private double getRadarTurn() { // // : final double alphaToEnemy = angleTo(getX(), getY(), enemyX, enemyY); // , , (Utils, Robocode ): final double sign = (alphaToEnemy != getRadarHeadingRadians()) ? signum(Utils.normalRelativeAngle(alphaToEnemy - getRadarHeadingRadians())) : 1; // 5 return Utils.normalRelativeAngle(alphaToEnemy - getRadarHeadingRadians() + RADIANS_5 * sign); // , setTurnRadarRightRadians, // } @Override /*+*/public void onScannedRobot(ScannedRobotEvent event) { /** ScannedRobotEvent , , , * , ( -, ) */ // final double alphaToEnemy = getHeadingRadians() + event.getBearingRadians(); // enemyX = getX() + Math.sin(alphaToEnemy) * event.getDistance(); enemyY = getY() + Math.cos(alphaToEnemy) * event.getDistance(); } @Override /*+*/public void onDeath(DeathEvent event) { isAlive = false; } @Override /*+*/public void onPaint(Graphics2D g) { // , // , // Paint if (enemyX > -1) { g.setColor(Color.WHITE); g.drawRect((int) (enemyX - getWidth() / 2), (int) (enemyY - getHeight() / 2), (int) getWidth(), (int) getHeight()); } } /** * Robocode - 0 : * 90 - , 180 - , 270 - , 360 - . * <p/> * - . * , , , , */ /*+*/private static double angleTo(double baseX, double baseY, double x, double y) { double theta = Math.asin((y - baseY) / Point2D.distance(x, y, baseX, baseY)) - Math.PI / 2; if (x >= baseX && theta < 0) { theta = -theta; } return (theta %= Math.PI * 2) >= 0 ? theta : (theta + Math.PI * 2); } }
ステップ2:はじめに
ランダムな軌道運動の初歩を理解します。 オービタルとは、敵が静止し、ランダムに常に一方向を与える場合、戦車が敵の周りを旋回することを意味します。 そして、ランダムなコンポーネントは、私たちの戦車をもう少し難しいターゲットにします。 この動きを実装するには、2つのメソッドを追加します。
private double getDistance() { // return 200 - 400 * random(); } private double getBodyTurn() { // final double alphaToMe = angleTo(enemyX, enemyY, getX(), getY()); // ( , ) ... final double lateralDirection = signum((getVelocity() != 0 ? getVelocity() : 1) * Math.sin(Utils.normalRelativeAngle(getHeadingRadians() - alphaToMe))); // final double desiredHeading = Utils.normalAbsoluteAngle(alphaToMe + Math.PI / 2 * lateralDirection); // final double normalHeading = getVelocity() >= 0 ? getHeadingRadians() : Utils.normalAbsoluteAngle(getHeadingRadians() + Math.PI); // return Utils.normalRelativeAngle(desiredHeading - normalHeading); }
そして、メインループで敵が検出されたという条件内で、次の行を追加します。
setTurnRadarRightRadians(radarTurn); /*+*/ final double bodyTurn = getBodyTurn(); /*+*/ setTurnRightRadians(bodyTurn); /*+*/ /*+*/ if (getDistanceRemaining() == 0) { /*+*/ final double distance = getDistance(); /*+*/ setAhead(distance); /*+*/ } }
ステップ3:発射!
最も単純な照準アルゴリズムを実装し、敵の現在の位置を撃ちます。 この目標を達成するために、ロボットは常に敵を銃口に保ち、できるだけ早く撃ちます。 タスクは1つの方法で実装されます。
private double getGunTurn() { // : , : return Utils.normalRelativeAngle(angleTo(getX(), getY(), enemyX, enemyY) - getGunHeadingRadians()); }
そして、メインループに3行追加します。
setAhead(distance); } /*+*/ final double gunTurn = getGunTurn(); /*+*/ setTurnGunRightRadians(gunTurn); /*+*/ setFire(2); }
次は何ですか
そして、ロボットにようこそ、またはこのトピックに興味のあるコメントを書いてください。ゲームのすべての基本的なテクニックを徐々に強調していきます。 この投稿を最後までマスターした皆さんに感謝します。
PSこれは私の最初のチュートリアルですので、建設的な批判に喜んでいます