ブロック崩し

by Nos_lkSsvOhB
ブロック崩しが作りたくなったので作ってみました。まぁ、習作ということで…

ちなみに、上側のフレームにぶつかるとボールの速さが1.5倍になります。
♥0 | Line 857 | Modified 2014-04-11 20:00:54 | MIT License
play

ActionScript3 source code

/**
 * Copyright Nos_lkSsvOhB ( http://wonderfl.net/user/Nos_lkSsvOhB )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/4CFm
 */

package
{
    import flash.display.Sprite;
    import flash.events.Event;
    
    /**
     * ...
     * @author Nosuke
     */
    [SWF(backgroundColor="#ffffff",width="465",height="465",frameRate="60")]
    
    public class Main extends Sprite
    {
        private var breakout:Breakout;
        
        public function Main():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
            start();
        }
        
        private function start():void
        {
            breakout = new Breakout(stage);
        }
    }
}

import flash.display.*;
import flash.events.Event;

class Breakout extends Sprite
{
    private var frame:Frame;
    private var blocks:Blocks;
    private var bar:Bar;
    private var ball:Ball;
    private var eventDisp:EventDisp;
    
    public static var stageBreakout:Stage
    
    public function Breakout(stg:Stage)
    {
        super();
        stageBreakout = stg;
        stg.addChild(this);
        
        frame = new Frame(stg.stageWidth, stg.stageHeight, this);
        bar = new Bar(this);
        init();
    }
    
    private function init():void
    {
        ball = new Ball(this);
        blocks = new Blocks(this);
        stageBreakout.addEventListener("miss", whenMissBall);
        stageBreakout.addEventListener("clear", gameClear);
    }
    
    private function whenMissBall(e:Event):void
    {
        stageBreakout.removeEventListener("miss", whenMissBall);
        stageBreakout.removeEventListener("clear", gameClear);
        ball.clear();
        eventDisp = new EventDisp("miss", this);
        stageBreakout.addEventListener("again", resetGame);
    }
    
    private function resetGame(e:Event):void
    {
        stageBreakout.removeEventListener("again", resetGame);
        ball.remove(this);
        blocks.remove(this);
        ball = null;
        blocks = null;
        eventDisp.remove(this);
        eventDisp = null;
        init();
    }
    
    private function gameClear(e:Event):void
    {
        stageBreakout.removeEventListener("miss", whenMissBall);
        stageBreakout.removeEventListener("clear", gameClear);
        ball.stop();
        eventDisp = new EventDisp("clear", this);
        stageBreakout.addEventListener("again", resetGame);
    }
}

import flash.display.Sprite;

class Frame extends Sprite
{
    public static var collision:BreakoutCollision;
    
    public function Frame(stageWidth:int, stageHeight:int, parent:Sprite)
    {
        super();
        parent.addChild(this);
        IniVar.frameWidth = stageWidth - 2 * IniVar.xoffset;
        IniVar.frameHeight = stageHeight - 2 * IniVar.yoffset;
        IniVar.fieldWidth = IniVar.frameWidth - 2 * IniVar.thickness;
        IniVar.fieldHeight = IniVar.frameHeight - 2 * IniVar.thickness;
        this.x = IniVar.xoffset;
        this.y = IniVar.yoffset;
        drawFrame();
        collision = new BreakoutCollision(BreakoutCollision.RECTANGLE_INNER, IniVar.ballR, IniVar.ballR, IniVar.fieldWidth - IniVar.ballR, IniVar.fieldHeight - IniVar.ballR);
    }
    
    private function drawFrame():void
    {
        //frame
        //up side
        drawRect(IniVar.frameColor, 0, 0, IniVar.frameWidth, IniVar.thickness);
        //left side
        drawRect(IniVar.frameColor, 0, IniVar.thickness, IniVar.thickness, IniVar.fieldHeight);
        //down side
        drawRect(IniVar.frameOutColor, 0, IniVar.frameHeight - IniVar.thickness, IniVar.frameWidth, IniVar.thickness);
        //right side
        drawRect(IniVar.frameColor, IniVar.frameWidth - IniVar.thickness, IniVar.thickness, IniVar.thickness, IniVar.fieldHeight);
        //background
        drawRect(IniVar.frameBgColor, IniVar.thickness, IniVar.thickness, IniVar.fieldWidth, IniVar.fieldHeight);
    }
    
    private function drawRect(color:int, xoff:int, yoff:int, wid:int, hei:int):void
    {
        //graphics.lineStyle(0, 0x000000, 0);
        graphics.beginFill(color, 1);
        graphics.drawRect(xoff, yoff, wid, hei);
        graphics.endFill();
    }
}

import flash.display.Sprite;

class Blocks extends Sprite
{
    private var bx:Number;
    private var by:Number;
    private var blocksSprite:Vector.<Sprite> = new Vector.<Sprite>;
    
    public static var blocksCollision:Vector.<BreakoutCollision>;
    public static var collision:BlocksCollision;
    
    public function Blocks(parent:Sprite)
    {
        //super();
        parent.addChild(this);
        this.x = IniVar.xoffset + IniVar.thickness;
        this.y = IniVar.yoffset + IniVar.thickness;
        
        collision = new BlocksCollision(this);
        blocksCollision = new Vector.<BreakoutCollision>;
        for (var i:int = 0; i < IniVar.blocksN; i++)
        {
            blocksSprite[i] = new Sprite();
            drawBlock(blocksSprite[i]);
            arrangeBlocksSprite(blocksSprite[i], i);
            blocksCollision[i] = new BreakoutCollision(BreakoutCollision.CIRCLE, blocksSprite[i].x, blocksSprite[i].y, 0, 0, IniVar.ballR + IniVar.blocksR);
                //blocksCollision[i] = new BreakoutCollision(BreakoutCollision.ROUNDED_RECT, blocksSprite[i].x - IniVar.blocksR / 2, blocksSprite[i].y - IniVar.blocksR / 2, blocksSprite[i].x + IniVar.blocksR / 2, blocksSprite[i].y + IniVar.blocksR / 2,IniVar.ballR);
        }
    }
    
    public function deleteIndex(i:int):void
    {
        blocksCollision[i] = null;
        blocksCollision.splice(i, 1);
        
        this.removeChild(blocksSprite[i]);
        blocksSprite[i] = null;
        blocksSprite.splice(i, 1);
    }
    
    private function drawBlock(sp:Sprite):void
    {
        sp.graphics.beginFill(IniVar.blocksColor, 1);
        sp.graphics.drawCircle(0, 0, IniVar.blocksR);
        //sp.graphics.drawRect(-IniVar.blocksR / 2, -IniVar.blocksR / 2, IniVar.blocksR, IniVar.blocksR);
        sp.graphics.endFill();
        this.addChild(sp);
    }
    
    private function arrangeBlocksSprite(sp:Sprite, i:int):void
    {
        IniVar.blocksXoffset = int((IniVar.fieldWidth - IniVar.blocksR * 2 * (IniVar.blocksCol - 1)) / 2);
        bx = i % IniVar.blocksCol;
        by = int(i / IniVar.blocksCol);
        sp.x = IniVar.blocksXoffset + IniVar.blocksR * 2 * bx;
        sp.y = IniVar.blocksYoffset + IniVar.blocksYspan * by;
    }
    
    private function deleteVector():void
    {
        blocksCollision.length = 0;
        //blocksSprite.length = 0;
        //blocksCollision = null;
        blocksSprite = null;
    }
    
    public function remove(parent:Sprite):void
    {
        parent.removeChild(this);
        recurRemoveChild(this);
        deleteVector();
        parent = null;
    }
    
    public function removeSprite():void
    {
        collision = null;
    }
    
    private function recurRemoveChild(sp:Sprite):void
    {
        while (sp.numChildren > 0)
        {
            recurRemoveChild(sp.getChildAt(sp.numChildren - 1) as Sprite);
            sp.removeChildAt(sp.numChildren - 1);
        }
        if (sp.hasOwnProperty("removeSprite"))
        {
            sp["removeSprite"]();
        }
        sp = null;
    }
}

import flash.display.Sprite;
import flash.events.Event;

class Bar extends Sprite
{
    private var barX:Number;
    private var moveX:Number;
    private var preX:Number;
    private var preY:Number;
    private var bar:Sprite = new Sprite();
    private var rr:int = 10;
    private var yFrag:Boolean = false;
    
    public static var collision:BreakoutCollision;
    
    public function Bar(parent:Sprite)
    {
        super();
        this.x = IniVar.xoffset + IniVar.thickness;
        this.y = IniVar.yoffset + IniVar.thickness;
        parent.addChild(this);
        drawBar();
        moveX = mouseX;
        if (yFrag)
            collision = new BreakoutCollision(BreakoutCollision.ROUNDED_RECT, moveX - IniVar.barWidth / 2, mouseY - IniVar.barHeight / 2, moveX + IniVar.barWidth / 2, mouseY + IniVar.barHeight / 2, IniVar.ballR + rr)
        else
            collision = new BreakoutCollision(BreakoutCollision.ROUNDED_RECT, moveX - IniVar.barWidth / 2, IniVar.baseY - IniVar.barHeight / 2, moveX + IniVar.barWidth / 2, IniVar.baseY + IniVar.barHeight / 2, IniVar.ballR + rr)
        preX = moveX;
        if (yFrag)
            preY = mouseY;
        addEventListener(Event.ENTER_FRAME, onEnterFrame);
    }
    
    private function onEnterFrame(e:Event):void
    {
        moveX = mouseX;
        barMove(moveX);
        collisionMove(moveX);
        preX = moveX;
        if (yFrag)
            preY = mouseY;
    }
    
    private function collisionMove(x:Number):void
    {
        if (yFrag)
            collision.collisionMove(x - preX, mouseY - preY);
        else
            collision.collisionMove(x - preX, 0);
    }
    
    private function barMove(x:Number):void
    {
        bar.x = x;
        if (yFrag)
            bar.y = mouseY;
    }
    
    private function drawBar():void
    {
        bar.graphics.beginFill(IniVar.barColor, 1);
        //bar.graphics.drawRect(-IniVar.barWidth / 2, -IniVar.barHeight / 2, IniVar.barWidth, IniVar.barHeight);
        
        bar.graphics.drawRoundRect(-IniVar.barWidth / 2 - rr, -IniVar.barHeight / 2 - rr, IniVar.barWidth + 2 * rr, IniVar.barHeight + 2 * rr, rr, rr);
        
        bar.graphics.endFill();
        bar.x = -100;
        bar.y = IniVar.baseY;
        this.addChild(bar);
    }
}

import flash.display.Sprite;
import flash.events.Event;

class Ball extends Sprite
{
    private var ballX:Number;
    private var ballY:Number;
    private var vx:Number;
    private var vy:Number;
    private var th:Number;
    private var ball:Sprite = new Sprite();
    
    public function Ball(parent:Sprite)
    {
        super();
        parent.addChild(this);
        drawCircle();
        
        this.x = IniVar.xoffset + IniVar.thickness;
        this.y = IniVar.yoffset + IniVar.thickness;
        ballX = (IniVar.fieldWidth - 2 * IniVar.ballR) * Math.random() + IniVar.ballR;
        ballY = IniVar.iniY;
        ball.x = ballX;
        ball.y = ballY;
        th = -(2 / 3 * Math.random() + 1 / 6) * Math.PI;
        vx = IniVar.Vm * Math.cos(th);
        vy = IniVar.Vm * Math.sin(th);
        addEventListener(Event.ENTER_FRAME, onEnterFrame);
        if (IniVar.useBallSpeedUp)
            IniVar.ballSpeedUp = true;
    }
    
    private function onEnterFrame(e:Event):void
    {
        ballX += vx * IniVar.dt;
        ballY += vy * IniVar.dt;
        
        if (Frame.collision.ifCollision(ballX, ballY, vx, vy))
        {
            ballX = Frame.collision.newX;
            ballY = Frame.collision.newY;
            vx = Frame.collision.newVx;
            vy = Frame.collision.newVy;
        }
        
        if (Bar.collision.ifCollision(ballX, ballY, vx, vy))
        {
            ballX = Bar.collision.newX;
            ballY = Bar.collision.newY;
            vx = Bar.collision.newVx;
            vy = Bar.collision.newVy;
        }
        
        if (Blocks.collision.ifCollision(ballX, ballY, vx, vy))
        {
            ballX = Blocks.collision.newX;
            ballY = Blocks.collision.newY;
            vx = Blocks.collision.newVx;
            vy = Blocks.collision.newVy;
        }
        
        //clear judge
        if (Blocks.blocksCollision.length == 0)
            Breakout.stageBreakout.dispatchEvent(new Event("clear"));
        
        if (ball)
        {
            ball.x = ballX;
            ball.y = ballY;
        }
    }
    
    private function drawCircle():void
    {
        ball.graphics.beginFill(IniVar.ballColor, 1);
        ball.graphics.drawCircle(0, 0, IniVar.ballR);
        ball.graphics.endFill();
        ball.x = -IniVar.ballR;
        ball.y = -IniVar.ballR;
        this.addChild(ball);
    }
    
    public function stop():void
    {
        removeEventListener(Event.ENTER_FRAME, onEnterFrame);
    }
    
    public function clear():void
    {
        removeEventListener(Event.ENTER_FRAME, onEnterFrame);
        recurRemoveChild(this);
    }
    
    public function remove(parent:Sprite):void
    {
        parent.removeChild(this);
        recurRemoveChild(this);
        parent = null;
    }
    
    public function removeSprite():void
    {
        ball = null;
    }
    
    private function recurRemoveChild(sp:Sprite):void
    {
        while (sp.numChildren > 0)
        {
            recurRemoveChild(sp.getChildAt(sp.numChildren - 1) as Sprite);
            sp.removeChildAt(sp.numChildren - 1);
        }
        if (sp.hasOwnProperty("removeSprite"))
        {
            sp["removeSprite"]();
        }
        sp = null;
    }
}

import flash.display.Sprite;
import flash.events.*;
import flash.text.*;

class EventDisp
{
    private var mask:Sprite;
    private var textField:TextField;
    private var textField2:TextField;
    
    public function EventDisp(event:String, parent:Sprite)
    {
        mask = new Sprite();
        mask.buttonMode = true;
        parent.addChild(mask);
        switch (event)
        {
            case "miss": 
                missDisp();
                break;
            case "clear": 
                clearDisp();
                break;
        }
    }
    
    private function missDisp():void
    {
        var textFormat:TextFormat = new TextFormat("_sans", 24, 0xcc0033, true);
        textField = new TextField();
        textField.defaultTextFormat = textFormat;
        textField.text = "miss!!";
        textField.selectable = false;
        textField.autoSize = "left";
        textField.x = IniVar.xoffset + int((IniVar.frameWidth - textField.textWidth) / 2);
        textField.y = IniVar.yoffset + int((IniVar.frameHeight - textField.textHeight) / 2) - 30;
        
        var textFormat2:TextFormat = new TextFormat("_sans", 20, 0x000033, true);
        textField2 = new TextField();
        textField2.defaultTextFormat = textFormat2;
        textField2.text = "again";
        textField2.selectable = false;
        textField2.autoSize = "left";
        textField2.x = IniVar.xoffset + int((IniVar.frameWidth - textField2.textWidth) / 2);
        textField2.y = IniVar.yoffset + int((IniVar.frameHeight - textField2.textHeight) / 2) + 20;
        mask.graphics.beginFill(0xFFBF60, 1);
        mask.graphics.drawEllipse(textField2.x - 5, textField2.y, textField2.textWidth * 1.3, textField2.textHeight * 1.3);
        mask.graphics.endFill();
        
        mask.addChild(textField);
        mask.addChild(textField2);
        mask.mouseChildren = false;
        
        mask.addEventListener(MouseEvent.MOUSE_DOWN, dispatchEvent);
    }
    
    private function clearDisp():void
    {
        var textFormat:TextFormat = new TextFormat("_sans", 24, 0xeaa033, true);
        textField = new TextField();
        textField.defaultTextFormat = textFormat;
        textField.text = "Congratulations!";
        textField.selectable = false;
        textField.autoSize = "left";
        textField.x = IniVar.xoffset + int((IniVar.frameWidth - textField.textWidth) / 2);
        textField.y = IniVar.yoffset + int((IniVar.frameHeight - textField.textHeight) / 2) - 20;
        
        var textFormat2:TextFormat = new TextFormat("_sans", 18, 0x000033, true);
        textField2 = new TextField();
        textField2.defaultTextFormat = textFormat2;
        textField2.text = "again";
        textField2.selectable = false;
        textField2.autoSize = "left";
        textField2.x = IniVar.xoffset + int((IniVar.frameWidth - textField2.textWidth) / 2);
        textField2.y = IniVar.yoffset + int((IniVar.frameHeight - textField2.textHeight) / 2) + 30;
        mask.graphics.beginFill(0xFFBF60, 1);
        mask.graphics.drawEllipse(textField2.x - 5, textField2.y, textField2.textWidth * 1.3, textField2.textHeight * 1.3);
        mask.graphics.endFill();
        
        mask.addChild(textField);
        mask.addChild(textField2);
        mask.mouseChildren = false;
        
        mask.addEventListener(MouseEvent.MOUSE_DOWN, dispatchEvent);
    }
    
    private function dispatchEvent(e:Event):void
    {
        textField.removeEventListener(MouseEvent.MOUSE_DOWN, dispatchEvent);
        Breakout.stageBreakout.dispatchEvent(new Event("again"));
    }
    
    public function remove(parent:Sprite):void
    {
        mask.removeChild(textField);
        textField = null;
        parent.removeChild(mask);
        mask = null;
    }
}

import flash.events.Event;

class BreakoutCollision
{
    private var collisionType:String;
    //now x
    private var p1x:Number;
    //now y
    private var p1y:Number;
    private var p2x:Number;
    private var p2y:Number;
    private var r:Number;
    private var th:Number;
    private var thp:Number;
    private var ph:Number;
    private var v_at:Number;
    private var px:Array = new Array(4);
    private var py:Array = new Array(4);
    private var tp:Array = new Array(4);
    private var d:Number;
    private var xa:Array = new Array(2);
    private var ya:Array = new Array(2);
    private var refFlag:Boolean = false;
    private var collisionFlag:Boolean;
    private var recRef:Boolean = false;
    private var cornerRef:Boolean = false;
    private var refFin:Boolean = false;
    
    public static const CIRCLE:String = "circle";
    public static const RECTANGLE:String = "rectangle";
    public static const RECTANGLE_INNER:String = "rectangleInner";
    public static const ROUNDED_RECT:String = "roundedRect";
    public var newX:Number;
    public var newY:Number;
    public var newVx:Number;
    public var newVy:Number;
    
    public function BreakoutCollision(collisionType:String, p1x:Number, p1y:Number, p2x:Number = 0, p2y:Number = 0, radius:Number = 0)
    {
        this.collisionType = collisionType;
        switch (collisionType)
        {
            case CIRCLE: 
                this.p1x = p1x, this.p1y = p1y;
                r = radius;
                break;
            case RECTANGLE: 
                this.p1x = p1x, this.p1y = p1y, this.p2x = p2x, this.p2y = p2y;
                break;
            case RECTANGLE_INNER: 
                this.p1x = p1x, this.p1y = p1y, this.p2x = p2x, this.p2y = p2y;
                break;
            case ROUNDED_RECT: 
                this.p1x = p1x, this.p1y = p1y, this.p2x = p2x, this.p2y = p2y;
                px = [p1x, p1x, p2x, p2x], py = [p1y, p2y, p2y, p1y];
                r = radius;
                break;
        }
    }
    
    public function ifCollision(x:Number, y:Number, vx:Number, vy:Number):Boolean
    {
        switch (collisionType)
        {
            case CIRCLE: 
                return ifCollisionCircle(x, y, vx, vy);
                break;
            case RECTANGLE: 
                return ifCollisionRectangle(x, y, vx, vy);
                break;
            case RECTANGLE_INNER: 
                return ifCollisionRectangleInner(x, y, vx, vy);
                break;
            case ROUNDED_RECT: 
                return ifCollisionRoundedRect(x, y, vx, vy);
                break;
            default: 
                return false;
        }
    }
    
    public function collisionMove(dx:Number, dy:Number):void
    {
        switch (collisionType)
        {
            case CIRCLE: 
                this.p1x += dx, this.p1y += dy;
                break;
            case RECTANGLE: 
                this.p1x += dx, this.p1y += dy, this.p2x += dx, this.p2y += dy;
                break;
            case RECTANGLE_INNER: 
                this.p1x += dx, this.p1y += dy, this.p2x += dx, this.p2y += dy;
                break;
            case ROUNDED_RECT: 
                this.p1x += dx, this.p1y += dy, this.p2x += dx, this.p2y += dy;
                px = [p1x, p1x, p2x, p2x], py = [p1y, p2y, p2y, p1y];
                break;
        }
    }
    
    public function get x():Number
    {
        return p1x;
    }
    
    public function get y():Number
    {
        return p1y;
    }
    
    public function set x(value:Number):void
    {
        switch (collisionType)
        {
            case CIRCLE: 
                p1x = value;
                break;
            case RECTANGLE: 
                d = value - p1x
                p1x = value;
                p2x += d;
                break;
            case RECTANGLE_INNER: 
                d = value - p1x
                p1x = value;
                p2x += d;
                break;
            case ROUNDED_RECT: 
                d = value - p1x
                p1x = value;
                p2x += d;
                px = [p1x, p1x, p2x, p2x];
                break;
        }
    }
    
    public function set y(value:Number):void
    {
        switch (collisionType)
        {
            case CIRCLE: 
                p1y = value;
                break;
            case RECTANGLE: 
                d = value - p1y;
                p1y = value;
                p2y += d;
                break;
            case RECTANGLE_INNER: 
                d = value - p1y;
                p1y = value;
                p2y += d;
                break;
            case ROUNDED_RECT: 
                d = value - p1y;
                p1y = value;
                p2y += d;
                py = [p1y, p2y, p2y, p1y];
                break;
        }
    }
    
    private function ifCollisionCircle(x:Number, y:Number, vx:Number, vy:Number):Boolean
    {
        if (!refFlag && Math.pow((x - p1x), 2) + Math.pow((y - p1y), 2) < r * r)
        {
            v_at = Math.sqrt(vx * vx + vy * vy);
            th = Math.atan2(vy, vx);
            d = Math.pow(p1x + Math.tan(th) * (Math.tan(th) * x - y + p1y), 2) - (Math.tan(th) * Math.tan(th) + 1) * (p1x * p1x + Math.pow(Math.tan(th) * x - y + p1y, 2) - r * r);
            xa[0] = ((p1x + Math.tan(th) * (Math.tan(th) * x - y + p1y)) + Math.sqrt(d)) / (Math.tan(th) * Math.tan(th) + 1)
            ya[0] = Math.tan(th) * (xa[0] - x) + y;
            xa[1] = ((p1x + Math.tan(th) * (Math.tan(th) * x - y + p1y)) - Math.sqrt(d)) / (Math.tan(th) * Math.tan(th) + 1)
            ya[1] = Math.tan(th) * (xa[1] - x) + y;
            if (Math.abs(Math.atan2(y - ya[0], x - xa[0]) - th) < Math.abs(Math.atan2(y - ya[1], x - xa[1]) - th))
                newX = xa[0], newY = ya[0];
            else
                newX = xa[1], newY = ya[1];
            ph = Math.atan2(newY - p1y, newX - p1x);
            thp = 2 * ph - th - Math.PI;
            newVx = v_at * Math.cos(thp);
            newVy = v_at * Math.sin(thp);
            newX = r * Math.cos(ph) + p1x;
            newY = r * Math.sin(ph) + p1y;
            refFlag = true;
        }
        collisionFlag = refFlag;
        refFlag = false;
        recRef = false;
        cornerRef = false;
        refFin = false;
        return collisionFlag;
    }
    
    private function ifCollisionRectangle(x:Number, y:Number, vx:Number, vy:Number):Boolean
    {
        if (!refFlag && (x > p1x && x < p2x && y > p1y && y < p2y))
        {
            //p1x-r,tp[0]
            //tp[1],p1y-r
            //p2x+r,tp[2]
            //tp[3],p2y+r
            //y=Math.tan(th)*(x-x1)+y1
            //x=1/Math.tan(th)*(y-y1)+x1
            th = Math.atan2(vy, vx);
            tp[0] = Math.tan(th) * (p1x - x) + y;
            tp[1] = 1 / Math.tan(th) * (p1y - y) + x;
            tp[2] = Math.tan(th) * (p2x - x) + y;
            tp[3] = 1 / Math.tan(th) * (p2y - y) + x;
            if (Math.abs(Math.atan2(y - tp[0], x - p1x) - th) < Math.abs(Math.atan2(y - tp[2], x - p2x) - th))
                xa[0] = p1x, ya[0] = tp[0];
            else
                xa[0] = p2x, ya[0] = tp[2];
            if (Math.abs(Math.atan2(y - p1y, x - tp[1]) - th) < Math.abs(Math.atan2(y - p2y, x - tp[3]) - th))
                xa[1] = tp[1], ya[1] = p1y;
            else
                xa[1] = tp[3], ya[1] = p2y;
            
            if (Math.pow(xa[0] - x, 2) + Math.pow(ya[0] - y, 2) < Math.pow(xa[1] - x, 2) + Math.pow(ya[1] - y, 2))
                newX = xa[0], newY = ya[0], newVx = -vx, newVy = vy;
            else
                newX = xa[1], newY = ya[1], newVx = vx, newVy = -vy;
            refFlag = true;
        }
        collisionFlag = refFlag;
        refFlag = false;
        return collisionFlag;
    }
    
    private function ifCollisionRectangleInner(x:Number, y:Number, vx:Number, vy:Number):Boolean
    {
        if (!refFlag)
        {
            if (x < p1x)
            {
                th = Math.atan2(vy, vx);
                ya[0] = Math.tan(th) * (p1x - x) + y;
                newX = p1x, newY = ya[0], newVx = -vx, newVy = vy;
                refFlag = true;
            }
            if (x > p2x)
            {
                th = Math.atan2(vy, vx);
                ya[0] = Math.tan(th) * (p2x - x) + y;
                newX = p2x, newY = ya[0], newVx = -vx, newVy = vy;
                refFlag = true;
            }
            if (y < p1y)
            {
                th = Math.atan2(vy, vx);
                xa[0] = 1 / Math.tan(th) * (p1y - y) + x;
                newX = xa[0], newY = p1y, newVx = vx, newVy = -vy;
                refFlag = true;
                if (IniVar.useBallSpeedUp && IniVar.ballSpeedUp)
                {
                    newVx = IniVar.ballSpeedUpRate * Math.sqrt(vx * vx + vy * vy) * Math.cos(Math.atan2(vy, vx));
                    newVy = -IniVar.ballSpeedUpRate * Math.sqrt(vx * vx + vy * vy) * Math.sin(Math.atan2(vy, vx));
                    IniVar.ballSpeedUp = false;
                }
            }
            if (y > p2y)
            {
                th = Math.atan2(vy, vx);
                xa[0] = 1 / Math.tan(th) * (p2y - y) + x;
                newX = xa[0], newY = p2y, newVx = vx, newVy = -vy;
                refFlag = true;
                Breakout.stageBreakout.dispatchEvent(new Event("miss"));
            }
        }
        collisionFlag = refFlag;
        refFlag = false;
        return collisionFlag;
    }
    
    private function ifCollisionRoundedRect(x:Number, y:Number, vx:Number, vy:Number):Boolean
    {
        if (!refFlag && ((x > p1x - r && x < p2x + r && y > p1y && y < p2y) || (x > p1x && x < p2x && y > p1y - r && y < p2y + r)))
        {
            recRef = true;
            refFlag = true;
        }
        for (var i:int = 0; i < 4; i++)
        {
            if (!refFlag && Math.pow((x - px[i]), 2) + Math.pow((y - py[i]), 2) < r * r)
            {
                th = Math.atan2(vy, vx);
                if (i == 0)
                {
                    if (th > 0 && th < Math.PI / 2)
                        cornerRef = true;
                    else
                        recRef = true;
                }
                else if (i == 1)
                {
                    if (th > -Math.PI / 2 && th < 0)
                        cornerRef = true;
                    else
                        recRef = true;
                }
                else if (i == 2)
                {
                    if (th > -Math.PI && th < -Math.PI / 2)
                        cornerRef = true;
                    else
                        recRef = true;
                }
                else if (i == 3)
                {
                    if (th > Math.PI / 2 && th < Math.PI)
                        cornerRef = true;
                    else
                        recRef = true;
                }
                refFlag = true;
            }
        }
        
        if (!refFin && recRef)
        {
            th = Math.atan2(vy, vx);
            tp[0] = Math.tan(th) * (p1x - r - x) + y;
            tp[1] = 1 / Math.tan(th) * (p1y - r - y) + x;
            tp[2] = Math.tan(th) * (p2x + r - x) + y;
            tp[3] = 1 / Math.tan(th) * (p2y + r - y) + x;
            if (Math.abs(Math.atan2(y - tp[0], x - (p1x - r)) - th) < Math.abs(Math.atan2(y - tp[2], x - (p2x + r)) - th))
                xa[0] = p1x - r, ya[0] = tp[0];
            else
                xa[0] = p2x + r, ya[0] = tp[2];
            if (Math.abs(Math.atan2(y - (p1y - r), x - tp[1]) - th) < Math.abs(Math.atan2(y - (p2y + r), x - tp[3]) - th))
                xa[1] = tp[1], ya[1] = p1y - r;
            else
                xa[1] = tp[3], ya[1] = p2y + r;
            
            if (Math.pow(xa[0] - x, 2) + Math.pow(ya[0] - y, 2) < Math.pow(xa[1] - x, 2) + Math.pow(ya[1] - y, 2))
                newX = xa[0], newY = ya[0], newVx = -vx, newVy = vy;
            else
                newX = xa[1], newY = ya[1], newVx = vx, newVy = -vy;
            refFin = true;
        }
        
        for (var j:int = 0; j < 4; j++)
        {
            if (!refFin && cornerRef && Math.pow((x - px[j]), 2) + Math.pow((y - py[j]), 2) < r * r)
            {
                v_at = Math.sqrt(vx * vx + vy * vy);
                th = Math.atan2(vy, vx);
                d = Math.pow(px[j] + Math.tan(th) * (Math.tan(th) * x - y + py[j]), 2) - (Math.tan(th) * Math.tan(th) + 1) * (px[j] * px[j] + Math.pow(Math.tan(th) * x - y + py[j], 2) - r * r);
                xa[0] = ((px[j] + Math.tan(th) * (Math.tan(th) * x - y + py[j])) + Math.sqrt(d)) / (Math.tan(th) * Math.tan(th) + 1)
                ya[0] = Math.tan(th) * (xa[0] - x) + y;
                xa[1] = ((px[j] + Math.tan(th) * (Math.tan(th) * x - y + py[j])) - Math.sqrt(d)) / (Math.tan(th) * Math.tan(th) + 1)
                ya[1] = Math.tan(th) * (xa[1] - x) + y;
                if (Math.abs(Math.atan2(y - ya[0], x - xa[0]) - th) < Math.abs(Math.atan2(y - ya[1], x - xa[1]) - th))
                    newX = xa[0], newY = ya[0];
                else
                    newX = xa[1], newY = ya[1];
                ph = Math.atan2(newY - py[j], newX - px[j]);
                thp = 2 * ph - th - Math.PI;
                newVx = v_at * Math.cos(thp);
                newVy = v_at * Math.sin(thp);
                newX = r * Math.cos(ph) + px[j];
                newY = r * Math.sin(ph) + py[j];
                refFin = true;
            }
        }
        collisionFlag = refFlag;
        refFlag = false;
        recRef = false;
        cornerRef = false;
        refFin = false;
        return collisionFlag;
    }
}

import flash.display.Sprite;
import flash.events.Event;

class BlocksCollision
{
    private var refFlag:Boolean = false;
    private var collisionFlag:Boolean;
    private var parent:Sprite;
    
    public var newX:Number;
    public var newY:Number;
    public var newVx:Number;
    public var newVy:Number;
    
    public function BlocksCollision(parent:Sprite)
    {
        this.parent = parent;
    }
    
    public function ifCollision(x:Number, y:Number, vx:Number, vy:Number):Boolean
    {
        for (var i:int = 0; i < Blocks.blocksCollision.length; i++)
        {
            if (Blocks.blocksCollision[i].ifCollision(x, y, vx, vy))
            {
                newX = Blocks.blocksCollision[i].newX;
                newY = Blocks.blocksCollision[i].newY;
                newVx = Blocks.blocksCollision[i].newVx;
                newVy = Blocks.blocksCollision[i].newVy;
                parent["deleteIndex"](i);
                refFlag = true;
            }
        }
        collisionFlag = refFlag;
        refFlag = false;
        return collisionFlag;
    }
}

class IniVar
{
    //frame property
    public static var frameWidth:int;
    public static var frameHeight:int;
    public static var fieldWidth:int;
    public static var fieldHeight:int;
    public static var xoffset:int = 70;
    public static var yoffset:int = 20;
    public static var thickness:int = 10;
    public static var frameColor:int = 0x6B6B6B;
    public static var frameBgColor:int = 0xF7F7F7;
    public static var frameOutColor:int = 0xBDBDBD;
    //ball property
    public static var ballR:int = 10;
    public static var iniY:int = 360;
    public static var Vm:Number = 10;
    public static var dt:Number = 0.6;
    public static var ballColor:int = 0x040404;
    //bar property
    public static var barWidth:int = 60;
    public static var barHeight:int = 30;
    public static var baseY:int = 407;
    public static var barColor:int = 0x393939;
    //blocks property
    public static var blocksR:int = 13;
    public static var blocksN:int = 80;
    public static var blocksCol:int = 10;
    public static var blocksYspan:int = blocksR * 2;
    
    public static var blocksXoffset:int;
    public static var blocksYoffset:int = blocksR + ballR * 2 + 3;
    public static var blocksColor:int = 0xB3B3B3;
    //game property
    public static var useBallSpeedUp:Boolean = true;
    public static var ballSpeedUp:Boolean = true;
    public static var ballSpeedUpRate:Number = 1.5;
    
    public function IniVar()
    {
    
    }

}