// forked from 5ivestar's ActionScript で弾幕ゲーをこしらえてみた // 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(width="465", height="465", backgroundColor="#262626", frameRate="60")] public class Sakege 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 Sakege() { stage.align = "TL"; stage.scaleMode = "noScale"; var context:LoaderContext = new LoaderContext; context.checkPolicyFile = true; loader = new Loader(); loader.contentLoaderInfo.addEventListener("complete", loadingComplete); loader.load(new URLRequest("http://assets.wonderfl.net/images/related_images/0/08/0844/08445684994346996daf69cea2874c4b0ed6a87a"), context); 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, 150); eField.addBullet(enemy); Bullet.player = player; Bullet.enemy = enemy; Bullet.field = eField; Player.field = pField; 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>; private var rect:Rectangle; public function BulletField(w:Number, h:Number) { fieldWidth = w; fieldHeight = h; bullets = new Vector.<Bullet>(); var bmp:BitmapData = new BitmapData(w, h, true, 0x00000000); rect = bmp.rect; super(bmp); } public function addBullet(bullet:Bullet):void { //bullet.field = this; bullets.push(bullet); } public function update():uint { bitmapData.lock(); bitmapData.fillRect(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.display.Shape; import flash.events.Event; import flash.events.KeyboardEvent; import flash.geom.ColorTransform; import flash.geom.Matrix; import flash.geom.Point; import flash.geom.Rectangle; // BulletField 上に表示されるオブジェクトの基底クラス // 動きを変更するには update // 当たり判定を変更するには hitTest // をそれぞれオーバーライドする class Bullet { public static var player:Player; public static var enemy:Enemy; public var x:Number = 0; public var y:Number = 0; public var direction:Number = 0; public static var field:BulletField; public var dead:Boolean = false; 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(bulletClass:Class, n:uint, direction:Number, range:Number, f:BulletField = null):void { var bullets:Vector.<Bullet> = (f || field).bullets; var length:uint = bullets.length; if (n == 1) { bullets[length] = new bulletClass(x, y, direction); } else { for (var i:int = 0; i < n; i++) { bullets[length + i] = new bulletClass(x, y, direction + range * (i/(n-1)-0.5)); } } } public function allDirections(bulletClass:Class, n:uint, direction:Number, f:BulletField = null):void { var bullets:Vector.<Bullet> = (f || field).bullets; var length:uint = bullets.length; for (var i:int = 0; i < n; i++) { bullets[length + i] = new bulletClass(x, y, direction + Math.PI * 2 * i/n); } } } // 自機 class Player extends Bullet { public static var images:Vector.<BitmapData>; public static var field:BulletField; 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; private var rect:Rectangle; public static function loadImage(bmp:BitmapData):void { images = new Vector.<BitmapData>(3, true); images[0] = bmp; var bmp1:BitmapData = bmp.clone(); bmp1.colorTransform(bmp.rect, new ColorTransform(1.0, 1.0, 1.0, 0.8)); images[1] = bmp1; var bmp2:BitmapData = bmp.clone(); bmp2.colorTransform(bmp.rect, new ColorTransform(1.0, 1.0, 1.0, 0.2)); images[2] = bmp2; } public function Player(x0:Number = 0, y0:Number = 0) { super(x0, y0, 0); image = images[0]; rect = image.rect; 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 - rect.width / 2; p.y = y - rect.height / 2; field.bitmapData.copyPixels(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; private var n: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 % 200 > 26 && t % 200 < 74) allDirections(GrainBullet1, 15, Math.tan(Math.PI*t*0.02) * 0.03 + int(t*0.01)/3); if (t % 200 > 26 && t % 200 < 74) allDirections(GrainBullet1, 15, -Math.tan(Math.PI*t*0.02) * 0.03 + int(t*0.01)/3); if (t % 200 > 75 && t % 200 < 180 && !(t % 5)) allDirections(GrainBullet2, 8, Math.PI * t / 200); if (t % 200 > 75 && t % 200 < 180 && !(t % 5)) allDirections(GrainBullet2, 8, -Math.PI * t / 200); if (t % 200 == 10) nWay(BigBall3, 6, d, Math.PI / 2); if (t % 200 == 25) nWay(BigBall3, 4, d, Math.PI / 2); } } // Bullet に弾のイメージを管理する機能を付与したクラス // AS3 では静的プロパティは継承されないため // イメージ毎にこうしたクラスを作る必要がある // 粒弾 class GrainBullet extends Bullet { private static var images:Vector.<BitmapData>; private static var p:Point; private static var rect:Rectangle; private static var centerX:Number; private static var centerY:Number; public var image:BitmapData; public static function loadImage(source:BitmapData):void { images = new Vector.<BitmapData>(360, true); 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[i] = bmp; } p = new Point(); rect = images[0].rect; centerX = rect.width / 2; centerY = rect.height / 2; } public function GrainBullet(x0:Number, y0:Number, d:Number) { super(x0, y0, d); updateImage(); } override public function draw():void { p.x = x - centerX; p.y = y - centerY; field.bitmapData.copyPixels(image, rect, p, null, null, true); } override public function hitTest():Boolean { var dx:Number, dy:Number; return (dx = player.x - x) * dx + (dy = player.y - y) * dy < 9; } public function updateImage():void { var i:int = direction / Math.PI * 180; image = images[((i %= 360) < 0) ? i + 360 : i]; } } // 大玉 class BigBall extends Bullet { private static var image:BitmapData; private static var p:Point; private static var rect:Rectangle; private static var centerX:Number; private static var centerY:Number; public static function loadImage(bmp:BitmapData):void { image = bmp; p = new Point() rect = image.rect; centerX = rect.width / 2; centerY = rect.height / 2; } public function BigBall(x0:Number, y0:Number, d:Number) { super(x0, y0, d); } override public function draw():void { p.x = x - centerX; p.y = y - centerY; field.bitmapData.copyPixels(image, rect, p, null, null, true); } override public function hitTest():Boolean { var dx:Number, dy:Number; return (dx = player.x - x) * dx + (dy = player.y - y) * dy < 100; } } // 等速直進運動する弾 class GrainBullet1 extends GrainBullet { private var vx:Number; private var vy:Number; private var t:uint = 0; public function GrainBullet1(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 { if (t < 25) { vx *= 0.98; vy *= 0.98; t++; } 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 vx:Number; private var vy:Number; private var t:uint = 0; public function GrainBullet2(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 { if (t < 25) { vx *= 0.97; vy *= 0.97; t++; } 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 BigBall2 extends BigBall { private var t:uint = 0; private var vx:Number; private var vy:Number; public function BigBall2(x0:Number, y0:Number, d:Number, v:Number = 2) { super(x0, y0, d); vx = Math.cos(direction) * v; vy = -Math.sin(direction) * v; } override public function update():void { t++; x += vx * (1 + t * 0.012); y += vy * (1 + t * 0.012); if (x < -10 || x > field.fieldWidth + 10 || y < -10 || y > field.fieldHeight + 10) { dead = true; } } } // はじけた後自機狙い class BigBall3 extends BigBall { private var t:uint = 0; private var vx:Number; private var vy:Number; public function BigBall3(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 < 50) { vx *= 0.98; vy *= 0.98; x += vx; y += vy; } else if (t == 50) { direction = Math.atan2(y - player.y, player.x - x) + (Math.random() - 0.5) * 0.5; vx = Math.cos(direction) * 2; vy = -Math.sin(direction) * 2; } else { x += vx * (1 + (t-50) * 0.012); y += vy * (1 + (t-50) * 0.012); if (x < -10 || x > field.fieldWidth + 10 || y < -10 || y > field.fieldHeight + 10) { dead = true; } } } } forked from: ActionScript で弾幕ゲーをこしらえてみた