のっくあうと

by uwi forked from Wonderfl Tank Game Tank Sample 1 (diff: 277)
このコードを新着タンク一覧http://flash-games.wonderfl.net/tank/list/new
に表示させるにはinfinite-tank-entry
というタグをつけてください
♥0 | Line 203 | Modified 2009-10-11 07:38:49 | MIT License | (replaced)
play

ActionScript3 source code

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

// forked from 9re's Wonderfl Tank Game Tank Sample 1
// このコードを新着タンク一覧http://flash-games.wonderfl.net/tank/list/new
// に表示させるにはinfinite-tank-entry
// というタグをつけてください
package 
{
	// ai0
	import Box2D.Common.Math.b2Vec2;
	
	import flash.display.Bitmap;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.display.BitmapData;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.TimerEvent;
	import flash.filters.*;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;
	import flash.system.Security;
	import flash.utils.setTimeout;
	import flash.utils.Timer;
	import flash.net.*;
	
	import net.wonderfl.game.infinity_tank.core.UserActionHandler;
	import net.wonderfl.game.infinity_tank.model.*;
	import net.wonderfl.game.infinity_tank.tank.TankBase;
	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 _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 _arrCommands:Array = [Command.FIRE, Command.GUN_TURN_LEFT, Command.GUN_TURN_RIGHT, Command.TANK_MOVE_BACKWARD, Command.TANK_MOVE_FORWARD, Command.TANK_TURN_LEFT, Command.TANK_TURN_RIGHT];
		private var _mat:Matrix = new Matrix(1, 0, 0, 1, 5, 15);
		
		public function Tank() 
		{
            // 弾のクラスのurlをセットしてください
			// 弾のドキュメントクラスはBulletRendererBaseクラスを拡張したBulletRendererクラスである必要があります
			// http://flash-games.wonderfl.net/static/asdoc/net/wonderfl/game/infinity_tank/bullet/BulletRendererBase.html
			_bulletRenderer = "http://swf.wonderfl.net/swf/usercode/8/8f/8faa/8faa6f4c1148ad9a535d25bdd49b7e4d98d02030.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/tankB_cannon.png"], _arr, onImageLoaded);
			
			_ctfm = new ColorTransform(1, 1, 1, 0);
		}
		
		private function onImageLoaded():void
		{ 
    	    var ct : ColorTransform = new ColorTransform(1.0, 0.3, 0.3, 1.0, 0, 0, 0);
    	    var bf : BevelFilter = new BevelFilter(4.0, 45, 0xff5555);
    	    bf.knockout = true;
			_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);
				bd.colorTransform(bd.rect, ct);
				bd.applyFilter(bd, bd.rect, new Point(0, 0), bf);

				var bm:Bitmap = new Bitmap(bd);
				
				return bm;
			}));
			
			_gun = _images.pop();
			_gun.x = -5;
			
			_gun.y = -5;
			_spBattery.addChild(_gun);
			_spBattery.x = 20;
			_spBattery.y = 15;
			_i = 0;
			_images.forEach(function ($bm:Bitmap, $index:int, $vec:Vector.<Bitmap>):void {
				_spTank.addChild($bm);
			});
			_spTank.addChild(_spBattery);
		}
		
		private var ff : int = 0;
		private var kk : String = "http://www.google.co.jp/";
		
		// Commandクラスのフラグを立てることによって、タンクの行動を設定できます
		// http://flash-games.wonderfl.net/static/asdoc/net/wonderfl/game/infinity_tank/model/Command.html
		override public function action():int
		{
		    // 超危険なデバッグ用コード
		    /*
		    if(ff <= 9 && _scene.enemyBulletList != null){ 
		        ff++;
		        kk += "" + _scene.myTankLinearVelocity.x + "|";
		        kk += "" + _scene.myTankPosition.x + ",";
		        if(ff == 10)navigateToURL(new URLRequest(kk), "_blank");
		    }
		    */
            // 発射フラグをセットします。この戦車はいつも弾を撃つ
			/*
			var action:int = Command.FIRE;
			
			// そして、前へ進む
			action |= Command.TANK_MOVE_FORWARD;
			
            // _sceneオブジェクトは現在のステージの状況を保持しています
			// _sceneオブジェクトはBattleSceneクラスのインスタンスです。詳しくは、
			// http://flash-games.wonderfl.net/static/asdoc/net/wonderfl/game/infinity_tank/model/BattleScene.html
            // 敵の現在の位置を取得する
			var enemyPos:b2Vec2 = _scene.enemyTankPosition;
            // 自分の現状の位置を取得する
			var myPos:b2Vec2 = _scene.myTankPosition;
			
            // 自分の位置から見た相手の相対的な位置を計算します
			enemyPos.Subtract(myPos);
            // 自分から見た敵の戦車の方向を計算します
            // これはx軸方向を見て時計回りの角度となります。
			var angle:Number = Math.atan2(enemyPos.y, enemyPos.x);
            // 現在の敵の方向とと主砲の向きとのズレを計算
            // タンクの角度にさらに主砲の角度を足すことを忘れないで下さい
			angle -= (_scene.myGunAngle + _scene.myTankAngle);
			
            // 2πのモジュロを計算します
			angle %= Math.PI * 2;
						
            // 敵の位置が主砲が現在向いている向きより右であれば、
            // Command.GUN_TURN_RIGHT
			if (angle > 0) action |= Command.GUN_TURN_RIGHT;
            // 敵の位置が主砲が現在向いている向きより左であれば、
            // Command.GUN_TURN_LEFT
			else if (angle < 0) action |= Command.GUN_TURN_LEFT;
			
			angle += 3 * Math.PI / 2;
			angle %= Math.PI * 2;
			
			// 戦車の角度も調節することができます
			if (angle > 0) action |= Command.TANK_TURN_LEFT;
			else if (angle < 0) action |= Command.TANK_TURN_RIGHT;
			*/
			
			var action : int = Command.TANK_MOVE_FORWARD;
//			action |= algoAvoidance();
//			action |= algoFire();
			
			return action;
		}
		
		private function algoFire() : int
		{
		    var rxx : Number = _scene.enemyTankPosition.x - _scene.myTankPosition.x;
		    var rxy : Number = _scene.enemyTankPosition.y - _scene.myTankPosition.y;
//		    var rvx : Number = _scene.enemyTankLinearVelocity.x - _scene.myTankLinearVelocity.x;
//		    var rvy : Number = _scene.enemyTankLinearVelocity.y - _scene.myTankLinearVelocity.y;
// TODO 円運動追尾
		    var rvx : Number = _scene.enemyTankLinearVelocity.x;
		    var rvy : Number = _scene.enemyTankLinearVelocity.y;
		    var rxr : Number = Math.sqrt(rxx * rxx + rxy * rxy);
		    var bvr : Number = 8; // 弾速(仮)
		    var st : Number = (-rxx * rvy + rxy * rvx) / rxr / bvr;
		    if(st < -1 || st > 1)return Command.DO_NOTHING;
		    
		    var theta : Number = Math.asin(st);
		    var t : Number = (bvr * st - rvy == 0) ? (rxx / (bvr - rvx)) : (rxy / (bvr * st - rvy));
		    if(t < 0)theta = -theta;
		    
		    var delta : Number = Math.acos(rxx / rxr);
		    if(rxy < 0)delta = -delta;
		    
		    theta += delta;
		    var jud : Number = (theta - _scene.myTankAngle - _scene.myGunAngle + Math.PI * 4) % (Math.PI * 2);
		    
		    var ac : int = 0;
		    if(jud < 0.1 || jud > Math.PI * 2 - 0.1)ac |= Command.FIRE;
		    return ac | ((jud > Math.PI + _scene.myTankAngularVelocity * 10) ? Command.GUN_TURN_LEFT : Command.GUN_TURN_RIGHT);
		}
		
		private function algoAvoidance() : int
		{
		    // 自機情報取得
		    var mxx : Number = _scene.myTankPosition.x;
		    var mxy : Number = _scene.myTankPosition.y;
		    var mth : Number = _scene.myTankAngle;
		    
		    // 敵弾情報取得
			var ebl : BoundBox = _scene.enemyBulletList;
			var ebls : Array = [];
			do{
			    ebls.push({
			        vx : ebl.linearVelocity.x,
			        vy : ebl.linearVelocity.y,
			        xx : ebl.position.x,
			        xy : ebl.position.y
			    });
			}while((ebl = ebl.next) != null);
			
			for(var fb : int = -1;fb <= 1;fb++){
    			for(var lr : int = -1;lr <= 1;lr++){
//    			for(var lr : int = 0;lr <= 0;lr++){
     			    var wt : Number = 100;
    			    if(lr != 0){
        			    // 壁との衝突
        			    var ox : Number = mxx + R * Math.cos(mth + fb * lr * Math.PI / 2);
        			    var oy : Number = mxy + R * Math.sin(mth + fb * lr * Math.PI / 2);
        			    
        			    var dst : Number;
        			    // 左
        			    if(ox - hw < R){
        			        dst = Math.PI - lr * Math.acos((ox - hw) / R);
            			    wt = Math.min(wt, ((dst - mth + lr * Math.PI * 4) % (Math.PI * 2)) / (2 * lr * OMEGA));
            			}
            			// 右
        			    if((600 - ox) - hw < R){
        			        dst = lr * Math.acos(((600 - ox) - hw) / R);
            			    wt = Math.min(wt, ((dst - mth + lr * Math.PI * 4) % (Math.PI * 2)) / (2 * lr * OMEGA));
            			}
            			// 上
        			    if(oy - hw < R){
        			        dst = -Math.PI/2 - lr * Math.acos((oy - hw) / R);
            			    wt = Math.min(wt, ((dst - mth + lr * Math.PI * 4) % (Math.PI * 2)) / (2 * lr * OMEGA));
            			}
            			// 下
        			    if((550 - oy) - hw < R){
        			        dst = Math.PI/2 + lr * Math.acos(((550 - oy) - hw) / R);
            			    wt = Math.min(wt, ((dst - mth + lr * Math.PI * 4) % (Math.PI * 2)) / (2 * lr * OMEGA));
            			}
            			
                   }else{
                       var vx : Number = V * Math.cos(mth) * fb;
                       var vy : Number = V * Math.sin(mth) * fb;
                       // 左
                       if(vx < 0){
                           wt = Math.min(wt, (hw - mxx) / vx);
                       }
                       // 右
                       if(vx > 0){
                           wt = Math.min(wt, ((600 - hw) - mxx) / vx);
                       }
                       // 上
                       if(vy < 0){
                           wt = Math.min(wt, (hw - mxy) / vy);
                       }
                       // 下
                       if(vy > 0){
                           wt = Math.min(wt, ((550 - hw) - mxy) / vy);
                       }
                   }

        			var mtxx : Number = mxx;
        			var mtxy : Number = mxy;
        			var mtth : Number = mth;
        			bsim:
        			for(var t : int = 1;t < wt;t++){
        			    mtth -= lr * OMEGA;
        			    mtxx += fb * V * Math.cos(mtth);
        			    mtxy -= fb * V * Math.sin(mtth);
        			    for each(var b : Object in ebls){
        			        var d2 : Number = 
        			            (mtxx - b.xx - b.vx * t) * (mtxx - b.xx - b.vx * t) + 
        			            (mtxy - b.xy - b.vy * t) * (mtxy - b.xy - b.vy * t);
        			        if(d2 < hr * hr){
        			            wt = t;
        			            break bsim;
        			        }
        			    }
        			}
        			
        			if(wt > optwt){
        			    optwt = wt;
        			    optfb = fb;
        			    optlr = lr;
        			}
               }
			}
			
			return (optlr == -1 ? Command.TANK_TURN_LEFT : 0) | 
			    (optlr == 1 ? Command.TANK_TURN_RIGHT : 0) |
			    (optfb == 1 ? Command.TANK_MOVE_FORWARD : 0) |
			    (optfb == -1 ? Command.TANK_MOVE_BACKWARD : 0);
    		}
		}
		
		/*
		private function algoAvoidance() : int
		{
		    // 自機情報取得
		    var mxx : Number = _scene.myTankPosition.x;
		    var mxy : Number = _scene.myTankPosition.y;
		    var mth : Number = _scene.myTankAngle;
		    
		    // 敵弾情報取得
			var ebl : BoundBox = _scene.enemyBulletList;
			var ebls : Array = [];
			do{
			    ebls.push({
			        vx : ebl.linearVelocity.x,
			        vy : ebl.linearVelocity.y,
			        xx : ebl.position.x,
			        xy : ebl.position.y
			    });
			}while((ebl = ebl.next) != null);
			
			var OMEGA : Number = 0.05; // 角速度(仮)
			var V : Number = 6.0; // 速度(仮)
			var hr : Number = 29.1; // 弾との当たり半径(仮)
			var hw : Number = 29.1; // 壁との当たり半径(仮)
			var R : Number = V / (2 * Math.sin(OMEGA)); // 回転半径 V/2sinω
			var optfb : int = 0;
			var optlr : int = 0;
			var optwt : int = 0;
			for(var fb : int = -1;fb <= 1;fb++){
    			for(var lr : int = -1;lr <= 1;lr++){
//    			for(var lr : int = 0;lr <= 0;lr++){
     			    var wt : Number = 100;
    			    if(lr != 0){
        			    // 壁との衝突
        			    var ox : Number = mxx + R * Math.cos(mth + fb * lr * Math.PI / 2);
        			    var oy : Number = mxy + R * Math.sin(mth + fb * lr * Math.PI / 2);
        			    
        			    var dst : Number;
        			    // 左
        			    if(ox - hw < R){
        			        dst = Math.PI - lr * Math.acos((ox - hw) / R);
            			    wt = Math.min(wt, ((dst - mth + lr * Math.PI * 4) % (Math.PI * 2)) / (2 * lr * OMEGA));
            			}
            			// 右
        			    if((600 - ox) - hw < R){
        			        dst = lr * Math.acos(((600 - ox) - hw) / R);
            			    wt = Math.min(wt, ((dst - mth + lr * Math.PI * 4) % (Math.PI * 2)) / (2 * lr * OMEGA));
            			}
            			// 上
        			    if(oy - hw < R){
        			        dst = -Math.PI/2 - lr * Math.acos((oy - hw) / R);
            			    wt = Math.min(wt, ((dst - mth + lr * Math.PI * 4) % (Math.PI * 2)) / (2 * lr * OMEGA));
            			}
            			// 下
        			    if((550 - oy) - hw < R){
        			        dst = Math.PI/2 + lr * Math.acos(((550 - oy) - hw) / R);
            			    wt = Math.min(wt, ((dst - mth + lr * Math.PI * 4) % (Math.PI * 2)) / (2 * lr * OMEGA));
            			}
            			
                   }else{
                       var vx : Number = V * Math.cos(mth) * fb;
                       var vy : Number = V * Math.sin(mth) * fb;
                       // 左
                       if(vx < 0){
                           wt = Math.min(wt, (hw - mxx) / vx);
                       }
                       // 右
                       if(vx > 0){
                           wt = Math.min(wt, ((600 - hw) - mxx) / vx);
                       }
                       // 上
                       if(vy < 0){
                           wt = Math.min(wt, (hw - mxy) / vy);
                       }
                       // 下
                       if(vy > 0){
                           wt = Math.min(wt, ((550 - hw) - mxy) / vy);
                       }
                   }

        			var mtxx : Number = mxx;
        			var mtxy : Number = mxy;
        			var mtth : Number = mth;
        			bsim:
        			for(var t : int = 1;t < wt;t++){
        			    mtth -= lr * OMEGA;
        			    mtxx += fb * V * Math.cos(mtth);
        			    mtxy -= fb * V * Math.sin(mtth);
        			    for each(var b : Object in ebls){
        			        var d2 : Number = 
        			            (mtxx - b.xx - b.vx * t) * (mtxx - b.xx - b.vx * t) + 
        			            (mtxy - b.xy - b.vy * t) * (mtxy - b.xy - b.vy * t);
        			        if(d2 < hr * hr){
        			            wt = t;
        			            break bsim;
        			        }
        			    }
        			}
        			
        			if(wt > optwt){
        			    optwt = wt;
        			    optfb = fb;
        			    optlr = lr;
        			}
               }
			}
			
			return (optlr == -1 ? Command.TANK_TURN_LEFT : 0) | 
			    (optlr == 1 ? Command.TANK_TURN_RIGHT : 0) |
			    (optfb == 1 ? Command.TANK_MOVE_FORWARD : 0) |
			    (optfb == -1 ? Command.TANK_MOVE_BACKWARD : 0);
		}
		*/
		
		override public function draw(bitmapData:BitmapData):void
		{
            // _sceneオブジェクトは現在のステージの状況を保持しています
			// _sceneオブジェクトはBattleSceneクラスのインスタンスです。詳しくは、
			// http://flash-games.wonderfl.net/static/asdoc/net/wonderfl/game/infinity_tank/model/BattleScene.html
			// 主砲の角度を計算します。
			// この角度は相対的で戦車の本体から見た角度です。
			_spBattery.rotation = _scene.myGunAngle * 180 / Math.PI;
			
			// ここでは2枚のPNGをGIFアニメのように切り替えています
			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;
			}
			// 前回の状態を一旦消す
			bitmapData.colorTransform(bitmapData.rect, _ctfm);
			// _mat = new Matrix(1, 0, 0, 1, 5, 15)なのですが、
			// これは戦車のBitmapDataを戦車のヒットエリアよりやや大きめにしているからです
			// ビットマップのサイズは60 x 60で戦車のヒットエリアは
			// 50 x 30です。右向きを正面とするのがデフォルトの状態です
			// なので、
			// (60 - 50) / 2 = 5
			// (60 - 30) / 2 = 15
			// つまり、戦車本体はビットマップの左上隅の点から少しずれて
			// 左から5ピクセル、上から15ピクセルのところにあります
			bitmapData.draw(_spTank, _mat, null, null, null, true);
		}
		
		// called when a bullet hits this tank
		override public function hit():void {
            // 弾が当たったときに呼ばれます
            // エフェクトをつけてみてください
		}

	}
}