NOVO Tank

by novogrammer forked from Wonderfl Tank Game Tank Sample 1 (diff: 73)
このコードを新着タンク一覧http://flash-games.wonderfl.net/tank/list/new
に表示させるにはinfinite-tank-entry
というタグをつけてください
コンセプトはステートレスに、それっぽく
反時計回りに適当ににげるだけ。単純な線形予測ロジックは前後移動に弱そう。
逃げるので予測は遠めに。距離によって予測もかえてみる。
はしにきたら方向転換を試みる でも反時計回り
_sceneの変数を代入するときはcopyしないと計算で値を壊す?
変数の名前に困るので、加(減)算命令は a+=bじゃなく a=b+cにしてほしかった。 
♥0 | Line 139 | Modified 2009-10-29 22:32:25 | MIT License | (replaced)
play

ActionScript3 source code

/**
 * Copyright novogrammer ( http://wonderfl.net/user/novogrammer )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/pp1W
 */

// forked from 9re's Wonderfl Tank Game Tank Sample 1
// このコードを新着タンク一覧http://flash-games.wonderfl.net/tank/list/new
// に表示させるにはinfinite-tank-entry
// というタグをつけてください

//コンセプトはステートレスに、それっぽく

//反時計回りに適当ににげるだけ。単純な線形予測ロジックは前後移動に弱そう。
//逃げるので予測は遠めに。距離によって予測もかえてみる。
//はしにきたら方向転換を試みる でも反時計回り

//_sceneの変数を代入するときはcopyしないと計算で値を壊す?
//変数の名前に困るので、加(減)算命令は a+=bじゃなく a=b+cにしてほしかった。 

package 
{
	import flash.display.Bitmap;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.display.BitmapData;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.utils.setTimeout;
	import flash.utils.Timer;
	
	import net.wonderfl.game.infinity_tank.development.*;
	import net.wonderfl.math.*;
	import net.wonderfl.utils.SequentialLoader;
	/**
	 * @author 9re
	 */
	// クラス名は必ずTankにして、TankBaseクラスを拡張して下さい
	// http://flash-games.wonderfl.net/static/asdoc/net/wonderfl/game/infinity_tank/tank/TankBase.html
	public class Tank extends TankBase
	{
		private var _gunFlag:Boolean = true;
		private var _lastBulletCount:int = 0;
		private var _spTank:Sprite;
		private var _spBattery:Sprite;
		private var _ctfm:ColorTransform;
		private var _images:Vector.<Bitmap>;
		private var _gun:Bitmap;
		private var _arr:Array = [];
		private var _i:int = -1;
		private var _j:int = 0;
		private var _mat:Matrix = new Matrix(1, 0, 0, 1, 5, 15);
		
		public function Tank() 
		{
           // 弾のクラスのurlをセットしてください
			// 弾のドキュメントクラスはBulletRendererBaseクラスを拡張したBulletRendererクラスである必要があります
			// 弾の一覧は、http://flash-games.wonderfl.net/tank/list/bullets
			// にあります.
			// http://flash-games.wonderfl.net/static/asdoc/net/wonderfl/game/infinity_tank/development/BulletRendererBase.html
			_bulletRenderer = "http://swf.wonderfl.net/swf/usercode/0/04/046c/046cee45b4334c4f2dac8dfa7ec9ea2b2b2eb27d.swf";
			
			_spTank = new Sprite;
			_spBattery = new Sprite;
			
			SequentialLoader.loadImages(["http://assets.wonderfl.net/images/tank/tankA_1.png", "http://assets.wonderfl.net/images/tank/tankA_2.png", "http://assets.wonderfl.net/images/tank/tankA_cannon.png"], _arr, onImageLoaded);
			
			_ctfm = new ColorTransform(1, 1, 1, 0);
			
			
			
			super();
		}

		private function onImageLoaded():void
		{
			_images = Vector.<Bitmap>(_arr.map(function ($ldr:Loader, $index:int, $arr:Array):Bitmap {
				var mat:Matrix = new Matrix;
				var bd:BitmapData = new BitmapData($ldr.width, $ldr.height, true, 0x00ffffff);
				bd.draw($ldr, mat);
				var bm:Bitmap = new Bitmap(bd);
				bm.x = -bm.width / 2;
				bm.y = -bm.height / 2;
				
				return bm;
			}));
			
			_gun = _images.pop();
			_gun.x = -5;
			
			_gun.y = -5;
			_spBattery.addChild(_gun);
			_i = 0;
			_images.forEach(function ($bm:Bitmap, $index:int, $vec:Vector.<Bitmap>):void {
				_spTank.addChild($bm);
			});
			_spTank.addChild(_spBattery);
		}
		
		// 5フレームに1度呼ばれるcallback
		// 現在のゲームの状態を見るには、_sceneオブジェクトのプロパティーを
		// 調べます.
		// @see http://flash-games.wonderfl.net/static/asdoc/net/wonderfl/game/infinity_tank/development/BattleScene.html
		override public function action():int
		{
			// 前回のactionで弾が撃たれたかどうかを調べる.
			// 人対AIのゲーム・バランスのために弾は同画面内に最大3発までしか
			// 撃てない.
			if (_lastBulletCount < _scene.myBulletCount) {
				// 前回た弾を撃っている場合は、撃たないようにフラグをセット
				_gunFlag = false;
				// 100ms後にフラグを解除
				setTimeout(clearGunFlag, 100);
			}
			// 現在の画面内にある弾の数を保存する.
			_lastBulletCount = _scene.myBulletCount;

            // フラグによって、撃つか撃たないかを判断
			var action:int = (_gunFlag) ? Command.FIRE : Command.DO_NOTHING;
			
			
            var pos:WVector2D = new WVector2D(_scene.myTankPosition.x,_scene.myTankPosition.y);
			// 敵の位置を取得.
			var enemyPos:WVector2D = _scene.enemyTankPosition;

            // 自分の位置を敵の位置から引く.
            // 自分から見た敵の位置を計算
			enemyPos.subtract(_scene.myTankPosition);
			
			// 敵との距離
			var enemyDistance:Number = enemyPos.length;
			
			// 敵の速度を取得
			var enemySpeed:WVector2D = _scene.enemyTankLinearVelocity;
			// 0.25+距離100あたりに0.3秒の位置を線形で予想
			enemySpeed.scale(0.25 + enemyDistance/100*0.3);
			enemyPos.add(enemySpeed);
			
			// 自分からみた敵の方向を計算する.
			var angle:Number = Math.atan2(enemyPos.y, enemyPos.x);
			// 敵の方向をコピー
			var direction:Number = angle;
			
			// 敵の方向と自分の砲台の向いている方向の差を計算
			angle -= (_scene.myTankAngle + _scene.myGunAngle);
			// 敵の方向と自分のタンクの向いている方向の差を計算
			direction -= _scene.myTankAngle;
			
			// 角度を0~2πに丸める
			angle = WMath.modulo2PI(angle);
			direction = WMath.modulo2PI(direction);
			
    		//右側を向いておく
			// 角度が0~πの場合は敵は砲台より右側にいる.
			if (angle <= Math.PI) action |= Command.GUN_TURN_RIGHT;
			// 角度がπより大きい場合は敵は砲台の左側にいる.
			else action |= Command.GUN_TURN_LEFT;

			//中心座標
            var centerVec:WVector2D=new WVector2D(600/2,550/2);
            //自分を起点に中心座標へのベクトル
			centerVec.subtract(pos);
			
			//中心からの距離が240より大きいときは緊急行動(副作用:玉よけ)
            if(centerVec.length>240)
            {
                if(Math.random()<0.15)//いつもより多めにバック
               {
                   action |= Command.TANK_MOVE_BACKWARD;
                   }
    		    else
    		    {
    		        action |= Command.TANK_MOVE_FORWARD;
    		    }
		        action |= Command.TANK_TURN_LEFT;
            }
       		else
       		{
                //ちょっと左よりを軸に判定(ランダム)
    			var dir2:Number=WMath.modulo2PI(direction+Math.PI/2-Math.PI/3*Math.random());
    			// 角度が0~πの場合は敵は自分の向いている方向の右側にいる.
    			if (dir2 <= Math.PI) action |= Command.TANK_TURN_RIGHT;
    			// 角度がπより大きい場合は敵は自分の向いている方向の左側にいる.
    			else action |= Command.TANK_TURN_LEFT;
    			
    			//たまに後ろにさがるとよさげだった
               if(Math.random()<0.05)
               {
    		        action |= Command.TANK_MOVE_BACKWARD;
    		    }
    		    else
    		    {
        		    action |= Command.TANK_MOVE_FORWARD;
                }
    	    }

			return action;
		}
		
		private function clearGunFlag():void
		{
			_gunFlag = true;
		}
		
		// 毎フレームごとに呼ばれる描画callback
		// stageと同じ大きさのBitmapDataが渡されます.
		// 現在のゲームの状態を見るには、_sceneオブジェクトのプロパティーを
		// 調べます.
		// @see http://flash-games.wonderfl.net/static/asdoc/net/wonderfl/game/infinity_tank/development/BattleScene.html
		override public function draw(bitmapData:BitmapData):void
		{
			// 砲台の向きをセットします.
			// 砲台はタンクのSpriteの子供のスプライトです.
			_spBattery.rotation = _scene.myGunAngle * 180 / Math.PI;
			
			
			if (_i > -1) {
				_i = (_j & 1) ? 1 : 0;
				var bm:Bitmap = _images[_i];
				bm.visible = true;
				_i = 1 - _i;
				bm = _images[_i];
				bm.visible = false;
				_j++;
				_j &= 3;
			}
			
			// 単位行列にセット
			_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);
		}
		
		// called when a bullet hits this tank
		override public function hit():void {
			// 被弾したときに呼ばれるcallbackです.
		}
		
		// called when this tank fires
		override public function fire():void 
		{
			// 弾が発射される時に呼ばれるcallbackです.
		}
	}
}