Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * 객체들끼리 서로 밀어내며 자리를 찾아 지속적으로 동일한 간격을 유지하게 하는 프로그램 예제
- * @author 거친마루 <comfuture@_GMAIL_COM_>
- */
- package
- {
- import flash.display.DisplayObject;
- import flash.display.Sprite;
- import flash.events.Event;
- import flash.events.MouseEvent;
- [SWF(width=640, height=480, frameRate=30)]
- public class Main extends Sprite
- {
- private var director:Director;
- public function Main()
- {
- super();
- director = new Director();
- addEventListener(Event.ENTER_FRAME, onEnterFrame);
- // 스테이지 그리기
- graphics.lineStyle(0x0);
- graphics.drawRect(0, 0, 640, 200);
- // 왼쪽 벽
- var left:Wall = new Wall();
- left.x = 0;
- addChild(left);
- // 오른쪽 벽
- var right:Wall = new Wall();
- right.x = 640;
- addChild(right);
- // 공 10개 추가
- for (var i:int = 0; i < 10; i++) {
- addBall();
- }
- // 공 추가 버튼
- var button:Sprite = new Sprite();
- with (button) {
- y = 220;
- graphics.beginFill(0x0000FF);
- graphics.drawRect(0, 0, 60, 25);
- graphics.endFill();
- addEventListener(MouseEvent.CLICK, addBall);
- }
- addChild(button);
- }
- private function addBall(event:MouseEvent=null):void
- {
- var ball:Ball = new Ball();
- ball.x = Math.random() * 640;
- ball.y = 100;
- ball.addEventListener(MouseEvent.CLICK, removeBall);
- addChild(ball);
- }
- private function removeBall(event:MouseEvent):void
- {
- var ball:Ball = event.target as Ball;
- removeChild(ball);
- }
- override public function addChild(child:DisplayObject):DisplayObject
- {
- // 추가하려는 차일드가 Actor면 Director가 관리
- if (child is Actor)
- director.addActor(child as Actor);
- return super.addChild(child);
- }
- override public function removeChild(child:DisplayObject):DisplayObject
- {
- // 제거하려는 차일드가 Actor면 Director로부터도 제거
- if (child is Actor)
- director.removeActor(child as Actor);
- return super.removeChild(child);
- }
- private function onEnterFrame(event:Event):void
- {
- var a:IAlignable;
- var b:IAlignable;
- // NOTE: 차일드의 갯수만큼 반복하여 해당 차일드보다 인덱스가 큰 나머지 차일드와
- // 배척 테스트를 실시한다.
- for (var i:int = 0; i < director.numActors - 1; i++) {
- // XXX: 이 프로그램에선 액터는 IAlignable 밖에 없다고 가정.
- // 실전에선 이런 가정이 버그를 만든다.
- a = director.getActorAt(i) as IAlignable;
- for (var j:int = i + 1; j < director.numActors; j++) {
- b = director.getActorAt(j) as IAlignable;
- a.repulse(b);
- }
- }
- // NOTE: 매 프레임마다 tick을 발생한다. 플래시 플레이어는 머신 성능에 맞추어
- // 프레임레이트를 조절해주므로
- // 복잡한 연산이 필요하지 않은 대부분의 경우 enterframe을
- // tick 대용으로 쓰기에 문제가 없다.
- director.tick();
- }
- }
- }
- import flash.display.Sprite;
- import flash.text.TextField;
- /**
- * 엑터들을 관리하는 감독(매니져) 클래스
- * 틱을 관리하고 틱 마다 액터들에게 onTick 을 실행시키는 역할을 한다.
- */
- internal class Director
- {
- protected var actors:Vector.<Actor>;
- public function Director()
- {
- actors = new Vector.<Actor>();
- }
- /**
- * 관리될 actor를 추가한다.
- * 추가된 actor는 다음 tick 부터 onTick 메소드를 호출당한다.
- * @param actor 액터
- */
- public function addActor(actor:Actor):void
- {
- actors.push(actor);
- }
- /**
- * actors로부터 actor를 제거
- * @param actor 제거할 actor
- */
- public function removeActor(actor:Actor):void
- {
- var found:int = actors.indexOf(actor);
- if (found > -1)
- actors.splice(found, 1);
- }
- public function get numActors():int { return actors.length; }
- /**
- * index 번째 액터를 반환한다.
- * @param index 순번
- * @return index번째 액터
- */
- public function getActorAt(index:int):Actor
- {
- if (index >= 0 && index < numActors) {
- return actors[index];
- }
- throw Error("Index out of range");
- }
- /**
- * 관리당하는 Actors 의 동작을 각각 1턴씩 실행시키는 tick 을 발생한다.
- */
- public function tick():void
- {
- for each (var actor:Actor in actors) {
- actor.onTick();
- }
- }
- }
- /**
- * onTick 함수를 가지고 있는 DisplayObject 원형
- * Director::addActor 메소드로 추가될 수 있다.
- */
- internal class Actor extends Sprite
- {
- public function Actor()
- {
- super();
- }
- /**
- * Actor는 onTick 퍼블릭 메소드를 가지며
- * 매니져클래스가 매 tick마다 이 메소드를 호출해줌으로써
- * 머신의 성능과 관계 없이 동일한 속도의 애니메이션을 구현할 수 있도록 한다.
- * 이 메소드는 반드시 재 구현해야 하므로 override 된 메소드에서
- * super.onTick() 으로 호출하지 않도록 주의한다.
- */
- /* abstract */ public function onTick():void
- {
- throw new Error("Must implement this");
- }
- }
- /**
- * 정렬 가능한 객체의 인터페이스
- */
- internal interface IAlignable
- {
- /**
- * x 좌표를 알 수 있어야 한다.
- */
- function get x():Number;
- /**
- * IAlignable 을 배척할 수 있어야 한다.
- * @param opponent 배척할 상대 정렬가능 객체
- */
- function repulse(opponent:IAlignable):void;
- /**
- * 가속도를 얻을 수 있어야 한다.
- * @param value 얻을 가속도
- */
- function addAccel(value:Number):void;
- }
- /**
- * 공 클래스.
- * 주위 객체들과 가로 방향으로 서로 밀어내며 위치를 찾는다.
- */
- internal class Ball extends Actor implements IAlignable
- {
- private var accel:Number;
- private var factor:Number;
- private var dropMode:Boolean = false;
- public function Ball()
- {
- super();
- accel = 0;
- factor = 10;
- graphics.beginFill(0xFF0000);
- graphics.drawCircle(0, 0, 10);
- graphics.endFill();
- //tf = new TextField();
- //addChild(tf);
- }
- override public function onTick():void
- {
- x += accel;
- accel *= 0.95; // 가속력 5% 씩 자연 감소
- // 벽에 부딛치면 속력 90% 잃고 반대방향으로
- if (x < 0) {
- accel = 0;
- x = 1;
- }
- if (x > 640) {
- accel = 0;
- x = 639;
- }
- }
- public function repulse(opponent:IAlignable):void
- {
- var distance:Number = x - opponent.x;
- if (Math.abs(distance) > 320) return;
- var amp:Number = (1 / distance) * factor;
- // 보정
- if (amp > 10) amp = 10;
- if (amp < -10) amp = -10;
- addAccel(amp);
- opponent.addAccel(-amp);
- }
- public function addAccel(value:Number):void
- {
- accel += value;
- }
- }
- /**
- * 벽 클래스.
- * 공과 마찬가지로 근처 객체들을 배쳑하지만 자기 자신은 밀려나지 않고 자신을 배척하는 객체에
- * 반대방향으로 2배 강한 가속력을 반영한다.
- */
- internal class Wall extends Actor implements IAlignable
- {
- private var factor:Number;
- public function Wall()
- {
- super();
- factor = 20;
- }
- override public function onTick():void {}
- public function repulse(opponent:IAlignable):void
- {
- var distance:Number = x - opponent.x;
- if (Math.abs(distance) > 160) return;
- var amp:Number = (1 / distance) * factor ;
- // 보정
- if (amp > 20) amp = 20;
- if (amp < -20) amp = -20;
- opponent.addAccel(-amp);
- }
- public function addAccel(value:Number):void
- {
- // NOTE: 벽은 가속력을 얻지 않음
- }
- }
Add Comment
Please, Sign In to add comment