タンクを改造しよう!

デフォルトタンクを改造
以下のドキュメントを読んだらまずはここからデフォルトのタンクへ。あなただけの最強タンクを作ろう!
他のユーザータンクを改造
タンクの下に表示されている「このタンクを改造」ボタンをクリックしていろんなタンクを改造しよう
asdoc
改造方法の詳細を調べたい方はASDocをご覧ください。

タンク改造ファーストステップ

  1. はじめに
  2. タンクの外観をつくる
  3. タンクのAIをつくる
  4. 弾の外観をつくる

1. はじめに

戦車や弾のクラスを拡張することによって、オリジナルの戦車や弾を作ってゲーム上のキャラクターとして 登場させることが可能です。
そのためにはまず、ゲームの基本的な座標について知る必要があります。
座標系は普通のフラッシュと同じで下の図にあるように、ステージの左上隅が(0, 0), 右上隅が(600, 0), 左下隅が (0, 550)となっています。

coordinate system of the stages

戦車や弾の座標は全て中心座標で表されていますのでご注意下さい。

作った砲弾や戦車をゲームのキャラクターとして登場させるには、

  • TankBaseの拡張を実装したwonderflのコードのページでinfinite-tank-entryというタグをつけると、新着タンク一覧のページに登場し、対戦にエントリーすることができます。
  • BulletRendererBaseの拡張を実装した wonderflのコードページでinfinite-tank-bulletというタグをつけると、新着砲弾のページに登場するようになります。

ページトップへ

2. タンクの外観をつくる

まずは、TankBaseクラスのdrawメソッドを拡張することから始めます。

タンクは本体と主砲の二つのパーツからなります。戦車には向きがありますが、 x軸方向を0度として時計回りを正として角度を取ります。
戦車の辺り判定の大きさは50x30ピクセルで右向きを正面が0度の基本の状態となりますので、
画像を作る場合はなるべくこの大きさで書くようにお願いします。
引数として画面と同じサイズのBitmapDataが渡されます。

drawメソッドは毎エンターフレーム毎に呼ばれます。

以下がサンプル・コードになりますが、_spBatteryは砲台のビットマップが乗っているSpriteのインスタンス、 _spTankはタンクの画像が載っているSpriteのインスタンスであるとします。
座標は全て中心座標で渡されますので、画像の中心が基点となるように画像の位置を調節してください。
_spBatteryは_spTankの子供のスプライトです.もし、タンクを親子関係にしないのであれば、
_spBattery.rotation = _scene.myGunagnle + _scene.myTankAngle
となることにご注意下さい.

private var _spBattery:Sprite;                                         // 砲台のグラフィック
private var _spTank:Sprite;                                            // 戦車のグラフィック
private var _mat:Matrix;                                               // drawメソッドでの表示位置の調整用
private var _ctfm:ColorTransform = new ColorTransform(1, 1, 1, 0);     // BitmapDataを消去する

override public function draw(bitmapData:BitmapData):void
{
    // 砲台を回転させる.
    // _spTank.addChild(_spBattery);
    _spBattery.rotation = _scene.myGunAngle * 180 / Math.PI;
    
    // タンクの座標と傾きをセットする
    _mat.identity();
    _mat.rotate(_scene.myTankAngle);
    _mat.translate(_scene.myTankPosition.x, _scene.myTankPosition.y);
    
    // bitmapDataを一旦クリアする
    bitmapData.colorTransform(bitmapData.rect, _ctfm);
    // bitmapDataを描画する
    bitmapData.draw(_spTank, _mat, null, null, null, true);
}

ページトップへ

3. タンクのAIをつくる

TankBaseクラスのactionというメソッドをオーバーライドすることにより、 人工知能を実装することが可能となります。
TankBaseはprotectedなプロパティーとして、_sceneという、BattleSceneのインスタンス を持っています。
この_sceneのプロパティーを調べることで、ゲームのフィールドの現在の 状態を取得することができます。

詳しくはasdocのBattleSceneクラスのプロパティーを ご覧下さい。
例えば、現在の自分の戦車の位置や相手の戦車の位置角度 角度測度や、速度といったものが取得できます。
速度については、Box2DがMKS単位系で データを管理しているため、一秒間に何ピクセル動くかという値が帰ってきます。
myBulletListやenemyBulletListには弾の座標などのデータが収まっています。

actionメソッドは、ゲームのクラスから100msごとに呼び出され、そのときに返す 値を次の戦車の指令として実行します。
値はCommandクラスで定義されている 整数型のフラグのBit OR演算によって定義します。詳しくはasdocのCommandクラス の所をご覧下さい。

またゲームの制約として、Command.FIRE - 主砲を打つは 同じ画面内に弾は3発までしか撃てません.
これはAIと人間が 戦った時のバランスとして設けています。

以下がサンプル・コードとなります。まず、Command.FIREフラグをセットしていますので、 この戦車のAIは兎に角いつも弾を撃ちます。ただ撃っても当たらなければ意味が無いので、 敵の方向を計算します。_sceneオブジェトには自分の現在の位置や敵の現在の位置が取得できます。

このサンプル・コードを改良してより良いAIを作ってみてください。

override public function action():int
{
    // 弾を撃つ
    var action:int = Command.FIRE;
    // タンクを前進させる.
    action |= Command.TANK_MOVE_FORWARD;
    
    // 敵の位置を取得
    var enemyPos:WVector2D = _scene.enemyTankPosition;
    // 自分の位置を取得
    var myPos:WVector2D = _scene.myTankPosition;
    
    // 自分の位置からみた敵の位置を取得
    enemyPos.subtract(myPos);
    // 自分の位置からみた敵の位置を方角に直す
    var angle:Number = Math.atan2(enemyPos.y, enemyPos.x);
    // 自分の砲台が向いている方角と敵の方角との差をとる
    angle -= (_scene.myGunAngle + _scene.myTankAngle);
    
    // 角度を0~2πに直す.
    angle = WMath.modulo2PI(angle);
    
    // 砲台を適切な角度に向ける.
    
    // 角度が180度以下なら敵は砲台より右側にいる.
    if (angle < Math.PI) action |= Command.GUN_TURN_RIGHT;
    // 角度が180度以上ということは敵は砲台より左側にいる.
    else if (angle > Math.PI) action |= Command.GUN_TURN_LEFT;
    
    return action;
}

ページトップへ

4. 弾の外観をつくる

弾の概観を作るにはBulletRendererBaseクラスを拡張し、 drawメソッドをオーバーライドすることによって実現します。

drawメソッドは引数を一つとり、引数にはステージと同じサイズの BitmapDataが渡されます。このBitmapDataに弾を直接書くことにより、 弾の概観を定義します。
BulletRendererBaseクラスは_sceneというprotectedなプロパティーとして BattleSceneのインスタンスを持っていますので、これを参照することにより、 画面上にある弾の座標を取得することが出来ます。

弾の形は弾の角度が0度(x軸方向を向いている)の状態で6ピクセル x 4ピクセルの長方形となっています。

_scene

override public function draw($bitmapData:BitmapData):void {
    $bitmapData.lock();
    // 弾道の尾を引かせるために前の像をアルファで少し残す
    $bitmapData.colorTransform($bitmapData.rect, new ColorTransform(1, 1, 1, 0.8));
    // myBulletListが自分の弾のリスト。このようにfor文で回す
    for (var i:BoundBox = _scene.myBulletList; i; i = i.next) {
     // i.positionに弾の座標が入ります。中心座標なので、左へ2、上へ3だけずらします
        _point.x = i.position.x - 2;
        _point.y = i.position.y - 3;
        // _bulletには弾の画像が入っているものとします
        $bitmapData.copyPixels(_bullet, _bullet.rect, _point);
    }
    $bitmapData.unlock();
}

ページトップへ