// <Control> // Start: click or key 'x'. // Move: arrow key. // Shot: key 'z'. // // 弾幕を避けるAIを作ろう企画 // 入力をフックして弾幕を避けるAIを作ってみてください (ゲーム自体は弄らず、inputAuto関数あたりを書き換える) // 最終的な被弾数が一番少ない美しいAIを作った人が勝ち // // 敵(青・赤・紫)に当たり判定ないです。弾(白・黄色)だけ当たります // スコアはついで。約1分半。 // // 普通に遊びたい人はクリック。 // // _skipFrameの値を多くするとフレームスキップします。さっさと動かしたい人向け package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BlendMode; import flash.display.Sprite; import flash.geom.ColorTransform; import flash.events.Event; import flash.events.MouseEvent; import flash.events.KeyboardEvent; import flash.text.TextField; import flash.text.TextFormat; import net.hires.debug.Stats; [SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "0x202030")] public class Main extends Sprite { public static var root:Main; private static const END_FRAME:int = 4600; public static const SCREEN_WIDTH:int = 465; public static const SCREEN_HEIGHT:int = 465; public static const BACKGROUND_COLOR:uint = 0x202030; private static const ENEMY_COLOR_TRANSFORMS:Vector.<ColorTransform> = Vector.<ColorTransform>([ new ColorTransform(1.0, 1.0, 1.0, 1.0, -32, -48, -48), new ColorTransform(1.25, 1.0, 1.0, 1.0, -12, -24, -32), new ColorTransform(1.0, 1.0, 1.0, 1.0, -24, -24, -24), new ColorTransform(1.0, 1.0, 1.0, 1.0, -24, -24, -24), ]); private static const NONENEMY_COLOR_TRANSFORMS:Vector.<ColorTransform> = Vector.<ColorTransform>([ new ColorTransform(1.0, 1.0, 1.0, 1.25, -32, -16, 0), new ColorTransform(1.0, 1.0, 1.0, 1.0, -16, -8, -16), new ColorTransform(1.0, 1.0, 1.0, 1.0, -12, -8, -12), new ColorTransform(1.0, 1.0, 1.0, 1.0, -24, -24, -8), ]); private static const MOTION_DATA:String = "2***y00|4***b00|4***w00|g***000,3***J00|3***r00|4***w00|g***000," + "0 g* ** 00|Y ** 1* 10, 0 M* ** 00|Y ** 1* 10, 0000000, 0000000, 0000000, 0000000, 0000000," + "4 ** *A 00|4 ** *a 00|0 ** *0 00, 4 ** *w 00|4 ** *2 00|0 ** *0 00, 4 ** ** 00|4 ** *a 00|0 ** *0 00," + "4 ** ** 00|4 ** *2 00|0 ** *0 00, 0000000, 0000000, 0000000," + "0000000, 0000000, 0000000, 0000000, 0000000, 0000000, 0000000," + "0000000, 0000000, 0000000, 0000000, 0000000, 0000000, 0000000," + "0000000, 0000000, 0000000, 0000000, 0000000," + "8 ** *2 00|8 ** *F 00|Y *8 w0 00|u ** *A 00," + "8 ** *2 00|8 ** *A 00|Y *4 *0 00," + "8 ** *4 00|8 ** *F 00|Y *g z0 00|Y *g z0 00|u ** *w 00," + "g ** *2 01|g ** *0 01|u ** *y 01|u ** 11 00|0 ** *1 00," + "_ ** ** 00|u ** 1* 00|u ** 0* 00|g ** 12 00|u ** 00 00," + "_ ** ** 00|4 ** w* 00|_ ** *1 00," + "a ** *1 01|8 ** *0 01|g ** *w 01|g ** 11 00|0 ** *2 00," + "8 ** *2 00|8 ** *A 00|Y *0 *0 00|Y ** ** 00|Y ** *2 00," + "2 ** *2 00|2 ** *A 00|Y *8 10 00|Y *8 10 00|Y *8 10 00|Y 0* *2 00"; private static const SHOT_DATA:String = "90a0 000k 1000 0010 313, 8000 000h 1100 0010 223, 90a0 000o 1a00 0010 1t3," +"91b0 000a 2000 171a 1E5, 8000 000h 1200 00b0 3A6, 82b0 000a 1000 0712 2Y8," +"91b0 00w4 0000 251a 515, 95c0 000v 1600 a100 081, 90a0 000o 1100 0030 0a1," +"91b0 0004 1500 1538 3A6, 91b0 0002 1500 1548 3A6, 91b0 0002 1100 1536 3Z8," +"80a0 000v 15v0 0020 029, 84b0 000o 15v0 0g0v 0vg, 90a0 Z00f 131f 0090 09o|90b0 f00a 13zn 0090 0ao," +"84b0 000o 15v0 090g 0_g, 93c0 0006 1000 070k 616, 95d0 000a 1700 fi00 2_6"; private static const STAGE_DATA:String = "0A 23a a001|1A 23b A001|30 25a a001|40 25b A001|3A 85c 8000|4A 15d L000|5A 15e 8000|6A 15f L000|" + "8A k3l v000|2A _3g v000|90 26i d00z|cA 23j g00z|eA 23k A00z|" + "h0 26i d00z|iA 23a A001|jA 36l g000|mA 36m _000|" + "rA 38n T101|tA 38o c101|vA 2an T101|xA 2ao c101|yA 28n T101|y_ 2go c101|zA 28n T101|zA 28o c101|" + "B0 1gp H101|BA 1gp 6101|DA 1gp H101|D_ 1gp 6101|EA 1gp H101|E_ 1gp 6101|" + "GA 42q px0H|I_ 42r _x0H|M0 g7v a001|MA g4w A001|" + "TA 11s 0000|X_ 11t 0000|XA 11u 0000|_A 11s 0000|__ 11t 0000|__ 11u 0000"; private static const ENEMY_DATA:String = "a 12 0a 300, a wx 0a 400, a 12 0a 300|a wx 0a 400, a 22 00 070|a x2 00 070, a 12 0g 3d0|a wx 0g 4d0, b 44 00 040|b z4 00 040, 00000000, 00000000, 00000000," +"b o2 Ea 022, b 82 ma 022, b 21 wa A10, b t1 wa A10, b 51 wk Ah0, b q1 wk Ah0," +"c 61 wa Ba5, c 61 wa Ba0, a 21 wa D30, b 21 ta E43, b t2 Ja F52, b 32 w3 064, b r2 w3 064," +"a t1 wa G80, a 21 wa G80, a f1 wa G90, c 41 wg He6, c p1 wg He6, d g1 wg If0, c p1 wg Hg0, c 41 wg Hg0," + "b o2 Ja 0i1, b 82 ma 0i1"; private var _resultTextField:TextField = new TextField(); private var _stats:Stats = new Stats(); private var _enemyLayer:BitmapData = new BitmapData(SCREEN_WIDTH, SCREEN_HEIGHT, false, 0); private var _enemyScreen:Bitmap = new Bitmap(_enemyLayer); private var _nonEnemyLayer:BitmapData = new BitmapData(SCREEN_WIDTH, SCREEN_HEIGHT, false, 0); private var _nonEnemyScreen:Bitmap = new Bitmap(_nonEnemyLayer); public var motionManager:DataManager = new DataManager(MOTION_DATA, MotionData); public var shotManager:ShotManager = new ShotManager(SHOT_DATA); private var _stageManager:StageManager = new StageManager(STAGE_DATA, ENEMY_DATA); private var _bullets:TokenContainer = new TokenContainer(Bullet, _enemyLayer); private var _enemys:TokenContainer = new TokenContainer(Enemy, _enemyLayer); private var _shots:TokenContainer = new TokenContainer(Bullet, _nonEnemyLayer); private var _effects:TokenContainer = new TokenContainer(Effect, _nonEnemyLayer); public var player:Player = new Player(); private var _skipFrame:int = 0; private var _isAuto:Boolean = true; private var _gameFrame:int, _hitCount:int, _score:int; public var inputKey:InputKey = new InputKey(); private var _lcg:LinearCongruentialGenerator = new LinearCongruentialGenerator(); public function Main() { Main.root = this; stage.addEventListener(MouseEvent.CLICK, startPlayer); stage.addEventListener(KeyboardEvent.KEY_DOWN, checkStartPlayerKey); _enemyScreen.blendMode = BlendMode.ADD; _nonEnemyScreen.blendMode = BlendMode.ADD; _resultTextField.defaultTextFormat = new TextFormat(null, 10, 0xFFFFFF); _resultTextField.x = SCREEN_WIDTH - 128; _resultTextField.selectable = false; graphics.beginFill(0x202030); graphics.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); startGame(); } private function startPlayer(event:Event = null):void { _isAuto = false; stage.focus = this; stage.removeEventListener(MouseEvent.CLICK, startPlayer); stage.removeEventListener(KeyboardEvent.KEY_DOWN, checkStartPlayerKey); startGame(); } private function startGame(isFirst:Boolean = true):void { while (numChildren > 0) { removeChildAt(0) } if (!_isAuto) { stage.addEventListener(KeyboardEvent.KEY_DOWN, inputKey.onKeyDown); stage.addEventListener(KeyboardEvent.KEY_UP, inputKey.onKeyUp); } else{ if(!isFirst) addMessage("Your Result\n\nDamaged: " + String(_hitCount) + "\nScore : " + String(_score) + "\n\n click or key 'x' to start"); else addMessage("click to start"); } _gameFrame = 0, _score = 0, _hitCount = 0; inputKey.initialize(); _lcg.initialize(); _stageManager.initialize(); if(_isAuto) initializeInputAuto(); _nonEnemyLayer.fillRect(_nonEnemyLayer.rect, 0); addChild(_nonEnemyScreen); _enemyLayer.fillRect(_enemyLayer.rect, 0); addChild(_enemyScreen); _bullets.clear(); _enemys.clear(); _shots.clear(); _effects.clear(); player.initialize(1, (SCREEN_WIDTH << Token.FIELD_SCALE) / 2, ((SCREEN_HEIGHT - 32) << Token.FIELD_SCALE)); updateResult(); addChild(_resultTextField); addChild(_stats); addEventListener(Event.ENTER_FRAME, enterFrameHandler); } private function enterFrameHandler(event:Event):void { _enemyLayer.lock(); _nonEnemyLayer.lock(); for (var i:int = 0; i <= _skipFrame; i++) { _gameFrame++; _enemyLayer.colorTransform(_enemyLayer.rect, ENEMY_COLOR_TRANSFORMS[_gameFrame % 4]); _nonEnemyLayer.colorTransform(_nonEnemyLayer.rect, NONENEMY_COLOR_TRANSFORMS[_gameFrame % 4]); _stageManager.update(_gameFrame); _enemys.update(); _bullets.update(); _shots.update(); _effects.update(); checkAttackEnemy(); if(!player.isInvincible) checkAttackPlayer(); if (_isAuto) inputKey.pushed = inputAuto(_gameFrame, player, _enemys.tokens, _bullets.tokens, _enemyLayer) player.update(); player.draw(_nonEnemyLayer); } _enemyLayer.unlock(); _nonEnemyLayer.unlock(); if (_gameFrame == END_FRAME) { endGame(); } } private function endGame():void { removeEventListener(Event.ENTER_FRAME, enterFrameHandler); if (!_isAuto){ _isAuto = true; stage.removeEventListener(KeyboardEvent.KEY_DOWN, inputKey.onKeyDown); stage.removeEventListener(KeyboardEvent.KEY_UP, inputKey.onKeyUp); stage.addEventListener(MouseEvent.CLICK, startPlayer); stage.addEventListener(KeyboardEvent.KEY_DOWN, checkStartPlayerKey); } addEventListener(Event.ENTER_FRAME, restart); } private function restart(event:Event):void { removeEventListener(Event.ENTER_FRAME, restart); startGame(false); } private function checkStartPlayerKey(event:KeyboardEvent):void { if (event.keyCode == 88) // keydown 'x' startPlayer(); } private function checkAttackPlayer():void { var lx:int = player.x >> Token.FIELD_SCALE; var ly:int = player.y >> Token.FIELD_SCALE; if ((_enemyLayer.getPixel(lx, ly) & 0xFF0000) == 0) // rough check return; if (checkCollisionPoint(player.x, player.y, _bullets.tokens)) { _hitCount++; updateResult(); player.damage(); } } private function checkAttackEnemy():void { var tokens:Vector.<IToken> = _shots.tokens; var n:int = tokens.length; for (var i:int = 0; i < n; i++ ) { var token:Token = tokens[i] as Token; var lx:int = token.x >> Token.FIELD_SCALE; var ly:int = token.y >> Token.FIELD_SCALE; if ((_enemyLayer.getPixel(lx, ly) & 0xFF0000) != 0 && checkCollisionEnemy(token)) token.vanish(); } } private function checkCollisionEnemy(shot:IToken):Boolean { var tokens:Vector.<IToken> = _enemys.tokens; var n:int = tokens.length; for (var i:int = 0; i < n; i++ ) { var enemy:Token = tokens[i] as Token; if (enemy.isCollision(shot.x, shot.y)) { enemy.damage(); return true; } } return false; } private function checkCollisionPoint(x:int, y:int, tokens:Vector.<IToken>):Boolean { var n:int = tokens.length; for (var i:int = 0; i < n; i++ ) { var token:Token = tokens[i] as Token; if (token.isCollision(x, y)) { return true; } } return false; } private function addMessage(message:String):void { var textField:TextField = new TextField(); var textFormat:TextFormat = new TextFormat(null, 20, 0xFFFFFF, true); textField.defaultTextFormat = textFormat; textField.selectable = false; textField.width = SCREEN_WIDTH; textField.height = 256; textField.text = message; addChild(textField); textField.x = (SCREEN_WIDTH - textField.textWidth) / 2; textField.y = (SCREEN_HEIGHT - textField.textHeight) / 2; } public function addBullet(id:int=0, x:int=0, y:int=0, direction:int=0, speed:int=0, motionID:int=0, shotID:int=0):Token { return _bullets.addToken(id, x, y, direction, speed, motionID, shotID); } public function addEnemy(id:int=0, x:int=0, y:int=0, direction:int=0, speed:int=0, motionID:int=0, shotID:int=0):Token { return _enemys.addToken(id, x, y, direction, speed, motionID, shotID); } public function addShot(id:int=0, x:int=0, y:int=0, direction:int=0, speed:int=0, motionID:int=0, shotID:int=0):Token { return _shots.addToken(id, x, y, direction, speed, motionID, shotID); } public function addEffect(id:int=0, x:int=0, y:int=0, direction:int=0, speed:int=0, motionID:int=0, shotID:int=0):Token { return _effects.addToken(id, x, y, direction, speed, motionID, shotID); } public function random():uint { return _lcg.random() } public function addScore(value:int):void { _score += value; updateResult(); } private function updateResult():void { _resultTextField.text = "Damaged: " + String(_hitCount) + "\nScore : " + String(_score); } } } import flash.display.BitmapData; import flash.geom.Point; import flash.events.KeyboardEvent; // Enemy shoot bullet. // When bullet collides with player, player is damaged. // However, player is not damaged when enemy collides with player. // Player moveable x is [8*16, 465-8*16] and y is [8*16, 465-8*16]. // Player's hit rect size is Rectangle(0, 0, 1*16, 1*16). It means a dot of screen. // Player's hit rect area is Rectangle(token.x, token.y, 1*16, 1*16) on game field // and Rectangle(token.x, token.y, 1, 1) on screen bitmap. // Bullet's hit rect size is Rectangle(0, 0, 16*16, 16*16). // Center of hit rect is Point(token.x, token.y). // So, Bullet's hit rect area is Rectangle(token.x - 8*16, token.y - 8*16, 16*16, 16*16) on game field // and Rectangle(token.x / 8 - 8, token.y / 8 - 8, 16, 16) and on screen bitmap. function inputAuto(gameFrame:int, player:IToken, enemys:Vector.<IToken>, bullets:Vector.<IToken>, enemyScreen:BitmapData):int { return InputAutoNearestBulletOtherSide(gameFrame, player, enemys, bullets, enemyScreen) } var centeringFlag:Boolean; function initializeInputAuto():void { centeringFlag = false; } // tekito- function InputAutoNearestBulletOtherSide(gameFrame:int, player:IToken, enemys:Vector.<IToken>, bullets:Vector.<IToken>, enemyScreen:BitmapData):int { var pushedKey:int = InputKey.KEY_SHOT; // always shoot if (bullets.length == 0) return pushedKey; if (centeringFlag) { if ((465/2-100)*16 < player.x && player.x < (465/2+100)*16) { centeringFlag = false; return pushedKey; } else if (player.x < 465 / 2 * 16) return pushedKey | InputKey.KEY_RIGHT; else return pushedKey | InputKey.KEY_LEFT; } if (player.x < Player.MIN_X + 30 * 16) { centeringFlag = true; return pushedKey | InputKey.KEY_RIGHT; } if (player.x > Player.MAX_X - 30 * 16) { centeringFlag = true; return pushedKey | InputKey.KEY_LEFT; } var nearestIndex:int = 0; var nearestLength:Number = Math.pow(player.x - bullets[0].x, 2) + Math.pow(player.y - bullets[0].y, 2) var n:int = bullets.length; for (var i:int = 1; i < n; i++ ) { var bullet:IToken = bullets[i]; var len:Number = Math.pow(player.x - bullet.x, 2) + Math.pow(player.y - bullet.y, 2); if (len < nearestLength) { nearestLength = len; nearestIndex = i; } } bullet = bullets[nearestIndex]; if (player.x < bullet.x) pushedKey |= InputKey.KEY_LEFT; else pushedKey |= InputKey.KEY_RIGHT; return pushedKey; } interface IToken { function get id():int; // 0: null, 1: player, 2:player's Shot, 3-5: effect, 6-9: enemy's bullet, 10-:enemy function get x():int; // screen x * 16, [0, 465 * 16] function get y():int; // screen y * 16, [0, 465 * 16] function get vx():int; // velocity x function get vy():int; // velocity y function get direction():int; // degree, [0, 360) function get speed():int; function get accelDirection():int; // degree, [0, 360) function get accelSpeed():int; function get frame():int; // alive frame count function get isVanished():Boolean; // When isVanished is true, token will remove } class InputKey { public static const KEY_UP:int = 1; public static const KEY_RIGHT:int = 1 << 1; public static const KEY_DOWN:int = 1 << 2; public static const KEY_LEFT:int = 1 << 3; public static const KEY_SHOT:int = 1 << 4; private static const KEYS:Object = { up:KEY_UP, right:KEY_RIGHT, down:KEY_DOWN, left:KEY_LEFT, shot:KEY_SHOT } private static const KEY_CODE:Object = { up:38, right:39, down:40, left:37, shot:90 }; public var pushed:int; public function initialize():void { pushed = 0; } private function readKeyFlag(event:KeyboardEvent):int { for(var key:String in KEY_CODE) if (event.keyCode == KEY_CODE[key]) return KEYS[key]; return 0; } public function onKeyDown(event:KeyboardEvent):void { var changedKeyFlag:int = readKeyFlag(event); pushed |= changedKeyFlag; } public function onKeyUp(event:KeyboardEvent):void { var changedKeyFlag:int = readKeyFlag(event); pushed ^= changedKeyFlag; } } class Token implements IToken { public function get id():int { return _id } public function get x():int { return _parent == null ? _x : _x + _parent.x } public function set x(value:int):void { _x = value } public function get y():int { return _parent == null ? _y : _y + _parent.y } public function set y(value:int):void { _y = value } public function get vx():int { return _vx } public function get vy():int { return _vy } public function get direction():int { return _direction } public function get speed():int { return _speed } public function get accelDirection():int { return _accelDirection } public function set accelDirection(value:int):void { _accelDirection = value } public function get accelSpeed():int { return _accelSpeed } public function set accelSpeed(value:int):void { _accelSpeed = value} public function get frame():int { return _frame } public function get isVanished():Boolean {return _isVanished} protected var _id:int, _frame:int; protected var _x:int, _y:int, _vx:int, _vy:int; protected var _direction:int, _speed:int, _accelDirection:int, _accelSpeed:int; protected var _isVanished:Boolean; protected var _parent:IToken; public function set parent(value:IToken):void { _parent = value } private var _motionGroup:Array; /* Array of MotionData */ private var _currentMotion:MotionData; private var _motionFrame:int, _motionState:int; private var _shotGroup:Array; /* Array of ShotData */ private static var tmpPoint:Point = new Point(); public static const FIELD_SCALE:int = 4; private static const FIELD_WIDTH:int = Main.SCREEN_WIDTH << FIELD_SCALE; private static const FIELD_HEIGHT:int = Main.SCREEN_HEIGHT << FIELD_SCALE; public static const DEG_CIRCLE:int = 360; private static const DEG_HALF:int = DEG_CIRCLE / 2; private static const DEG_SCALE:int = 100; private static const PI_DEG_HALF:Number = Math.PI / DEG_HALF; private static const PI_HALF:Number = Math.PI / 2; protected static const bitmapDataTable:Vector.<BitmapData> = createBitmapTable(); public static function createBitmapTable():Vector.<BitmapData> { var table:Vector.<BitmapData> = new Vector.<BitmapData>(); table.push(new BitmapData(1, 1, true, 0)); // null table.push(new BitmapData(16, 16, true, 0xFFFF4500)); // player table.push(new BitmapData(16, 16, true, 0xFF606000)); // shot table.push(new BitmapData(6, 6, true, 0xFFFFD700)); // effect1 table.push(new BitmapData(6, 6, true, 0xFF88672C)); // effect2 table.push(new BitmapData(12, 12, true, 0xFFD040A0)); // effect3 table.push(new BitmapData(16, 16, true, 0xFFFFFFFF)); // bullet1 (no use) table.push(new BitmapData(16, 16, true, 0xFFFF5050)); // bullet2 (no use) table.push(new BitmapData(16, 16, true, 0xFFFFDD50)); // bullet3 table.push(new BitmapData(16, 16, true, 0xFFFFEEEE)); // bullut4 table.push(new BitmapData(20, 20, true, 0xFFEE2050)); // child enemy1 table.push(new BitmapData(32, 32, true, 0xFF5050FF)); // enemy1 table.push(new BitmapData(80, 64, true, 0xFF50AAFF)); // enemy2 table.push(new BitmapData(160, 80, true, 0xFFD050FF)); // enemy3 return table; } public function initialize(id:int=0, x:int=0, y:int=0, direction:int=0, speed:int=0, motionID:int=0, shotID:int=0):void { _id = id; _x = x; _y = y; _direction = direction; _speed = speed; _frame = 0; _isVanished = false; _accelDirection = 0; _accelSpeed = 0; setVelocity(); _currentMotion = null; _motionGroup = null; _motionFrame = 0; _motionState = 0; _shotGroup = null; _parent = null; if (motionID != 0){ _motionGroup = Main.root.motionManager.getDataGroup(motionID); setMotion(); } if (shotID != 0){ _shotGroup = Main.root.shotManager.getDataGroup(shotID); } } public function update():void { _frame++; motion(); if (_accelSpeed != 0 || _accelDirection != 0) { setMovement(_direction + _accelDirection, _speed + _accelSpeed); } _x += _vx; _y += _vy; if ((_frame > 8 && _parent == null && (_x < 0 || _x >= FIELD_WIDTH || _y < 0 || _y >= FIELD_HEIGHT)) // out of field || (_parent != null && _parent.isVanished)) // parent vanished _isVanished = true; else shot(); } public function draw(buffer:BitmapData):void { var bitmapData:BitmapData = bitmapDataTable[_id]; tmpPoint.x = (_x >> FIELD_SCALE) - (bitmapData.width >> 1); tmpPoint.y = (_y >> FIELD_SCALE) - (bitmapData.height >> 1); if (_parent != null) { tmpPoint.x += _parent.x >> FIELD_SCALE; tmpPoint.y += _parent.y >> FIELD_SCALE; } buffer.copyPixels(bitmapData, bitmapData.rect , tmpPoint, null, null, true); } public function setMovement(d:int, s:int) :void { _direction = d % DEG_CIRCLE; _speed = s; setVelocity(); } public function set direction(d:int) :void { _direction = d % DEG_CIRCLE; setVelocity(); } public function set speed(s:int) :void { _speed = s; setVelocity(); } protected function setVelocity():void { _vx = (Math.floor(Math.sin(_direction * PI_DEG_HALF) * DEG_SCALE) / DEG_SCALE) * _speed; _vy = ( -Math.floor(Math.sin(_direction * PI_DEG_HALF + PI_HALF) * DEG_SCALE) / DEG_SCALE) * _speed; } protected function setMotion():void { _currentMotion = _motionGroup[_motionState]; _accelDirection = _currentMotion.accelDirection != int.MAX_VALUE ? _currentMotion.accelDirection : 0; _accelSpeed = _currentMotion.accelSpeed != int.MAX_VALUE ? _currentMotion.accelSpeed : 0; if (_currentMotion.direction != int.MAX_VALUE) _direction = _currentMotion.target ? _currentMotion.direction : _currentMotion.direction + getAimDirection(); if (_currentMotion.speed != int.MAX_VALUE) _speed = _currentMotion.speed; setVelocity(); } protected function motion():void { if (_currentMotion != null) { if (_currentMotion.frame <= _motionFrame) { if (_motionState < _motionGroup.length - 1) { _motionState = _currentMotion.goto == 0 ? _motionState+1 : _currentMotion.goto-1; setMotion(); _motionFrame = 0; } else { _currentMotion = null; } } else if (_currentMotion.target) { direction = getAimDirection(); } } _motionFrame++; } protected function shot():void { if (_shotGroup != null) { var startFrame:int = 0; var n:int = _shotGroup.length; for (var i:int = 0; i < n; i++ ) { var shotData:ShotData = _shotGroup[i]; var f:int = _frame - shotData.startFrame + startFrame; if ((f >= 0) && (_frame <= startFrame + shotData.endFrame) && (f % shotData.stepFrame == 0)) Main.root.shotManager.shot(this, shotData); startFrame += shotData.startFrame; } } } protected function getAimDirection():int { return ShotManager.getAimDirection(x, y); } public function damage():void { } public function vanish():void { _isVanished = true; } public function isCollision(x:int, y:int):Boolean { return false; } } class Effect extends Token { private var _gravity:int = 0; private var _aliveFrame:int = 0; override public function initialize(id:int = 0, x:int = 0, y:int = 0, direction:int = 0, speed:int = 0, motionID:int = 0, shotID:int = 0):void { super.initialize(id, x, y, direction, speed, motionID, shotID); if (id == 3) { _gravity = 4; _aliveFrame = 90 } else if (id == 4) { _gravity = 2; _aliveFrame = 15 } else if (id == 5) { _gravity = 4; _aliveFrame = 90 } } override public function update():void { super.update(); if (_frame > _aliveFrame) vanish(); _y += _frame * _gravity; } } class Bullet extends Token { protected var _hitTopX:int; protected var _hitTopY:int; protected var _hitBottomX:int; protected var _hitBottomY:int; override public function initialize(id:int = 0, x:int = 0, y:int = 0, direction:int = 0, speed:int = 0, motionID:int = 0, shotID:int = 0):void { super.initialize(id, x, y, direction, speed, motionID, shotID); var bitmapData:BitmapData = bitmapDataTable[_id]; _hitTopX = -(bitmapData.width >> 1) << Token.FIELD_SCALE; _hitTopY = -(bitmapData.height >> 1) << Token.FIELD_SCALE; _hitBottomX = (bitmapData.width >> 1) << Token.FIELD_SCALE; _hitBottomY = (bitmapData.height >> 1) << Token.FIELD_SCALE; } override public function isCollision(cx:int, cy:int):Boolean { return (x + _hitTopX < cx) && (y + _hitTopY < cy) && (x + _hitBottomX > cx) && (y + _hitBottomY > cy); } } class Enemy extends Bullet { private var _life:int = 0; override public function initialize(id:int = 0, x:int = 0, y:int = 0, direction:int = 0, speed:int = 0, motionID:int = 0, shotID:int = 0):void { super.initialize(id, x, y, direction, speed, motionID, shotID); _life = 3; if (id == 12) _life += 10; else if (id == 10) _life = 1; else if (id == 13) _life += 40; _hitTopX -= 16 << Token.FIELD_SCALE; _hitTopY -= 16 << Token.FIELD_SCALE; _hitBottomX += 16 << Token.FIELD_SCALE; _hitBottomY += 16 << Token.FIELD_SCALE; } override public function damage():void { _life--; Main.root.addScore(10); if (_life == 0) { n = _parent == null ? 12 + (id - 11) * 8 : 4; for (i = 0; i < n; i++ ) { Main.root.addEffect(5, x, y, 240/n*i + int(Main.root.random() % 30) + 210, 64 + int(Main.root.random() % 64), 2) } Main.root.addScore(_parent == null ? (id - 10) * 1000 : 5000); vanish(); } else { var n:int = 4; for (var i:int = 0; i < n; i++ ) { Main.root.addEffect(4, x, y, 120/n*i + int(Main.root.random() % 60) + 120, 8 + int(Main.root.random() % 64), 1) } } } } class Player extends Token { public static const MAX_X:int = (Main.SCREEN_WIDTH - 8) << Token.FIELD_SCALE; public static const MIN_X:int = 8 << Token.FIELD_SCALE; public static const MAX_Y:int = (Main.SCREEN_HEIGHT - 8) << Token.FIELD_SCALE; public static const MIN_Y:int = 8 << Token.FIELD_SCALE; private static const COMMAND_DIRECTIONS:Object = { 1:0, 2:90, 4:180, 8:270, 3:45, 6:135, 9:315, 12:225 } private static const MOVE_SPEED:int = 32; private static const MOVE_MAXSPEED:int = 96; private static const MOVE_BRAKE:int = 32; private static const SHOT_SPEED:int = 196; private static const DAMAGED_INVINCIBLE_FRAME:int = 30; public function get isInvincible():Boolean { return _invincibleFrame > 0 } private var _invincibleFrame:int; private var _shotFrame:int; private var _shotFlag:Boolean; override public function initialize(id:int = 0, x:int = 0, y:int = 0, direction:int = 0, speed:int = 0, motionID:int = 0, shotID:int = 0):void { super.initialize(id, x, y, direction, speed, motionID, shotID); _invincibleFrame = 0; _shotFrame = 0; _shotFlag = false; } override public function update():void { super.update(); command(); if (_invincibleFrame > 0) _invincibleFrame--; } override public function draw(buffer:BitmapData):void { if(_invincibleFrame == 0 || _invincibleFrame % 4 == 0) super.draw(buffer); } override protected function shot():void { if (_shotFrame != 0) { if (_shotFrame > 0) { if (_shotFrame > 12) { _shotFrame = -12; _shotFlag = false; } else if(_shotFrame % 4 == 1){ Main.root.addShot(2, _x - 256, _y - 32, 0, SHOT_SPEED); Main.root.addShot(2, _x + 256, _y - 32, 0, SHOT_SPEED); } } _shotFrame++; if (_shotFrame == 0){ if(_shotFlag) { _shotFrame = 1; _shotFlag = false; } else if (((Main.root.inputKey.pushed & InputKey.KEY_SHOT) != 0)) { _shotFrame = 1; _shotFlag = false; } } } } private function command():void { var pushedKey:int = Main.root.inputKey.pushed; var p:int = pushedKey & (InputKey.KEY_UP | InputKey.KEY_RIGHT | InputKey.KEY_DOWN | InputKey.KEY_LEFT) if (p in COMMAND_DIRECTIONS) { if (_speed < MOVE_MAXSPEED) _speed += MOVE_SPEED; direction = COMMAND_DIRECTIONS[p]; setVelocity(); } else if (_speed > 0) { var b:int = MOVE_BRAKE; _speed -= b; if (_speed < 0) _speed = 0; setVelocity(); } if (_x < MIN_X) { _x = MIN_X } else if (_x > MAX_X) { _x = MAX_X } if (_y < MIN_Y) {_y = MIN_Y} else if (_y > MAX_Y) { _y = MAX_Y } if ((pushedKey & InputKey.KEY_SHOT) != 0) { if (_shotFrame == 0) _shotFrame++; else _shotFlag = true; } } override public function damage():void { _invincibleFrame = DAMAGED_INVINCIBLE_FRAME; var n:int = 16; for (var i:int = 0; i < n; i++ ) { Main.root.addEffect(3, _x, _y, 90/n*i + int(Main.root.random() % 30) + 315, 16 + int(Main.root.random() % 96), 1) } } } class DataContainer{ protected static const VALUE_TABLE:Object = createValueTable(); protected static function createValueTable():Object { var i:int; var table:Object = { }; var ca:int = "a".charCodeAt(0); var cA:int = "A".charCodeAt(0); for (i = 0; i < 10; i++) { table[String(i)] = i } for (i = 0; i < 26; i++ ) { table[String.fromCharCode(ca + i)] = 10 + i} for (i = 0; i < 26; i++ ) { table[String.fromCharCode(cA + i)] = 36 + i} table['-'] = 62; table['_'] = 63; table['*'] = int.MAX_VALUE; return table; } protected function getDeg(value:int):int{return value != int.MAX_VALUE ? Math.floor(value * Token.DEG_CIRCLE / 64) : value} protected function getInteger(value:int):int {return value != int.MAX_VALUE ? (value < 32 ? value : -(value - 31)) : value} protected function getInteger2(value:int):int { return value != int.MAX_VALUE ? (value < 32 ? value * 2: -(value - 31)) * 2 : value } public function setData(data:String):void { } } class DataManager { private var _dataClass:Class; protected var _dataList:Array = []; public function DataManager(data:String, dataClass:Class) { _dataClass = dataClass; var groupTable:Array = data.replace(/\s/g, "").split(/,/); var n:int = groupTable.length; for (var i:int = 0; i < n; i++) { var elementList:Array = []; var elementDataList:Array = String(groupTable[i]).split(/\|/); var m:int = elementDataList.length; for (var j:int = 0; j < m; j++ ) { var element:DataContainer = new dataClass(); element.setData(elementDataList[j]); elementList.push(element); } _dataList[i] = elementList; } } public function getDataGroup(dataID:int):Array { return _dataList[dataID-1]; } } class StageEnemyData extends DataContainer{ public var id:int; public var x:int, y:int; public var direction:int, speed:int; public var motion:int, shot:int; public var children:int; override public function setData(data:String):void { id = VALUE_TABLE[data.charAt(0)]; x = Math.floor(getInteger(VALUE_TABLE[data.charAt(1)]) * Main.SCREEN_WIDTH / 32) << Token.FIELD_SCALE; y = Math.floor(getInteger(VALUE_TABLE[data.charAt(2)]) * Main.SCREEN_HEIGHT / 32) << Token.FIELD_SCALE; direction = getDeg(VALUE_TABLE[data.charAt(3)]); speed = getInteger2(VALUE_TABLE[data.charAt(4)]); motion = VALUE_TABLE[data.charAt(5)]; shot = VALUE_TABLE[data.charAt(6)]; children = VALUE_TABLE[data.charAt(7)]; } } class StageEnemyFormationData extends DataContainer { public var startFrame:int, endFrame:int; public var stepFrame:int, num:int; public var id:int; public var stepX:int, stepY:int; public var stepDirection:int, stepSpeed:int; override public function setData(data:String):void { startFrame = VALUE_TABLE[data.charAt(0)] * 64 + VALUE_TABLE[data.charAt(1)]; stepFrame = VALUE_TABLE[data.charAt(2)] * 8; num = VALUE_TABLE[data.charAt(3)]; endFrame = startFrame + stepFrame * num; id = VALUE_TABLE[data.charAt(4)]; stepX = getInteger2(VALUE_TABLE[data.charAt(5)]) << Token.FIELD_SCALE; stepY = getInteger2(VALUE_TABLE[data.charAt(6)]) << Token.FIELD_SCALE; stepDirection = getDeg(VALUE_TABLE[data.charAt(7)]); stepSpeed = getInteger2(VALUE_TABLE[data.charAt(8)]); } } class StageManager extends DataManager { private var _stageEnemyTable:Array = []; private var _enemyManager:DataManager; private var _currentStage:int = 0; private var _activeFormations:Array = []; public function StageManager(data:String, enemyData:String) { super(data, StageEnemyFormationData); _enemyManager = new DataManager(enemyData, StageEnemyData); var n:int = _dataList.length; for (var i:int = 0; i < n; i++ ) { var frameEnemyTable:Object = { }; var m:int = _dataList[i].length for (var j:int = 0; j < m; j++ ) { var formation:StageEnemyFormationData = _dataList[i][j]; if (!(formation.startFrame in frameEnemyTable)) { frameEnemyTable[formation.startFrame] = []; } (frameEnemyTable[formation.startFrame] as Array).push(formation); } _stageEnemyTable[i] = frameEnemyTable; } } public function initialize():void { _activeFormations = []; } public function update(frame:int):void { var stageEnemy:Object = _stageEnemyTable[_currentStage]; if (frame in stageEnemy) { var formations:Array = stageEnemy[frame]; var n:int = formations.length; for (var i:int = 0; i < n; i++ ) { _activeFormations.push(formations[i]); } } n = _activeFormations.length; for (i = 0; i < n; i++ ) { var formation:StageEnemyFormationData = _activeFormations[i]; if (frame >= formation.endFrame){ _activeFormations.splice(i, 1); n--; i--; } else if ((frame - formation.startFrame) % formation.stepFrame == 0){ createFormationEnemy(formation, int((frame - formation.startFrame) / formation.stepFrame)); } } } private function createFormationEnemy(formation:StageEnemyFormationData, step:int):void { var enemys:Array = _enemyManager.getDataGroup(formation.id); var n:int = enemys.length; for (var i:int = 0; i < n; i++ ){ var enemy:StageEnemyData = enemys[i]; var enemyToken:Token = createEnemy(enemy); enemyToken.x += formation.stepX * step; enemyToken.y += formation.stepY * step; enemyToken.direction += formation.stepDirection * step; enemyToken.speed += formation.stepSpeed * step; } } private function createEnemy(enemy:StageEnemyData, parent:IToken = null):Token { var token:Token = Main.root.addEnemy(enemy.id, enemy.x, enemy.y, enemy.direction, enemy.speed, enemy.motion, enemy.shot); if (parent != null) token.parent = parent; if (enemy.children != 0) { var children:Array = _enemyManager.getDataGroup(enemy.children); var n:int = children.length; for (var i:int = 0; i < n; i++ ) createEnemy(children[i], token); } return token; } } class MotionData extends DataContainer { public var frame:int; public var direction:int, speed:int; public var accelDirection:int, accelSpeed:int; public var goto:int, target:Boolean; override public function setData(data:String):void { frame = VALUE_TABLE[data.charAt(0)] * 2; direction = getDeg(VALUE_TABLE[data.charAt(1)]); speed = getInteger2(VALUE_TABLE[data.charAt(2)]); accelDirection = getDeg(VALUE_TABLE[data.charAt(3)]); accelSpeed = getInteger(VALUE_TABLE[data.charAt(4)]); goto = VALUE_TABLE[data.charAt(5)]; target = VALUE_TABLE[data.charAt(6)] != 0; } } class ShotData extends DataContainer { public var id:int, func:int, motion:int, shot:int; public var x:int, y:int, direction:int, speed:int; public var aim:Boolean, deg:int, accelDeg:int, frame:int; public var len:int, num:int, way:int, wide:int; public var startFrame:int, stepFrame:int, endFrame:int; override public function setData(data:String):void { id = VALUE_TABLE[data.charAt(0)]; func = VALUE_TABLE[data.charAt(1)]; motion = VALUE_TABLE[data.charAt(2)]; shot = VALUE_TABLE[data.charAt(3)]; x = getInteger(VALUE_TABLE[data.charAt(4)]) << Token.FIELD_SCALE; y = getInteger(VALUE_TABLE[data.charAt(5)]) << Token.FIELD_SCALE; direction = getDeg(VALUE_TABLE[data.charAt(6)]); speed = getInteger2(VALUE_TABLE[data.charAt(7)]); aim = VALUE_TABLE[data.charAt(8)] != 0; deg = getDeg(VALUE_TABLE[data.charAt(9)]); accelDeg = getDeg(VALUE_TABLE[data.charAt(10)]); frame = VALUE_TABLE[data.charAt(11)]; len = VALUE_TABLE[data.charAt(12)]; num = VALUE_TABLE[data.charAt(13)]; way = VALUE_TABLE[data.charAt(14)]; wide = VALUE_TABLE[data.charAt(15)]; startFrame = VALUE_TABLE[data.charAt(16)] * 20; stepFrame = VALUE_TABLE[data.charAt(17)]; endFrame = VALUE_TABLE[data.charAt(18)] * 20; } } class ShotManager extends DataManager{ private static const PI:Number = Math.PI; private static const SHOT_FUNCS:Vector.<Function> = Vector.<Function>([shotWay, shotLineWay, shotCurve, shotLineToArrow, shotCircle, shotRandom]); public function ShotManager(data:String) { super(data, ShotData); } public function shot(token:IToken, shotData:ShotData):void { SHOT_FUNCS[shotData.func](token, shotData); } private static function shotBullet(id:int, x:int, y:int, direction:int, speed:int, motionID:int, shotID:int):Token { return Main.root.addBullet(id, x, y, direction, speed, motionID, shotID); } private static function getShotDirection(data:ShotData, bx:int, by:int, direction:int):int { return data.aim ? data.direction + getAimDirection(bx, by) + direction : data.direction + direction; } private static function getDirectionX(direction:int):Number { return int(Math.sin((direction / 180) * PI) * 100) / 100; } private static function getDirectionY(direction:int):Number { return -int(Math.sin((direction / 180) * PI + PI / 2) * 100) / 100; } public static function getAimDirection(x:int, y:int):int { var player:Player = Main.root.player; return Math.floor(((Math.atan2(player.y - y, player.x - x) * 180 / PI) + 90)) % 360; } private static function shotWay(token:IToken, data:ShotData, x:int = 0, y:int = 0, direction:int = 0, speed:int = 0):void { if (data.accelDeg != 0) { var maxFrame:int = data.frame == 0 ? Token.DEG_CIRCLE / data.accelDeg : data.frame; direction += token.frame % maxFrame * data.accelDeg; } var bx:int = token.x + data.x; var by:int = token.y + data.y; var dir:int = getShotDirection(data, bx, by, direction); if (data.way % 2 == 1) shotBullet(data.id, bx, by, dir, data.speed + speed, data.motion, data.shot); var n:int = data.way / 2; for (var i:int = 1; i <= n; i++) { shotBullet(data.id, bx, by, dir + data.deg * i, data.speed + speed, data.motion, data.shot); shotBullet(data.id, bx, by, dir - data.deg * i, data.speed + speed, data.motion, data.shot); } } private static function shotLineWay(token:IToken, data:ShotData, x:int = 0, y:int = 0, direction:int = 0, speed:int = 0):void { var bx:int = token.x + data.x; var by:int = token.y + data.y; var dir:int = getShotDirection(data, bx, by, direction); if (data.way % 2 == 1) { shotLineBullet(bx, by, dir, data, x, y, direction, speed) } var n:int = data.way >> 1; for (var i:int = 1; i <= n; i++) { shotLineBullet(bx, by, dir + data.deg * i, data, x, y, direction, speed); shotLineBullet(bx, by, dir - data.deg * i, data, x, y, direction, speed); } function shotLineBullet(bx:int, by:int, dir:int, data:ShotData, x:int = 0, y:int = 0, direction:int = 0, speed:int = 0):void { var vx:int = getDirectionX(dir) * data.wide; var vy:int = getDirectionY(dir) * data.wide; for (var i:int = 0; i < data.num; i++ ){ var bullet:Token = shotBullet(data.id, bx + vx * i, by + vy * i, dir, data.speed + speed - i, data.motion, data.shot); bullet.accelSpeed = data.len * i; } } } private static function shotCurve(token:IToken, data:ShotData, x:int = 0, y:int = 0, direction:int = 0, speed:int = 0):void { var bx:int = token.x + data.x; var by:int = token.y + data.y; var dir:int = getShotDirection(data, bx, by, direction); var n:int = data.num / 2; for (var i:int = 0; i < data.num; i++) { var bullet:Token = shotBullet(data.id, bx, by, dir + ((i + 1) % data.num - n) * data.wide, data.speed + speed - Math.abs(((i + 1) % data.num - n) * 2), data.motion, data.shot); bullet.accelSpeed = ((i + 1) % data.num - n) * data.len; } } private static function shotLineToArrow(token:IToken, data:ShotData, x:int = 0, y:int = 0, direction:int = 0, speed:int = 0):void { var bx:int = token.x + data.x; var by:int = token.y + data.y; var dir:int = getShotDirection(data, bx, by, direction); var dir2:int = dir + 90; var vx:int = (getDirectionX(dir2) * data.wide) << Token.FIELD_SCALE; var vy:int = (getDirectionY(dir2) * data.wide) << Token.FIELD_SCALE; if (data.num % 2 == 1) shotBullet(data.id, bx, by, dir, data.speed + speed, data.motion, data.shot); var n:int = data.num / 2; var bullet:Token; for (var i:int = 1; i <= n; i++) { bullet = shotBullet(data.id, bx+vx*i, by+vy*i, dir, data.speed + speed, data.motion, data.shot) bullet.accelSpeed += i * 2; bullet = shotBullet(data.id, bx-vx*i, by-vy*i, dir, data.speed + speed, data.motion, data.shot) bullet.accelSpeed += i * 2; } } private static function shotCircle(token:IToken, data:ShotData, x:int = 0, y:int = 0, direction:int = 0, speed:int = 0):void { var bx:int = token.x + data.x; var by:int = token.y + data.y; var dir:int = getShotDirection(data, bx, by, direction); var degUnit:int = 360 / data.num; for (var i:int = 0; i < data.num; i++ ) { var vx:int = (getDirectionX(degUnit*i) * data.wide * 2) << Token.FIELD_SCALE; var vy:int = (getDirectionY(degUnit*i) * data.wide * 2) << Token.FIELD_SCALE; var bullet:Token = shotBullet(data.id , bx + vy, by + vx, dir, data.speed + speed, data.motion, data.shot); } } private static function shotRandom(token:IToken, data:ShotData, x:int = 0, y:int = 0, direction:int = 0, speed:int = 0):void { var bx:int = token.x + data.x; var by:int = token.y + data.y; var dir:int = getShotDirection(data, bx, by, direction); var deg2:int = data.deg >> 1; for (var i:int = 0; i < data.num; i++ ) { var bullet:Token = shotBullet(data.id, bx, by, dir + Main.root.random() % data.deg - deg2, data.speed + speed + Main.root.random() % data.wide, data.motion, data.shot); if(data.len != 0) bullet.accelSpeed = Main.root.random() % data.len; } } } class TokenContainer { private var _tokenClass:Class; private var _layer:BitmapData; private var _tokens:Vector.<IToken> = new Vector.<IToken>(); public function get tokens():Vector.<IToken> { return _tokens; } private var _oldTokens:Vector.<Token> = new Vector.<Token>(); public function TokenContainer(tokenClass:Class, layer:BitmapData) { _tokenClass = tokenClass; _layer = layer; } public function addToken(id:int=0, x:int=0, y:int=0, direction:int=0, speed:int=0, motionID:int=0, shotID:int=0):Token { var token:Token = _oldTokens.length > 0 ? _oldTokens.pop() : new _tokenClass(); token.initialize(id, x, y, direction, speed, motionID, shotID); _tokens.push(token); return token; } public function update():void { var n:int = _tokens.length; for (var i:int = 0; i < n; i++) { var token:Token = tokens[i] as Token; token.update(); if (token.isVanished) { tokens.splice(i, 1); n--; i--; _oldTokens.push(token); } else{ token.draw(_layer); } } } public function clear():void { _tokens = new Vector.<IToken>(); } } class LinearCongruentialGenerator { private static const A:Number = 1664525; private static const C:Number = 1013904223; private static const M:Number = 0x100000000; private var x:Number; public function LinearCongruentialGenerator(seed:Number = 1.0):void { initialize(seed); } public function initialize(seed:Number = 1.0):void { x = seed; } public function random():uint { x = (x * A + C) % M; return x; } } 俺の弾幕を越えていけ(Shooting AI)