Quantcast
Channel: itouhiroはてなブログ
Viewing all articles
Browse latest Browse all 107

ActionScript3.0でSTGを作成(1)

$
0
0

前の記事:

の続き



STGをFlashで作る。
f:id:itouhiro:20130517125048p:plain


マウス動かして自機を操作。マウスクリックで弾を発射。GAME OVERしたあとゲームを再プレイするには、このWebページをリロード。


拡大版 https://sites.google.com/site/itouhiro/2013/20130517stg.swf?attredirects=0
だと画面横の制限なく移動できてしまうな‥‥。


使用した背景画像はNASA
フォントはPress Start 2P http://www.google.com/fonts/specimen/Press+Start+2P
(c) 2011 Cody "CodeMan38" Boisclair. Released under the SIL Open Font License.


ソースは以下。状態遷移を考えてないフラグ立てプログラミングなので、GAME OVERのあとリスタートできない。

Stg201305.as (Main)

package 
{
    import flash.automation.ActionGenerator;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.GradientType;
    import flash.display.InterpolationMethod;
    import flash.display.PixelSnapping;
    import flash.display.Shape;
    import flash.display.SpreadMethod;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix;
    import flash.text.StyleSheet;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;
    
    /**
     * ...
     * @author itouhiro
     */
    [SWF(width="480",height="480",backgroundColor="0x000000",frameRate="60")]
    public class Stg201305 extends Sprite 
    {
        private var myShip:MyShip;
        private var count:int = 0;
        private var gameOverCount:int;
        private var scoreTxt:TextField;
        private var statusTxt:TextField;
        private var backgroundImg:Bitmap;
        public var enemies:Array = [];
        
        public function Stg201305():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
            
            //背景
            backgroundImg = new Bitmap(new BackgroundImg());
            addChild(backgroundImg);
            setChildIndex(backgroundImg, 0);
            //グラデ背景
            //var matrix:Matrix = new Matrix();
            //matrix.createGradientBox(stage.stageWidth, stage.stageHeight * 0.8, Math.PI / 3, 0, 0);
            //graphics.beginGradientFill(
                //GradientType.LINEAR,
                //[0x030108, 0x100830],
                //[0xffffff, 0x999999],
                //[1, 1],
                //[0, 255],
                //matrix,
                //SpreadMethod.PAD,
                //InterpolationMethod.RGB,
                //0);
            //graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
            //graphics.endFill();
            
            //score表示欄
            scoreTxt = new TextField();
            var theFont:NamcoFont = new NamcoFont();
            /* Font: (c) 2011 Cody "CodeMan38" Boisclair. Released under the SIL Open Font License. */
            scoreTxt.defaultTextFormat = new TextFormat(theFont.fontName, 16, 0xEEEEEE);
            scoreTxt.embedFonts = true;
            scoreTxt.x = 0;
            scoreTxt.width = stage.stageWidth;
            scoreTxt.autoSize = TextFieldAutoSize.CENTER;
            scoreTxt.y = 10;
            addChild(scoreTxt);
            
            //gameOver表示欄
            statusTxt = new TextField();
            statusTxt.defaultTextFormat = new TextFormat(theFont.fontName, 16, 0xEEEEEE);
            statusTxt.embedFonts = true;
            statusTxt.x = 0;
            statusTxt.width = stage.stageWidth;
            statusTxt.autoSize = TextFieldAutoSize.CENTER;
            statusTxt.y = stage.stageHeight / 2 - 16; //16はフォントの縦幅
            statusTxt.text = '';
            addChild(statusTxt);
            
            //自機を配置
            myShip = new MyShip(stage.stageWidth / 2, stage.stageHeight / 2, stage.frameRate, enemies, scoreTxt);
            addChild(myShip);
            
            gameOverCount = stage.frameRate * 2;
            count = 0;
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
        
        private function enterFrameHandler(e:Event):void {
            var i:int;
            moveBackground(null);
            
            if ( ! myShip.gactive) {
                //自機爆破中
                gameOverCount--;
                statusTxt.text = 'GAME OVER';
                for (i = 0; i < enemies.length; i++) {
                    enemies[i].sgameOver();
                    enemies[i].alpha = gameOverCount / (stage.frameRate * 2);
                }
                //自機爆破終了
                if (gameOverCount <= 0) {
                    removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
                    //背景の動作のみ残す
                    addEventListener(Event.ENTER_FRAME, moveBackground);
                    for (i = 0; i < enemies.length; i++) {
                        enemies[i].deleteMyself();
                        enemies[i] = null;
                        delete enemies[i];
                    }
                }
                return;
            }
            //適当に敵を出現
            if (count % 6 === 0) {
                if (Math.random() > 0.75) {
                    var enemy:Enemy = new Enemy(int(stage.stageWidth / 3 * 2 * Math.random()), stage.frameRate, myShip);
                    addChild(enemy);
                    enemies.push(enemy);
                }
            }
        }
        
        private function moveBackground(e:Event):void 
        {
            count++;
            backgroundImg.y = Math.sin((count % 360) * Math.PI / 180) * 20 + 20; // 0~40
        }
    }
}


MyShip.as

package  
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.PixelSnapping;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.media.Sound;
    import flash.text.TextField;
    
    /**
     * ...
     * @author ...
     */
    public class MyShip extends Sprite 
    {
        private var img:Bitmap;
        private var backfire:Bitmap;
        private var bulletCount:int = 0; //弾を射出してからのカウント
        private var enemies:Array = [];
        private var bomberCount:int = 0;
        private var active:Boolean = true;
        private var score:int = 0;
        private var scoreTxt:TextField;
        var imgSrc:Array = [];
        var count:int = 0;
        var displayBackFire:Boolean = true;
        var fps:int = 0;
        
        public function MyShip(_x:int, _y:int, _fps:int, _enemies:Array, _scoreTxt:TextField) {
            x = _x;
            y = _y;
            fps = _fps;
            enemies = _enemies;
            scoreTxt = _scoreTxt;
            
            //自機
            imgSrc[0] = new MyShip1();
            imgSrc[1] = new MyShip2();
            img = new Bitmap(imgSrc[0], PixelSnapping.AUTO, false);
            img.scaleX = img.scaleY = 4.0;
            img.x = -(img.width / 2); //マウスカーソルが指すのをimg画像「中央」にする。0の場合、画像「左上端」を指す
            img.y = -(img.height / 2);
            addChild(img);
            
            imgSrc[2] = new Bang1();
            imgSrc[3] = new Bang2();
            
            //自機のロケット噴射
            backfire = new Bitmap(new MyShipBackFire(), PixelSnapping.AUTO, false);
            backfire.scaleX = backfire.scaleY = 4.0;
            backfire.x = -(img.width / 2) + 1; //素材が1pixelずれてるので補正
            backfire.y = -(img.height / 2) + img.height; //myShipImgの画面下部に位置するよう指定
            backfire.alpha = 0.8;
            displayBackFire = true;
            addChild(backfire);
            
            score = 0;
            setScore(score);
            
            count = 0;
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
            bulletCount = 0;
            addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
        }
        
        private function mouseDownHandler(e:MouseEvent):void {
            //弾を発射
            var bullet:MyBullet = new MyBullet(x, y - img.height / 2, fps, enemies, this);
            parent.addChild(bullet); //myShipの子ではなく、stageの子にする
            parent.setChildIndex(bullet, 1); //背面に配置
            bulletCount = fps / 4;
        }
        
        private function enterFrameHandler(e:Event):void {
            if (bomberCount > 1) {
                img.alpha = bomberCount / 120;
                bomberCount--;
                if (bomberCount === 1) {
                    //消去
                    removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
                    removeChild(img);
                    visible = false;
                }
                //爆発パターンを切り替え
                count++;
                if (count >= fps / 2) {
                    count = 0;
                    displayBackFire = ! displayBackFire;
                    if (displayBackFire){
                        img.bitmapData = imgSrc[2];
                    }else {
                        img.bitmapData = imgSrc[3];
                    }
                }
                return;
            }
            
            x += (parent.mouseX  - x) / 10; //parent. つけないと値がおかしい
            y += (parent.mouseY  - y) / 10;
            
            count++;
            if (count >= fps / 2) {
                //半秒間ごとにロケット噴射の描写を切り替え
                count = 0;
                displayBackFire = ! displayBackFire;
                backfire.visible = displayBackFire;
            }
            
            if (bulletCount > 0) {
                //弾を射出してから1/4秒は、自機の画像を別のに変更
                img.bitmapData = imgSrc[1];
                bulletCount--;
            }else {
                img.bitmapData = imgSrc[0];
            }
        }
        
        public function get gx():int { //gx .. get x の略
            return x;
        }
        public function get gy():int {
            return y;
        }
        //爆発
        public function bomber():void 
        {
            img.bitmapData = imgSrc[2];
            displayBackFire = true;
            active = false;
            bomberCount = 120;
            removeChild(backfire);
            var snd:Sound = new MyShipBomber();
            snd.play(0);
            snd.play(50);
            snd.play(100);
        }
        public function get gactive():Boolean
        {
            return active;
        }
        public function setScore(plusScore:int):void {
            score += plusScore;
            scoreTxt.text = 'SCORE  ' + ('0000000' + score).slice( -7);
        }
    }
}


MyBullet.as

package  {
    import flash.display.Bitmap;
    import flash.display.Sprite;
    import flash.events.Event;
    
    /**
     * ...
     * @author ...
     */
    public class MyBullet extends Sprite {
        private var img:Bitmap;
        private var count:int = 0;
        private var fps:int;
        private var enemies:Array;
        private var myShip:MyShip;
        
        //自機の射出した弾
        public function MyBullet(_x:int, _y:int, _fps:int, _enemies:Array, _myShip:MyShip) {
            x = _x;
            y = _y;
            fps = _fps;
            enemies = _enemies;
            myShip = _myShip;
            
            img = new Bitmap(new MyFire());
            img.scaleX = img.scaleY = 4.0;
            img.x = -(img.width / 2);
            img.y = -(img.height / 2);
            addChild(img);
            
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
        
        private function enterFrameHandler(e:Event):void {
            y -= fps * 0.05;
            
            //当たり判定
            if (myShip.gactive) {
                var elen:int = enemies.length;
                for (var i:int = 0; i < elen; i++) {
                    if (Math.abs(enemies[i].x - x) < 48 && Math.abs(enemies[i].y - y) < 48) {
                        enemies[i].bomber();
                        enemies.splice(i, 1);
                        myShip.setScore(100);
                        deleteMyself();
                        return;
                    }
                }
            }
            
            if (y < -img.height * 2) {
                //画面外に出たら消去
                deleteMyself();
            }
        }
        
        private function deleteMyself():void 
        {
            removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
            removeChild(img);
            parent.removeChild(this);
            delete this;
        }
    }
}


Enemy.as

package  {
    import adobe.utils.CustomActions;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.PixelSnapping;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.media.Sound;
    
    /**
     * ...
     * @author ...
     */
    public class Enemy extends Sprite {
        private var img:Bitmap;
        private var imgSrc:Array = [];
        private var fps:int = 0;
        private var count:int = 0;
        private var index:int = 0;
        private var tendencyX:Number = 0;
        private var tendencyY:Number = 0;
        private var myShip:MyShip;
        private var bomberCount:int = 0;
        private var gameOver:Boolean = false;
        
        public function Enemy(_x:int, _fps:int, _myShip:MyShip) {
            imgSrc[0] = new Enemy1();
            imgSrc[1] = new Enemy2();
            img = new Bitmap(imgSrc[0], PixelSnapping.AUTO, false);
            img.scaleX = img.scaleY = 4.0;
            img.x = -(img.width / 2); //マウスカーソルが指すのをimg画像「中央」にする。0の場合、画像「左上端」を指す
            img.y = -(img.height / 2);
            
            imgSrc[2] = new Bang1();
            imgSrc[3] = new Bang2();
            
            x = _x;
            y = -img.height;
            fps = _fps;
            myShip = _myShip;

            addChild(img);
            
            //tendency ‥‥ どちらに移動するかの傾向
            tendencyX = (Math.random() * 3.0) - 1.0;
            tendencyY = Math.random() * 3.0;
            count = 0;
            index = 0;
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
        
        private function enterFrameHandler(e:Event):void {
            x += (Math.random() * 2.0) * tendencyX;
            y += Math.random() * tendencyY;
            count++;
            
            if (bomberCount <= 0) {
                //撃墜されてない。通常運行
                if (count % (fps / 2) === 0) {
                    //半秒間ごとに画像パターンを切り替え
                    index = (index + 1) % 2;
                    img.bitmapData = imgSrc[index];
                    
                    //弾を撃つ
                    if ( ! gameOver && Math.random() * 10.0 + (tendencyY*0.5) > 9.1) {
                        var blt:Bullet = new Bullet(x, y, fps, Math.atan2(myShip.gy - y, myShip.gx - x), myShip);
                        parent.addChild(blt);
                        parent.setChildIndex(blt, 2);
                    }
                }
                if (count % (fps * 2) === 0) {
                    //移動方向変わるかも
                    tendencyX = (Math.random() * 3.0) - 1.0;
                }
            } else {
                //自機に撃墜されて爆発中
                if (count % (fps / 4) === 0) {
                    index = (index + 1) % 2;
                    img.bitmapData = imgSrc[index + 2];
                }
                img.alpha = (bomberCount * 3) / 100;
                bomberCount--;
            }
            if (outFromStage()){
                //画面外に出たらor爆発終了したら消去
                deleteMyself();
                removeChild(img);
                parent.removeChild(this);
                delete this;
            }
        }
        
        public function deleteMyself():void {
            removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
        
        private function outFromStage():Boolean
        {
            if (y > stage.stageHeight + img.height ||
                y < -img.height * 2 ||
                x > stage.stageWidth + img.width * 2 ||
                x < -img.width * 2 ||
                bomberCount === 1) {
                return true;
            }
            return false;
        }
        
        public function bomber():void 
        {
            img.bitmapData = imgSrc[index + 2];
            bomberCount = 30;
            var snd:Sound = new MyShipBomber();
            snd.play();
        }
        
        public function sgameOver():void {
            gameOver = true;
        }
    }
}


Bullet.as

package  {
    import flash.display.Bitmap;
    import flash.display.Sprite;
    import flash.events.Event;
    
    /**
     * ...
     * @author ...
     */
    public class Bullet extends Sprite {
        private var img:Bitmap;
        private var fps:int = 0;
        private var radian:Number;
        private var myShip:MyShip;
        
        //敵弾
        public function Bullet(_x:int, _y:int, _fps:int, _radian:Number, _myShip:MyShip) {
            x = _x;
            y = _y;
            fps = _fps;
            radian = _radian;
            myShip = _myShip;
            
            img = new Bitmap(new EnemyFire());
            img.scaleX = img.scaleY = 4.0;
            img.x = -(img.width / 2);
            img.y = -(img.height / 2);
            addChild(img);
            
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
        
        private function enterFrameHandler(e:Event):void {
            x += Math.cos(radian) * fps * 0.03;
            y += Math.sin(radian) * fps * 0.03;
            
            //当たり判定
            if (myShip.gactive && 
                Math.abs(myShip.gx - x) < 24 &&
                Math.abs(myShip.gy - y) < 24) {
                    
                myShip.bomber();
                removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
                removeChild(img);
                parent.removeChild(this);
                delete this;
                return;
            }
            
            if (outFromStage()) {
                //画面外に出たら消去
                removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
                removeChild(img);
                parent.removeChild(this);
                delete this;
            }
        }
        private function outFromStage():Boolean
        {
            if (y > stage.stageHeight + img.height ||
                y < -img.height * 2 ||
                x > stage.stageWidth + img.width * 2 ||
                x < -img.width * 2) {
                return true;
            }
            return false;
        }
    }
}

状態遷移を考えて作り直したい。あと同じようなコードが複数ファイルにあるのでまとめたい。







 


Viewing all articles
Browse latest Browse all 107

Trending Articles