In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

formation 4

-- 목적지를 IDestination 인터페이스로 추상화했다
unit.dest = new Location(x0, y0)
unit.dest = new UnitLocation(unit) 아직 안 씀
unit.dest.x, unit.dest.y 처럼 쓰면 된다
-- 쐐기 대형을 추가했다

TODO
-- abstract params of formation functions
     destX, destY -> input:DestInput
-- 충돌 처리 부분을 수신자에서 빼내어 별개의 모듈로 만든다
-- 목적지로 이동하는 부분도 모듈로 빼낸다
Get Adobe Flash player
by codeonwort 13 May 2011
/**
 * Copyright codeonwort ( http://wonderfl.net/user/codeonwort )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/v51P
 */

// forked from codefl's formation 3
package {
    
    import flash.display.Sprite
    import flash.display.MovieClip
    import flash.events.Event
    import flash.events.MouseEvent
    import flash.events.KeyboardEvent
    import flash.ui.Keyboard
    import flash.text.TextField
    
    [SWF(width=400, height=400, backgroundColor=0x000000)]
    
    // 화면을 누르면 누른 지점을 기점으로 대형을 이룬다
    // 화면을 더블 클릭하면 흩어진다
    // 유닛은 목적지까지 일정 속도로 움직인다
    // 왼쪽, 오른쪽 방향키를 누르면 화면을 누를 때 이루는 대형이 바뀐다
    // 화면 위의 텍스트 필드에 숫자를 입력하고 엔터를 눌러 유닛 수를 바꾼다
    
    public class Formation extends Sprite {
        
        private var formations:Array = [f0, f1, f2, f3]
        private var formationIndex:int = 0
        private var formationView:TextField
        
        private var numInput:TextField
        private var unitContainer:Sprite
        
        public function Formation() {
            unitContainer = addChild(new Sprite) as Sprite
            unitContainer.mouseEnabled = false
            unitContainer.mouseChildren = false
            makeUnits(67) // 인자는 유닛 개수
            setMouseAction()
            setKeyboardAction()
            unitContainer.addEventListener("enterFrame", loop)
        }
        
        private function makeUnits(num:uint):void {
            var unit:Unit, x0:Number, y0:Number
            for(var i:int=0 ; i<num ; i++){
                x0 = Math.random() * stage.stageWidth
                y0 = Math.random() * stage.stageHeight
                unit = new Unit(x0, y0)
                unitContainer.addChild(unit)
            }
        }
        
        private function loop(e:Event):void {
            // move units
            var speedX:Number = 5, speedY:Number = 5
            var unit:Unit
            for(var i:int=0 ; i<unitContainer.numChildren ; i++){
                unit = unitAt(i)
                if(unit.x < unit.dest.x){
                    if(unit.dest.x - unit.x > speedX) unit.vx = speedX
                    else unit.vx = unit.dest.x - unit.x
                }
                else if(unit.x > unit.dest.x){
                    if(unit.x - unit.dest.x > speedX) unit.vx = -speedX
                    else unit.vx = unit.dest.x - unit.x
                }
                if(unit.y < unit.dest.y){
                    if(unit.dest.y - unit.y > speedY) unit.vy = speedY
                    else unit.vy = unit.dest.y - unit.y
                }
                else if(unit.y > unit.dest.y){
                    if(unit.y - unit.dest.y > speedY) unit.vy = -speedY
                    else unit.vy = unit.dest.y - unit.y
                }
                if(Math.abs(unit.x-unit.dest.x)<0.05) unit.vx = 0
                if(Math.abs(unit.y-unit.dest.y)<0.05) unit.vy = 0
                unit.x += unit.vx
                unit.y += unit.vy
            }
        }

        
        // setFormation 시리즈 /////////////////////////////////////////////////////
        // 직사각형 대형
        private function f0(destX:Number, destY:Number):void {
            var numUnits:uint = numUnits()
            var numColumns:int = Math.sqrt(numUnits)
            var numRows:int = numUnits / numColumns
            var numMods:int = numUnits - numColumns*numRows
            var spaceX:Number = Unit.R * 2
            var spaceY:Number = Unit.R * 2
            var LT_x:Number = destX - numRows*spaceX/2
            var LT_y:Number = destY - numColumns*spaceY/2
            
            var unit:Unit, count:int=0
            for(var column:int=0 ; column<numColumns ; column++){
                for(var row:int=0 ; row<numRows ; row++){
                    unit = unitAt(count)
                    unit.dest.x = LT_x + row*spaceX
                    unit.dest.y = LT_y + column*spaceY
                    count ++
                }
            }
            if(count < numUnits){
                var numRest:uint = numUnits - numRows*numColumns
                for(var i:int=0 ; i<numRest ; i++){
                    unit = unitAt(count)
                    unit.dest.x = LT_x + i*spaceX
                    unit.dest.y = LT_y + numColumns*spaceY
                    count ++
                }
            }
        }
        
        // 원 대형
        private function f1(destX:Number, destY:Number):void {
            var numUnits:uint = numUnits()
            var radius:Number = Math.min(200, numUnits*2)
            var unit:Unit
            for(var i:int=0 ; i<numUnits ; i++){
                  unit = unitAt(i)
                  unit.dest.x = destX + radius * Math.cos(2*Math.PI*i/unitContainer.numChildren)
                  unit.dest.y = destY + radius * Math.sin(2*Math.PI*i/unitContainer.numChildren)
            }
        }
        
        // 다층 원 대형
        private function f2(destX:Number, destY:Number):void {
            var rest:int = numUnits()
            var need:int = Math.min(3, rest)
            var count:int = 0
            var radius:Number = Unit.R * 2
            var unit:Unit
            while(true){
                for(var i:int=0 ; i<need ; i++){
                    unit = unitAt(count)
                    unit.dest.x = destX + radius * Math.cos(2*Math.PI*i/need)
                    unit.dest.y = destY + radius * Math.sin(2*Math.PI*i/need)
                    count ++
                }
                rest -= need
                if(rest <= 0) break
                need = Math.min(rest, need+5)
                radius += Unit.R * 3
            }
        }
        
        // 쐐기 대형
        private function f3(cx:Number, cy:Number):void {
            var rest:uint = numUnits()
            var num:uint = 1, num_inc:uint = 8
            var rowSpace:Number = Unit.R * 6
            var spaceX:Number = Unit.R * 2.5
            var spaceY:Number = Unit.R * 2
            var rowCount:uint = 0
            var x0:Number
            while(true){
                rest -= num
                x0 = cx - rowSpace * rowCount
                
                var i:int, unit:Unit, half:uint
                if(num & 1){
                    // odd
                    unit = nextUnit()
                    unit.dest.x = x0
                    unit.dest.y = cy
                    half = (num - 1) / 2
                    for(i = 1 ; i <= half ; i++){
                        unit = nextUnit()
                        unit.dest.x = x0 + spaceX*i
                        unit.dest.y = cy - spaceY*i
                    }
                    for(i = 1; i <= half ; i++){
                        unit = nextUnit()
                        unit.dest.x = x0 + spaceX*i
                        unit.dest.y = cy + spaceY*i
                    }
                }else{
                    // even
                    half = num / 2
                    for(i = 1 ; i <= half ; i++){
                        unit = nextUnit()
                        unit.dest.x = x0 + spaceX*i
                        unit.dest.y = cy - spaceY*i
                    }
                    for(i = 1 ; i <= half ; i++){
                        unit = nextUnit()
                        unit.dest.x = x0 + spaceX*i
                        unit.dest.y = cy + spaceY*i 
                    }
                }
                
                if(rest <= 0) break
                num += num_inc
                rowCount ++
            }
            var next:uint = 0
            function nextUnit():Unit {
                return unitAt(next++)
            }
        }


        ///////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////
        // 볼 필요 없는 부분 no need to see
        private function unitAt(idx:int):Unit {
            return unitContainer.getChildAt(idx) as Unit
        }
        private function numUnits():uint {
            return unitContainer.numChildren
        }

        private function setMouseAction():void {
            stage.addEventListener("mouseDown", setDestination)
            function setDestination(e:MouseEvent):void {
                if(e.target == stage) formations[formationIndex](e.stageX, e.stageY)
            }
            
            stage.doubleClickEnabled = true
            stage.addEventListener("doubleClick", scatterUnits)
            function scatterUnits(e:Event):void {
                var unit:Unit
                for(var i:int=0 ; i<unitContainer.numChildren ; i++){
                    unit = unitAt(i)
                    unit.dest.x = Math.random() * stage.stageWidth
                    unit.dest.y = Math.random() * stage.stageHeight
                }
            }
        }
        
        private function setKeyboardAction():void {
            formationView = addChild(new TextField()) as TextField
            formationView.autoSize = "left"
            formationView.selectable = false
            formationView.textColor = 0xffffff
            formationView.text = "formation : 0"
            formationView.mouseEnabled = false
            stage.addEventListener("keyDown", changeFormation)
            function changeFormation(e:KeyboardEvent):void {
                switch(e.keyCode){
                    case Keyboard.LEFT :
                        formationIndex --
                        if(formationIndex == -1) formationIndex = formations.length - 1
                        break
                    case Keyboard.RIGHT :
                        formationIndex ++
                        if(formationIndex == formations.length) formationIndex = 0
                        break
                }
                formationView.text = "formation : " + formationIndex
            }
            
            var cap:TextField = addChild(new TextField()) as TextField
            cap.selectable = false
            cap.autoSize = "left"
            cap.y = 20
            cap.textColor = 0xffffff
            cap.mouseEnabled = false
            cap.text = "write number of units and enter"
            
            numInput = addChild(new TextField) as TextField
            numInput.text = "67"
            numInput.type = "input"
            numInput.autoSize = "left"
            numInput.background = true
            numInput.backgroundColor = 0xffff00
            numInput.textColor = 0x000000
            numInput.x = 160
            numInput.y = 20
            numInput.restrict = "0-9"
            numInput.addEventListener("keyDown", changeNumUnits)
            function changeNumUnits(e:KeyboardEvent):void {
                if(e.keyCode == Keyboard.ENTER){
                    for(;unitContainer.numChildren;) unitContainer.removeChildAt(0)
                    makeUnits(int(numInput.text))
                }
            }
        } // setKeyboardAction() 끝
        
    }
    
}

//////////////////////////////////////////////////////
// 패키지 스코프의 바깥
//////////////////////////////////////////////////////
import flash.display.Shape
internal class Unit extends Shape {
    public static const R:int = 5
    public var dest:IDestination
    public var vx:Number=0, vy:Number=0
    public function Unit(x0:Number, y0:Number){
        x = x0 ; y = y0
        dest = new Location(x0, y0)
        graphics.beginFill(0xff0000, 1)
        graphics.drawCircle(0, 0, R)
        graphics.endFill()
    }
}

internal interface IDestination {
    function get x():Number
    function set x(val:Number):void
    function get y():Number
    function set y(val:Number):void
}
internal class Location implements IDestination {
    private var _x:Number, _y:Number
    public function Location(x0:Number, y0:Number) {
        _x = x0 ; _y = y0
    }
    public function get x():Number { return _x }
    public function set x(val:Number):void { _x = val }
    public function get y():Number { return _y }
    public function set y(val:Number):void { _y = val }
}
internal class UnitLocation implements IDestination {
    private var _u:Unit
    public function UnitLocation(u:Unit) {
        _u = u
    }
    public function get x():Number { return _u.x }
    public function get y():Number { return _u.y }
    public function set x(val:Number):void {}
    public function set y(val:Number):void {}
}