formation 6
forked from formation 5 (diff: 95)
제어부를 클래스로
ActionScript3 source code
/**
* Copyright codeonwort ( http://wonderfl.net/user/codeonwort )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/z2nE
*/
// forked from codefl's formation 5
// forked from codefl's formation 4
// forked from codefl's formation 3
package {
import flash.display.InteractiveObject
import flash.display.DisplayObjectContainer
import flash.events.EventDispatcher
import flash.display.DisplayObject
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
import com.bit101.components.RadioButton
[SWF(width=500, height=500)]
// 화면을 누르면 누른 지점을 기점으로 대형을 이룬다
// 화면을 더블 클릭하면 흩어진다
// 유닛은 목적지까지 일정 속도로 움직인다
// 왼쪽, 오른쪽 방향키를 누르면 화면을 누를 때 이루는 대형이 바뀐다
// 화면 위의 텍스트 필드에 숫자를 입력하고 엔터를 눌러 유닛 수를 바꾼다
public class FormationWorld extends Sprite {
private var formations:Array = [f0, f1, f2, f3, f4, f5]
private var formationIndex:int = 0
public function get formationFunction():Function { return formations[formationIndex] }
private var formationView:TextField
private var numInput:TextField
private var unitContainer:Sprite
private var formCaller:FormationCaller
public function FormationWorld() {
graphics.beginFill(0x0, 1)
graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight)
graphics.endFill()
unitContainer = addChild(new Sprite)
as Object as EventDispatcher as DisplayObject
as InteractiveObject as DisplayObjectContainer as Sprite
unitContainer.mouseEnabled = false
unitContainer.mouseChildren = false
makeUnits(67) // 인자는 유닛 개수
setMouseAction()
setKeyboardAction()
unitContainer.addEventListener("enterFrame", loop)
// 언제 대형 함수를 호출할 지를 결정한다
formCaller = new FormationCaller(this)
formCaller.runClickMode(stage)
makeFormationCallModeInterface()
}
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++) }
}
// 나선 대형
private function f4(cx:Number, cy:Number):void {
var rest:uint = numUnits()
var t:Number = 0, r:Number = Unit.R * 2
var rInc:Number = Unit.R / 2
for(var i:int = 0 ; i < rest ; i++){
unitAt(i).dest.x = cx + r * Math.cos(t)
unitAt(i).dest.y = cy + r * Math.sin(t)
t += Math.acos((r*r + (r+rInc)*(r+rInc) - Unit.R*Unit.R*4) / (2*r*(r+rInc)))
r += rInc
}
}
// 별 대형
private function f5(cx:Number, cy:Number):void {
var rest:uint = numUnits()
var t:Number = 0, r:Number = Unit.R * 2, space:Number = Unit.R * 2
var numNiddles:uint = 8, tInc:Number = 2*Math.PI / numNiddles
var limit:uint = numNiddles
var c:uint = 0, angle:Number = 30 * Math.PI/180
for(var i:int = 0 ; i <= limit ; i++){
if(i == numNiddles){
rest -= numNiddles
if(rest <= 0) break
else{
i = 0
r += space
t = 0
limit = Math.min(rest, numNiddles)
}
}
unitAt(c).dest.x = cx + r * Math.cos(angle + t)
unitAt(c).dest.y = cy + r * Math.sin(angle + t)
t += tInc
c ++
}
}
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// 볼 필요 없는 부분 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.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() 끝
private function makeFormationCallModeInterface():void {
new RadioButton(this, stage.width-80, 5, "click", true, _setClickMode)
new RadioButton(this, stage.width-80, 20, "timed click", false, _setTimedClickMode)
function _setClickMode():void { formCaller.runClickMode(stage) }
function _setTimedClickMode():void { formCaller.runTimedClickkMode(stage) }
}
}
}
//////////////////////////////////////////////////////
// 패키지 스코프의 바깥
//////////////////////////////////////////////////////
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 {}
}
import flash.display.InteractiveObject
import flash.events.MouseEvent
import flash.events.Event
// manages when to call formation function
// 대형 함수를 호출하는 역할을 맡는다
internal class FormationCaller {
private var world:FormationWorld
private var clk_io:InteractiveObject
private var time_io:InteractiveObject
public function FormationCaller(formationWorld:FormationWorld) {
world = formationWorld
}
public function runClickMode(io:InteractiveObject):void {
clearMode()
io.addEventListener("mouseDown", clickMode_mouseDown)
clk_io = io
}
private function clickMode_mouseDown(e:MouseEvent):void {
if(e.target == clk_io){
world.formationFunction(e.stageX, e.stageY)
}
}
public function runTimedClickkMode(io:InteractiveObject):void {
clearMode()
io.addEventListener("mouseDown", timedClickMode_mouseDown)
time_io = io
}
private function timedClickMode_mouseDown(e:MouseEvent):void {
time_io.addEventListener("mouseMove", timedClickMode_mouseMove)
time_io.stage.addEventListener("mouseUp", timedClickMode_mouseUp)
if(e.target == time_io) world.formationFunction(e.stageX, e.stageY)
}
private function timedClickMode_mouseMove(e:MouseEvent):void {
world.formationFunction(e.stageX, e.stageY)
}
private function timedClickMode_mouseUp(e:MouseEvent):void {
time_io.removeEventListener("mouseMove", timedClickMode_mouseMove)
time_io.stage.removeEventListener("mouseUp", timedClickMode_mouseUp)
}
private function clearMode():void {
if(clk_io){
clk_io.removeEventListener("mouseDown", clickMode_mouseDown)
clk_io = null
}
if(time_io){
time_io.removeEventListener("mouseMove", timedClickMode_mouseMove)
time_io.removeEventListener("mouseMove", timedClickMode_mouseMove)
time_io.stage.removeEventListener("mouseUp", timedClickMode_mouseUp)
time_io = null
}
}
}