// Arrow Key で移動 // Shift で低速移動 // 今のところ避けることしかできません package { import flash.display.Loader; import flash.display.Sprite; import flash.display.BitmapData; import flash.events.Event; import flash.events.MouseEvent; import flash.events.KeyboardEvent; import flash.geom.Rectangle; import flash.geom.Point; import flash.net.URLRequest; import flash.text.TextField; import flash.text.TextFormat; import flash.system.LoaderContext; import flash.system.Security; import net.hires.debug.Stats; [SWF(backgroundColor="#262626", frameRate="60")] public class Game extends Sprite { private var eField:BulletField; private var pField:BulletField; private var player:Player; private var enemy:Enemy; private var status:TextField; private var t:uint; private var hit:uint; private var loader:Loader; public function Game() { stage.align = "TL"; stage.scaleMode = "noScale"; loader = new Loader(); loader.contentLoaderInfo.addEventListener("complete", loadingComplete); loader.load(new URLRequest("http://assets.wonderfl.net/images/related_images/0/08/0844/08445684994346996daf69cea2874c4b0ed6a87a"), new LoaderContext(true)); pField = new BulletField(380, 445); pField.x = 10, pField.y = 10; addChild(pField); eField = new BulletField(380, 445); eField.x = 10, eField.y = 10; addChild(eField); var frame:Sprite = new Sprite(); frame.graphics.beginFill(0x000000); frame.graphics.drawRect(0, 0, 465, 465); frame.graphics.drawRect(10, 10, 380, 445); addChild(frame); var stats:Stats = new Stats(); stats.x = 395; stats.y = 10; frame.addChild(stats); status = new TextField(); status.defaultTextFormat = new TextFormat("_sans", 9); status.autoSize = "left"; status.textColor = 0xffffff; status.x = 395; status.y = 110; frame.addChild(status); } public function loadingComplete(e:Event):void { var source:BitmapData = new BitmapData(55, 28, true, 0x00000000); source.draw(loader); var bmp1:BitmapData = new BitmapData(12, 12, true, 0x00000000); bmp1.copyPixels(source, new Rectangle(0, 0, 12, 12), new Point()); Player.loadImage(bmp1); var bmp2:BitmapData = new BitmapData(15, 15, true, 0x00000000); bmp2.copyPixels(source, new Rectangle(12, 0, 15, 15), new Point()); GrainBullet.loadImage(bmp2); var bmp3:BitmapData = new BitmapData(28, 28, true, 0x00000000); bmp3.copyPixels(source, new Rectangle(27, 0, 28, 28), new Point()); BigBall.loadImage(bmp3); var s:Sprite = new Sprite(); s.graphics.beginFill(0x000000, 0.5); s.graphics.drawRect(10, 10, 380, 445); addChild(s); var tf:TextField = new TextField(); tf.defaultTextFormat = new TextFormat("_sans", 18); tf.autoSize = "left"; tf.textColor = 0xffffff; tf.text = "click start"; tf.x = 200 - tf.width / 2; tf.y = 230 - tf.height / 2; s.addChild(tf); s.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void { removeChild(s); stage.focus = stage; start(); }); } public function start():void { t = 0; hit = 0; eField.clear(); pField.clear(); player = new Player(185, 390); pField.addBullet(player); stage.addEventListener(KeyboardEvent.KEY_DOWN, player.keyDown); stage.addEventListener(KeyboardEvent.KEY_UP, player.keyUp); enemy = new Enemy(185, 75); eField.addBullet(enemy); Bullet.player = player; Bullet.enemy = enemy; addEventListener(Event.ENTER_FRAME, update); } public function update(e:Event):void { t++; pField.update(); var h:uint = eField.update(); if (h) player.hit(); if (player.dead) finish(); hit += h; var s:String = ["BULLETS: " + eField.bullets.length.toString(), "HIT: " + hit.toString(), "LIFE: "].join("\n"); for (var i:int = 0; i < player.life; i++) { s += "★"; } status.text = s; } public function finish():void { removeEventListener(Event.ENTER_FRAME, update); stage.removeEventListener(KeyboardEvent.KEY_DOWN, player.keyDown); stage.removeEventListener(KeyboardEvent.KEY_UP, player.keyUp); var s:Sprite = new Sprite(); s.graphics.beginFill(0x000000, 0.5); s.graphics.drawRect(10, 10, 380, 445); addChild(s); var tf:TextField = new TextField(); tf.defaultTextFormat = new TextFormat("_sans", 18); tf.autoSize = "left"; tf.textColor = 0xffffff; tf.text = "retry"; tf.x = 200 - tf.width / 2; tf.y = 230 - tf.height / 2; s.addChild(tf); s.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void { removeChild(s); stage.focus = stage; start() }); } } } import flash.display.Bitmap; import flash.display.Sprite; // 弾のコンテナ class BulletField extends Bitmap { public var fieldWidth:Number; public var fieldHeight:Number; public var bullets:Vector.<Bullet>; public function BulletField(w:Number, h:Number) { fieldWidth = w; fieldHeight = h; bullets = new Vector.<Bullet>(); var bmp:BitmapData = new BitmapData(w, h, true, 0x00000000); super(bmp); } public function addBullet(bullet:Bullet):void { bullet.field = this; bullets.push(bullet); } public function update():uint { bitmapData.lock(); bitmapData.fillRect(bitmapData.rect, 0x00000000); var hit:uint = 0; var n:uint = bullets.length; while (n--) { var bullet:Bullet = bullets[n]; bullet.update(); bullet.draw(); if (bullet.hitTest()) hit++; if (bullet.dead) { bullets.splice(n, 1); } } bitmapData.unlock() return hit; } public function clear():void { bullets.splice(0, bullets.length); } } import flash.display.Bitmap; import flash.display.BitmapData; import flash.geom.Matrix; // BulletField 上に表示されるオブジェクトの基底クラス // 動きを変更するには update // 当たり判定を変更するには hitTest // をそれぞれオーバーライドする class Bullet { public static var player:Player; public static var enemy:Enemy; public var dead:Boolean = false; public var x:Number = 0; public var y:Number = 0; protected var direction:Number; public var field:BulletField; public function Bullet(x0:Number, y0:Number, d:Number) { x = x0, y = y0; direction = d; } public function update():void { } public function hitTest():Boolean { return false; } public function draw():void { } public function nWay(bullet:Class, n:int, direction:Number, range:Number, f:BulletField = null):void { if (n > 1) { for (var i:int = 0; i < n; i++) { (f || field).addBullet(new bullet(x, y, direction + range * (i/(n-1)-0.5))); } } else if (n == 1) { (f || field).addBullet(new bullet(x, y, direction)); } } } import flash.display.Shape; import flash.events.Event; import flash.events.KeyboardEvent; import flash.geom.ColorTransform; import flash.geom.Point; // 自機 class Player extends Bullet { public static var images:Vector.<BitmapData>; private var image:BitmapData; public var life:int = 4; private var t:uint; private var damaged:uint; private var slow:Boolean = false; private var left:Boolean = false; private var up:Boolean = false; private var right:Boolean = false; private var down:Boolean = false; private var alpha:Number = 1; private var p:Point; public static function loadImage(bmp:BitmapData):void { images = new Vector.<BitmapData>(); images.push(bmp); var bmp1:BitmapData = bmp.clone(); bmp1.colorTransform(bmp.rect, new ColorTransform(1.0, 1.0, 1.0, 0.8)); images.push(bmp1); var bmp2:BitmapData = bmp.clone(); bmp2.colorTransform(bmp.rect, new ColorTransform(1.0, 1.0, 1.0, 0.2)); images.push(bmp2); } public function Player(x0:Number = 0, y0:Number = 0) { super(x0, y0, 0); image = images[0]; p = new Point(); } override public function update():void { t++; var vx:Number = 0; var vy:Number = 0; if (left && !right) vx = -1; if (!left && right) vx = 1; if (up && !down) vy = -1; if (!up && down) vy = 1; if (slow) { x += vx; y += vy; } else { x += vx * 3; y += vy * 3; } x = Math.max(0, x); x = Math.min(field.fieldWidth, x); y = Math.max(0, y); y = Math.min(field.fieldHeight, y); if (damaged) { var n:int = t - damaged; if (n % 8 < 4) { image = images[2]; } else { image = images[1]; } if (n > 75) { image = images[0]; damaged = 0; } } } override public function draw():void { p.x = x - image.width / 2; p.y = y - image.height / 2; field.bitmapData.copyPixels(image, image.rect, p, null, null, true); } public function hit():void { if (!damaged) { damaged = t; life--; if (!life) { dead = true; } } } public function keyDown(e:KeyboardEvent):void { switch (e.keyCode) { case 16: slow = true; break; case 37: left = true; break; case 38: up = true; break; case 39: right = true; break; case 40: down = true; break; } } public function keyUp(e:KeyboardEvent):void { switch (e.keyCode) { case 16: slow = false; break; case 37: left = false; break; case 38: up = false; break; case 39: right = false; break; case 40: down = false; break; } } } // 敵機 class Enemy extends Bullet { private var t:uint; public function Enemy(x0:Number = 0, y0:Number = 0) { super(x0, y0, 0); } override public function update():void { t++; var d:Number = Math.atan2(y - player.y, player.x - x); if (t < 100) { if (!(t % 5)) nWay(GrainBullet1, 30, Math.PI * (t % 360) / 180, Math.PI * 2); } else if (t > 250 && t < 1050) { if (!(t % 25)) nWay(GrainBullet1, 31, d, Math.PI * 4/3); if (!(t % 20)) nWay(BigBall1, 10, -Math.PI * (t % 16) / 8, Math.PI * 2); } else if (t > 1250 && t < 2050) { if (!(t % 10)) nWay(GrainBullet1, 20, Math.PI * (t % 90) / 45, Math.PI * 2); if (!(t % 10)) nWay(GrainBullet1, 20, -Math.PI * (t % 90) / 45, Math.PI * 2); if (!(t % 50)) nWay(BigBall1, 11, d, Math.PI * 4/3); } else if (t > 2200 && t < 2800) { if (!(t % 250)) nWay(GrainBullet2, 20, 0, Math.PI * 2); } } } // Bullet に弾のイメージを管理する機能を付与したクラス // AS3 では静的プロパティは継承されないため // イメージ毎にこうしたクラスを作る必要がある // 粒弾 class GrainBullet extends Bullet { private static var images:Vector.<BitmapData>; private static var p:Point; public var image:BitmapData; public static function loadImage(source:BitmapData):void { images = new Vector.<BitmapData>(); var s:Number = source.width; for (var i:int; i < 360; i++) { var bmp:BitmapData = new BitmapData(s, s, true, 0x00000000); var d:Number = i / 180 * Math.PI; var m:Matrix = new Matrix(); m.translate(-s/2, -s/2); m.rotate(-d); m.translate(s/2, s/2); bmp.draw(source, m, null, null, null, true); images.push(bmp); } p = new Point(); } public function GrainBullet(x0:Number, y0:Number, d:Number) { super(x0, y0, d); updateImage(); } override public function draw():void { p.x = x - image.width / 2; p.y = y - image.height / 2; field.bitmapData.copyPixels(image, image.rect, p, null, null, true); } override public function hitTest():Boolean { return Math.sqrt(Math.pow(player.x - x, 2) + Math.pow(player.y - y, 2)) < 3; } protected function updateImage():void { var l:int = images.length; var i:int = direction / Math.PI * l * 0.5; image = images[((i %= l) < 0) ? i + l : i]; } } // 大玉 class BigBall extends Bullet { private static var image:BitmapData; private static var p:Point; public static function loadImage(bmp:BitmapData):void { image = bmp; p = new Point() } public function BigBall(x0:Number, y0:Number, d:Number) { super(x0, y0, d); } override public function draw():void { p.x = x - image.width / 2; p.y = y - image.height / 2; field.bitmapData.copyPixels(image, image.rect, p, null, null, true); } override public function hitTest():Boolean { return Math.sqrt(Math.pow(player.x - x, 2) + Math.pow(player.y - y, 2)) < 10; } } // 等速直進運動する弾 class GrainBullet1 extends GrainBullet { private var vx:Number; private var vy:Number; public function GrainBullet1(x0:Number, y0:Number, d:Number, v:Number = 1.5) { super(x0, y0, d); vx = Math.cos(direction) * v; vy = -Math.sin(direction) * v; } override public function update():void { x += vx; y += vy; if (x < -10 || x > field.fieldWidth + 10 || y < -10 || y > field.fieldHeight + 10) { dead = true; } } } class BigBall1 extends BigBall { private var vx:Number; private var vy:Number; public function BigBall1(x0:Number, y0:Number, d:Number, v:Number = 1) { super(x0, y0, d); vx = Math.cos(direction) * v; vy = -Math.sin(direction) * v; } override public function update():void { x += vx; y += vy; if (x < -10 || x > field.fieldWidth + 10 || y < -10 || y > field.fieldHeight + 10) { dead = true; } } } // 敵機の周りを回った後はじける class GrainBullet2 extends GrainBullet { private var t:uint = 0; public function GrainBullet2(x0:Number, y0:Number, d:Number) { super(x0, y0, d); } override public function update():void { t++; if (t < 300) { direction += 0.06 - t * 0.0002; updateImage(); x += Math.cos(direction); y -= Math.sin(direction); } else { nWay(GrainBullet3, 50, 0, Math.PI * 2); dead = true; } } } // はじけた後落ちていく class GrainBullet3 extends GrainBullet { private var t:uint = 0; private var vx:Number; private var vy:Number; public function GrainBullet3(x0:Number, y0:Number, d:Number) { super(x0, y0, d); vx = Math.cos(direction) * 2.5; vy = -Math.sin(direction) * 2.5; } override public function update():void { t++; if (t < 100) { vx *= 0.99; vy *= 0.99; x += vx; y += vy; } else { vy += 0.01; x += vx; y += vy; direction = Math.atan2(-vy, vx); updateImage(); if (x < -10 || x > field.fieldWidth + 10 || y < -10 || y > field.fieldHeight + 10) { dead = true; } } } } ActionScript で弾幕ゲーをこしらえてみた