UFO_Tank

by cpu_t forked from TankTemplate (diff: 487)
このコードを新着タンク一覧http://flash-games.wonderfl.net/tank/list/new
に表示させるにはinfinite-tank-entry
というタグをつけてください
♥0 | Line 332 | Modified 2010-01-01 19:34:16 | MIT License | (replaced)
play

ActionScript3 source code

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

// forked from cpu_t's TankTemplate
// forked from cpu_t's EscapeTank
// forked from 9re's Wonderfl Tank Game Tank Sample 1
// このコードを新着タンク一覧http://flash-games.wonderfl.net/tank/list/new
// に表示させるにはinfinite-tank-entry
// というタグをつけてください
package 
{
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.display.BitmapData;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	
	import flash.display.GradientType;
	import flash.display.SpreadMethod;
	import flash.display.InterpolationMethod;
	
	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 _spTank:Sprite;
		private var _spBattery:Sprite;
		private var _spUFO:Sprite;
		private var _spOutput:Sprite;
		private var _spOutputField:Sprite;
		private var _ctfm:ColorTransform;
		private var _mat:Matrix = new Matrix(1, 0, 0, 1, 5, 15);
		private var _wmat:WMatrix2D = new WMatrix2D;
		private var g:Graphics;
		
		private const CenterPos:WVector2D = new WVector2D(300, 275);
		
		private var goForward:Boolean = true;
		private var moveAvoid:Boolean = false;
		private var targetPos:WVector2D = new WVector2D(300, 275);
		private var avoidCount:Number = 0;
		private var moveTargetAngle:Number = 0;
		
		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;
			_spUFO = new Sprite;
			_spOutput = new Sprite;
			_spOutputField = new Sprite;
			
			initDraw();
			
			_ctfm = new ColorTransform(1, 1, 1, 0);
			
			super();
		}
		
		// ※タンクの動きのメイン関数
		// 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
		{
			// Command.FIRE           弾を撃つ
			// Command.GUN_TURN_RIGHT 砲台を右旋回
			// Command.GUN_TURN_LEFT  砲台を左旋回
			// Command.TANK_MOVE_FORWARD  前進
			// Command.TANK_MOVE_BACKWARD  後進
			// Command.TANK_TURN_LEFT 左に旋回
			// Command.TANK_TURN_RIGHT 右に旋回
			
			// command.addCommand(Command.コマンド);//実行する動きに追加
			// return command.action; この関数の最後で実行する
			
			// _spOutputをクリア
			g = _spOutput.graphics;
			g.clear();
			g = _spOutputField.graphics;
			g.clear();
			
			var command:Command = new Command;
			
			// AI設定部分
			
			var t:Number;
			var tempVec:WVector2D;
			
			// 色々取得
			var myPos:WVector2D = _scene.myTankPosition;
			var enemyPos:WVector2D = _scene.enemyTankPosition;
			var enemyVec:WVector2D = _scene.enemyTankLinearVelocity;
			tempVec = enemyPos.copy();
			tempVec.subtract(myPos);
			var enemyDistance:Number = tempVec.length;
			
			// 敵の弾で、自機に当たりそうな物をalertEnemyShotに格納
			var enemyShot:BoundBox = _scene.enemyBulletList;
			var alertEnemyShot:Vector.<BoundBox> = new Vector.<BoundBox>;
			while (enemyShot != null) {
				var enemyShotPos:WVector2D = enemyShot.position.copy();
				var enemyShotDirection:WVector2D = enemyShot.linearVelocity.copy();
				// 弾が自機に向かっていたら、alertEnemyShotにpush
				tempVec = myPos.copy();
				tempVec.subtract(enemyShotPos);
				if (WMath.dot2D(tempVec, enemyShotDirection) > 0) {
					alertEnemyShot.push(enemyShot);
				}
				// 次の弾を取得
				enemyShot = enemyShot.next;
			}
			var _alert:Number = 9999;
			for each(var alertShot:BoundBox in alertEnemyShot) {
				// 自機に当たりそうかどうか
				if (checkCrclLine(myPos, 80, alertShot.position, alertShot.linearVelocity)) {
					// 自機に一番近い弾を見る
					tempVec = myPos.copy();
					tempVec.subtract(alertShot.position);
					if (tempVec.length < _alert) {
						_alert = tempVec.length;
						// 中央付近を維持している
						if (checkCrclPoint(CenterPos, 250, myPos)) {
							// さっきまで逃げていなかったなら方向を計算
							if (moveAvoid == false) {
								moveAvoid = true;
								// 自機が弾道のどちら側にいるか
								t = Math.sin(WMath.modulo2PI(vecToRad(tempVec) - vecToRad(alertShot.linearVelocity)));
								if (WMath.modulo2PI(Math.sin(_scene.myTankAngle) - vecToRad(alertShot.linearVelocity)) < 0) {
									if (t > 0) goForward = true;
									else goForward = false;
								} else {
									if (t < 0) goForward = true;
									else goForward = false;
								}
							}
						}else {
							moveAvoid = true;
							// 中央から離れすぎている
							tempVec = myPos.copy();
							tempVec.subtract(CenterPos);
							if (Math.cos(WMath.modulo2PI(_scene.myTankAngle - vecToRad(tempVec))) < 0) goForward = true;
							else goForward = false;
						}
					}
				}
			}
			// どの弾にも当たりそうにない
			if (_alert == 9999) {
				// 逃げない
				moveAvoid = false;
			}
			// 逃げるならとりあえず逃げる
			if (moveAvoid) {
				command.addCommand(getForward());
			}else {
				tempVec = myPos.copy();
				tempVec.subtract(CenterPos);
				if (Math.cos(WMath.modulo2PI(_scene.myTankAngle - vecToRad(tempVec))) < 0) goForward = true;
				else goForward = false;
				if (!checkCrclPoint(CenterPos, 150, myPos) || (enemyDistance < 200))
					command.addCommand(getForward());
			}
			// 敵位置予想
			tempVec = enemyPos.copy();
			tempVec.add(enemyVec);
			// 敵と水平な角度を目指す
			tempVec.subtract(CenterPos);
			moveTargetAngle = WMath.modulo2PI(vecToRad(tempVec) + 90 * Math.PI / 180);
			// 自機旋回
			t = WMath.modulo2PI(moveTargetAngle - _scene.myTankAngle);
			if (t < Math.PI / 2 || (t > Math.PI && t < Math.PI * 3 / 2)) command.addCommand(Command.TANK_TURN_RIGHT);
			else command.addCommand(Command.TANK_TURN_LEFT);
			
			/*
			var myPos:WVector2D = _scene.myTankPosition;
			// 敵の弾を取得
			var enemyShot:BoundBox = _scene.enemyBulletList;
			var alertEnemyShotDirection:Vector.<WVector2D> = new Vector.<WVector2D>;
			while (enemyShot != null) {
				var enemyShotPos:WVector2D = enemyShot.position;
				var enemyShotDirection:WVector2D = new WVector2D(Math.cos(enemyShot.rotation), Math.sin(enemyShot.rotation));
				// 敵の弾に当たりそうな場合、alertEnemyShotに追加
				if (checkCrclLine(myPos, 60, enemyShot.position, enemyShotDirection)) {
					alertEnemyShotDirection.push(enemyShotDirection);
					
					g = _spOutputField.graphics;
					g.lineStyle(1, 0x800080, 1.0);
					g.beginFill(0x000000, 0.0);
					g.drawCircle(enemyShotPos.x, enemyShotPos.y, 30);
					g.lineStyle(1, 0x800080, 1.0);
					g.moveTo(enemyShotPos.x, enemyShotPos.y);
					enemyShotDirection.scale(100);
					enemyShotPos.add(enemyShotDirection);
					g.lineTo(enemyShotPos.x, enemyShotPos.y);
					g.lineStyle(1, 0xffffff, 0.5);
					g.beginFill(0x000000, 0.0);
					g.drawCircle(myPos.x, myPos.y, 60);
				}
				enemyShot = enemyShot.next;
			}
			
			var _moveflg:Boolean = true;
			
			// 自機の速度を取得
			var mySpeed:WVector2D = _scene.myTankLinearVelocity;
			var CenterPos:WVector2D = new WVector2D(300, 275);
			var temp:WVector2D;
			var m:WMatrix2D = new WMatrix2D;
			avoidCount--;
			if (avoidCount < 0) {
				// targetPosを更新
				if (alertEnemyShotDirection.length > 0) {
					// 逃げるように移動する
					var alertShotVec:WVector2D = new WVector2D(0, 0);
					for each(var v:WVector2D in alertEnemyShotDirection) {
						alertShotVec.add(v);
					}
					alertShotVec.normalize();
					m.setRotationMatrix(90 * Math.PI / 180);
					m.scale(CenterPos.length);
					alertShotVec.applyMatrix(m);
					if (WMath.dot2D(mySpeed, alertShotVec) < 0) {
						m.identity();
						m.setRotationMatrix(180 * Math.PI / 180);
						alertShotVec.applyMatrix(m);
					}
					temp = alertShotVec.copy();
					m.identity();
					m.setRotationMatrix(180 * Math.PI / 180);
					temp.applyMatrix(m);
					alertShotVec.add(myPos);
					temp.add(myPos);
					alertShotVec.subtract(CenterPos);
					temp.subtract(CenterPos);
					if (temp.length * 2 < alertShotVec.length) {
						alertShotVec = temp;
					}
					alertShotVec.add(CenterPos);
					targetPos = alertShotVec.copy();
					moveAvoid = true;
					avoidCount = 5;
				} else {
					moveAvoid = false;
					var zeroVec:WVector2D = new WVector2D(0, 0);
					if (checkCrclLine(CenterPos, 100, myPos, zeroVec)) {
						targetPos = myPos;
						_moveflg = false;
						var myAngle:Number = _scene.myTankAngle;
						var enemyAngle:Number = Math.atan2(_scene.enemyTankLinearVelocity.y, _scene.enemyTankLinearVelocity.x);
						if (WMath.modulo2PI(enemyAngle + (90 * Math.PI / 180) - myAngle) <= Math.PI) command.addCommand(Command.TANK_TURN_RIGHT)
						else command.addCommand(Command.TANK_TURN_LEFT);
					} else {
						var enemyPos:WVector2D = _scene.enemyTankPosition;
						var directionPos:WVector2D = CenterPos.copy();
						directionPos.subtract(enemyPos);
						directionPos.normalize();
						directionPos.scale(200);
						directionPos.add(enemyPos);
						if (checkCrclLine(directionPos, 100, myPos, zeroVec)) {
							targetPos = myPos;
						}else{
							targetPos = directionPos;
						}
					}
				}
			}
			shot(command);
			if(_moveflg) move(command);
			*/
			
			shot(command);
			
			// command.actionがフラグとなっている
			return command.action;
		}
		private var cnt:int = 0;
		
		private var lastEnemyPos:WVector2D = new WVector2D(300, 275);
		private var shotSpeed:Number = 200;
		private var shotCount:Number = 1;
		private var lastShotNum:int = 0;
		// 攻撃用関数
		private function shot(command:Command):void {
			// 弾を撃っていたら、現在の弾のスピードをshotSpeedに反映
			if (_scene.myBulletCount > lastShotNum) {
				var myShot:BoundBox = _scene.myBulletList;
				while (myShot != null) {
					shotCount++;
					shotSpeed = shotSpeed * (shotCount - 1) / shotCount + myShot.linearVelocity.length / shotCount;
					myShot = myShot.next;
				}
			}
			lastShotNum = _scene.myBulletCount;
			// 色々取得、設定
			var myPos:WVector2D = _scene.myTankPosition;
			var enemyPos:WVector2D = _scene.enemyTankPosition;
			var shotDirection:WVector2D = enemyPos.copy();
			shotDirection.subtract(myPos);
			var enemyDistance:Number = shotDirection.length;
			var baseEnemyVec:WVector2D = enemyPos.copy();
			baseEnemyVec.subtract(lastEnemyPos);
			lastEnemyPos = enemyPos.copy();
			var enemyVec:WVector2D;
			var _fire:Boolean = true;
			
				g = _spOutputField.graphics;
				g.lineStyle(1, 0xffff00, 0.1);
				g.beginFill(0x000000, 0.0);
				g.moveTo(myPos.x, myPos.y);
				g.lineTo(enemyPos.x, enemyPos.y);
			
			// 弾が届くまでの時間
			var reachTime:Number = enemyDistance / shotSpeed;
			var lastTime:Number = 0;
			var _times:Number = 0;
			// 算出した時間分だけ敵の位置を進めて再計算
			// 誤差が小さくなるか、100回繰り返したら抜ける
			while (reachTime - lastTime > 0.01 && _times < 100) {
				_times++;
				enemyVec = baseEnemyVec.copy();
				_wmat.identity();
				_wmat.scale(reachTime - lastTime);
				enemyVec.applyMatrix(_wmat);
				enemyPos.add(enemyVec);
					g.lineTo(enemyPos.x, enemyPos.y);
				shotDirection.add(enemyVec);
				enemyDistance = shotDirection.length;
				lastTime = reachTime;
				reachTime = enemyDistance / shotSpeed;
				/*
				// 予測位置が画面外になる場合、攻撃しない
				if ((enemyPos.x < 0 || enemyPos.x > 600 ||
				enemyPos.y < 0 || enemyPos.y > 550) && enemyDistance > 200) {
					_fire = false;
					break;
				}
				*/
			}
				g.lineStyle(1, 0xff8000, 0.1);
				g.endFill();
			// 予想した敵の位置に砲台を向ける
			var shotAngle:Number = Math.atan2(shotDirection.y, shotDirection.x);
			shotAngle = WMath.modulo2PI(shotAngle - (_scene.myTankAngle + _scene.myGunAngle));
			if (shotAngle > 5 * Math.PI / 180 && shotAngle < (360 - 5) * Math.PI / 180) {
				if (shotAngle <= Math.PI) command.addCommand(Command.GUN_TURN_RIGHT);
				else command.addCommand(Command.GUN_TURN_LEFT);
			}
			// だいたい合うか、近くに居れば攻撃
			if ((((shotAngle < 10 * Math.PI / 180) || (shotAngle > (360 - 10) * Math.PI / 180)) && _fire) || 
			(enemyDistance < 100 && ((shotAngle < 30 * Math.PI / 180) || (shotAngle > (360 - 30) * Math.PI / 180)))) {
				command.addCommand(Command.FIRE);
			}
		}
		
		// 移動用関数
		private function move(command:Command):void {
			var myPos:WVector2D = _scene.myTankPosition;
			var myAngle:Number = _scene.myTankAngle;
			if (!goForward)
				myAngle += 180 * Math.PI / 180;
			// 目標点を設定
			var directionPos:WVector2D = targetPos.copy();
			// ランダム性を持たせる
			var rndVec:WVector2D = new WVector2D(Math.random() - 0.5, Math.random() - 0.5);
			rndVec.normalize();
			rndVec.scale(50);
			directionPos.add(rndVec);
			// 目標地点に赤い円を描画
				g = _spOutputField.graphics;
				g.lineStyle(1, 0xff0000, 1.0);
				g.beginFill(0xff0000, 0.5);
				g.drawCircle(directionPos.x, directionPos.y , 5);
			// 目標点を自機から見た方向で計算
			directionPos.subtract(myPos);
			var distance:Number = directionPos.length;
			// 向かう方向に線を引く
				g = _spOutput.graphics;
				g.lineStyle(1, moveAvoid?0xff8000:0x00ffff, 0.5);
				g.moveTo(0, 0);
				g.lineTo(directionPos.x, directionPos.y);
			directionPos.normalize();
			var direction:Number = Math.atan2(directionPos.y, directionPos.x);
			// 向かう方向と現在の方向の差を計算
			var tempAngle:Number = WMath.modulo2PI(direction - myAngle);
			tempAngle-= 180 * Math.PI / 180;
			// 一定以上差が大きければ進行方向を逆転
			if ((tempAngle < 60 * Math.PI / 180) && (tempAngle > -60 * Math.PI / 180)) {
				turn();
				myAngle += 180 * Math.PI / 180;
			}
			// 向かう方向から自機の方向を引く
			tempAngle = WMath.modulo2PI(direction - myAngle);
			// 一定以上差が小さければ前進
			var CenterPos:WVector2D = new WVector2D(300, 275);
			var r:Number = CenterPos.length;
			var _t:Number = 90 * distance / r;
			if ((tempAngle < _t * Math.PI / 180) || (tempAngle > (360 - _t) * Math.PI / 180)) {
				command.addCommand(getForward());
			}
			// PI未満なら右旋回
			if (tempAngle < Math.PI) command.addCommand(getRight());
			else command.addCommand(getLeft());
		}
		
		// 進行方向を逆転する
		private function turn():void {
			goForward = !goForward;
		}
		
		private function getForward():int {
			return goForward ? Command.TANK_MOVE_FORWARD : Command.TANK_MOVE_BACKWARD;
		}
		private function getRight():int {
			return goForward ? Command.TANK_TURN_RIGHT : Command.TANK_TURN_LEFT;
		}
		private function getLeft():int {
			return goForward ? Command.TANK_TURN_LEFT : Command.TANK_TURN_RIGHT;
		}
		
		// WVector2Dを角度(ラジアン)に変換する
		private function vecToRad(vec:WVector2D):Number {
			return Math.atan2(vec.y, vec.x);
		}
		
		// 円と点の判定
		private function checkCrclPoint(crclPos:WVector2D, crclRadius:Number, PointPos:WVector2D):Boolean {
			var temp:WVector2D = crclPos.copy();
			temp.subtract(PointPos);
			if (temp.length < crclRadius) return true;
			else return false;
		}
		
		// 円と半直線の交差判定
		private function checkCrclLine(crclPos:WVector2D, crclRadius:Number, linePos:WVector2D, lineVec:WVector2D):Boolean {
            var temp:WVector2D = lineVec.copy();
			temp.normalize();
            // 半直線の始点から円の中心へのベクトル
            var C:WVector2D = crclPos.copy();
            C.subtract(linePos);
            // Cと半直線のベクトルの内積
            var dot:Number = WMath.dot2D(C, temp);
            // dot < 0 のとき、円の中心に向かって線が伸びていない
            if (dot < 0){
                if (C.length < crclRadius) // Cの長さが円の半径より小さければ交差
                    return true;
                else
                    return false;
            } else {
                //円の中心から直線に降ろした足のベクトルを計算
                temp.scale(dot);
                C.subtract(temp);
                if (C.length < crclRadius) //足の長さが半径より小さければ交差
                    return true;
                else
                    return false;
            }
		}
		
		// ※被弾時に演出を入れたい時に編集してください。
		// called when a bullet hits this tank
		override public function hit():void {
			// 被弾したときに呼ばれるcallbackです.
		}
		// ※発射時に演出を入れたい時に編集してください。
		// called when this tank fires
		override public function fire():void 
		{
			// 弾が発射される時に呼ばれるcallbackです.
		}
		
		private function initDraw():void
		{
			var g:Graphics;
			
			g = _spBattery.graphics;
			g.lineStyle(1, 0x00ffc0, 1.0);
			g.beginFill(0x00ffc0, 1.0);
			g.drawCircle(30, 0, 2);
			g.endFill();
			/*
			g.lineStyle(1, 0x000000, 1.0);
			g.beginFill(0xffffff, 0.5);
			g.drawCircle(0, 0, 7.5);
			g.endFill();
			g.beginFill(0xc0c0c0, 0.5);
			g.drawRect( -4, -2, 25, 4);
			g.endFill();
			*/
			
			g = _spTank.graphics;
			g.lineStyle(1, 0x00ff00, 0.5);
			g.moveTo( -25, -12);
			g.lineTo( -25, -15);
			g.lineTo( -22, -15);
			g.lineTo( -25, -15);
			g.moveTo(22, -15);
			g.lineTo(25, -15);
			g.lineTo(25, -12);
			g.lineTo(25, -15);
			g.moveTo(25, 12);
			g.lineTo(25, 15);
			g.lineTo(22, 15);
			g.lineTo(25, 15);
			g.moveTo( -22, 15);
			g.lineTo( -25, 15);
			g.lineTo( -25, 12);
			g.lineTo( -25, 15);
			g.endFill();
			g.lineStyle(1, 0x00ff00, 0.5);
			g.beginFill(0xffffff, 0.0);
			g.moveTo(23, -4);
			g.lineTo(28, 0);
			g.lineTo(23, 4);
			g.lineStyle(1, 0x000000, 0.0);
			g.endFill();
			/*
			g.lineStyle(1, 0xffffff, 1.0);
			g.beginFill(0x808080, 1.0);
			var m:Matrix = new Matrix;
			m.identity();
			m.scale(1.0 / 1638.4 * 25 * 2, 1);
			g.beginGradientFill(GradientType.LINEAR, [0x8080ff, 0xffff80, 0xff8080], [1.0, 1.0, 1.0], [0, 128, 255], 
				m , SpreadMethod.REPEAT, InterpolationMethod.LINEAR_RGB, 0.0);
			g.drawRoundRect( -25, -15, 50, 30, 15, 15);
			g.endFill();
			g.beginFill(0xffa0a0, 1.0);
			g.moveTo(15, -8);
			g.lineTo(23, 0);
			g.lineTo(15, 8);
			*/
			
			g = _spUFO.graphics;
			g.lineStyle(1, 0xffffff);
			g.beginFill(0xc0c0c0);
			g.drawCircle(-13, 6, 5.5);
			g.drawCircle(0, 8, 5.5);
			g.drawCircle(13, 6, 5.5);
			g.endFill();
			g.lineStyle(1, 0xffffff);
			g.beginFill(0xc0c0c0);
			g.drawEllipse(-19, -4, 38, 12);
			g.endFill();
			g.lineStyle(1, 0xffffff);
			g.beginFill(0xc0c0c0);
			g.drawEllipse(-8, -12, 16, 14);
			g.endFill();
			
			_spTank.addChild(_spBattery);
		}
		// ※タンクの向きを描画している関数。修正の必要はありません。
		// 毎フレームごとに呼ばれる描画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;
			
			// 単位行列にセット
			_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);
			// _spOutput, _spUFOを描画
			_mat.identity();
			_mat.translate(_scene.myTankPosition.x, _scene.myTankPosition.y);
			bitmapData.draw(_spUFO, _mat, null, null, null, true);
			bitmapData.draw(_spOutput, _mat, null, null, null, true);
			_mat.identity();
			bitmapData.draw(_spOutputField, _mat, null, null, null, true);
		}
	}
}