// 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.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.utils.getTimer; import net.wonderfl.game.infinity_tank.development.*; import net.wonderfl.utils.SequentialLoader; import net.wonderfl.math.*; /** * @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/related_images/b/b7/b7aa/b7aa7e34d862722e9d939f2c8d8c38f844b02f20", "http://assets.wonderfl.net/images/related_images/7/76/76d4/76d4ef9f4c0a8172551f750a12f3bb207a0f0546", "http://assets.wonderfl.net/images/related_images/f/f3/f3db/f3dbbe24d0308a857f7f3f252d488a9e6def05c6" ], _arr, onImageLoaded); _ctfm = new ColorTransform(1, 1, 1, 0); } 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); } private var isMovingForward:Boolean = true; private var changeCount:int = 5; private var lastPos:WVector2D = new WVector2D(-100,0); private var hosei:Number = 0; private var lastFire:Number = 0; // Commandクラスのフラグを立てることによって、タンクの行動を設定できます // http://flash-games.wonderfl.net/static/asdoc/net/wonderfl/game/infinity_tank/model/Command.html override public function action():int { // 行動フラグ action var action:int; changeCount--; lastPos.subtract(_scene.myTankPosition); trace(lastPos.length) if( lastPos.normalize() < 7 && changeCount < 0 ){ isMovingForward = !isMovingForward; changeCount = 20; } lastPos.x = _scene.myTankPosition.x; lastPos.y = _scene.myTankPosition.y; /* var myfuturePos:WVector2D = _scene.myTankPosition; myfuturePos.add(_scene.myTankLinearVelocity); if( myfuturePos.x < 30 || myfuturePos.x > 570 || myfuturePos.y < 30 || myfuturePos.y > 520 ){ if( changeCount < 0 ){ isMovingForward = !isMovingForward; changeCount = 20; } } */ // 前へ進む // action |= Command.TANK_MOVE_FORWARD; action |= isMovingForward?Command.TANK_MOVE_FORWARD:Command.TANK_MOVE_BACKWARD; // _sceneオブジェクトは現在のステージの状況を保持しています // _sceneオブジェクトはBattleSceneクラスのインスタンスです。詳しくは、 // http://flash-games.wonderfl.net/static/asdoc/net/wonderfl/game/infinity_tank/model/BattleScene.html // 敵の現在の位置を取得する var enemyPos:WVector2D = _scene.enemyTankPosition; // 自分の現状の位置を取得する var myPos:WVector2D = _scene.myTankPosition; // 自分の位置から見た相手の相対的な位置を計算します enemyPos.subtract(myPos); // 自分から見た敵の戦車の方向を計算します // これはx軸方向を見て時計回りの角度となります。 var angle2:Number = Math.atan2(enemyPos.y, enemyPos.x); // 現在の敵の方向とと主砲の向きとのズレを計算 // タンクの角度にさらに主砲の角度を足すことを忘れないで下さい angle2 -= (_scene.myTankAngle); // 敵が等速直線運動をする仮定で偏差射撃 var enemyVec:WVector2D = _scene.enemyTankLinearVelocity; var enemyAngVel:Number = _scene.enemyTankAngularVelocity; var tempMat:WMatrix2D = new WMatrix2D(); tempMat.setRotationMatrix(enemyAngVel); enemyVec.applyMatrix(tempMat); var enemyVecP:Point = new Point(enemyVec.x, enemyVec.y); var enemyVecNorm:Number = enemyVecP.length; enemyVecP.normalize(1); var yd:Number = enemyVecP.x * enemyPos.x + enemyVecP.y * enemyPos.y; var x:Number = Math.sqrt(enemyPos.x*enemyPos.x+enemyPos.y*enemyPos.y - yd*yd); var bulletSpeed:Number = 150+100*Math.cos(hosei); // この数字がてきとう.. var vd:Number = enemyVecNorm*enemyVecNorm; var md:Number = bulletSpeed * bulletSpeed; // 弾が敵にヒットする時間 var alpha:Number = yd * yd * vd - (x * x + yd * yd) * (vd - md); var sign:int = (alpha>=0)?1:-1; var meetTime:Number = sign * (yd * enemyVecNorm - Math.sqrt( sign * alpha ) ) / (vd - md); var limit:int = 1; if( enemyPos.length < 20 ) meetTime = 0; tempPoint = new WVector2D(enemyPos.x+meetTime*enemyVec.x, enemyPos.y+meetTime*enemyVec.y); while( (tempPoint.x > 600 || tempPoint.x < 0 || tempPoint.y > 550 || tempPoint.y < 0) && limit-- ){ meetTime *= 0.75; tempPoint = new WVector2D(enemyPos.x+meetTime*enemyVec.x, enemyPos.y+meetTime*enemyVec.y); } // meetTime後の敵の位置を狙う var angle:Number = Math.atan2(tempPoint.y, tempPoint.x); angle -= (_scene.myGunAngle + _scene.myTankAngle); trace( angle, yd * yd * vd - (x * x + yd * yd) * (vd - md) ); // 2πのモジュロを計算します angle %= Math.PI * 2; if( angle > Math.PI ) angle -= Math.PI*2; if( angle < -Math.PI ) 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; // 敵を十分に狙えているか、非常に近くてほぼヒット確実なら射撃 if( Math.abs( angle ) < 0.20 || meetTime < 0.5 ){ if( getTimer() - lastFire > 400 ){ action |=Command.FIRE; lastFire = getTimer(); hosei+=0.2; } drawFlg = true; } else { drawFlg = false; } angle2 += 3 * Math.PI / 2; if( isMovingForward ) angle2 -= 0.35 * Math.PI; else angle2 += 0.35 * Math.PI; angle2 %= Math.PI * 2; if( angle2 > Math.PI ) angle2 -= Math.PI*2; if( angle2 < -Math.PI ) angle2 += Math.PI*2; // 戦車の角度も調節することができます if (angle2 > 0) action |= Command.TANK_TURN_LEFT; else if (angle2 < 0) action |= Command.TANK_TURN_RIGHT; return action; } private var tempPoint:WVector2D = new WVector2D(0,0); private var drawFlg:Boolean = false; 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; } // 単位行列にセット _mat.identity(); // タンクの傾きをセット _mat.rotate(_scene.myTankAngle); // タンクの位置に平行移動. タンクのグラフィックは中心座標となっています. _mat.translate(_scene.myTankPosition.x, _scene.myTankPosition.y); // 前回の状態を一旦消す 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); if( _spTank ){ _spTank.graphics.clear(); var tempPoint2:WVector2D = new WVector2D(tempPoint.x, tempPoint.y); var m2d:WMatrix2D = new WMatrix2D(); m2d.setRotationMatrix( -_scene.myTankAngle); tempPoint2.applyMatrix(m2d); m2d.setRotationMatrix( 0.20 ); tempPoint2.applyMatrix(m2d); if( drawFlg ){ _spTank.graphics.lineStyle(0, 0x004400); } else { _spTank.graphics.lineStyle(0, 0x440000); } _spTank.graphics.lineTo(tempPoint2.x, tempPoint2.y); m2d.setRotationMatrix( -0.40 ); tempPoint2.applyMatrix(m2d); _spTank.graphics.lineTo(tempPoint2.x, tempPoint2.y); _spTank.graphics.lineTo(0, 0); } } // called when a bullet hits this tank override public function hit():void { // 弾が当たったときに呼ばれます // エフェクトをつけてみてください } } } 適当に偏差射撃