Created
December 24, 2010 05:02
-
-
Save comfuture/753913 to your computer and use it in GitHub Desktop.
as3 coding convention and example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 객체들끼리 서로 밀어내며 자리를 찾아 지속적으로 동일한 간격을 유지하게 하는 프로그램 예제 | |
* @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: 벽은 가속력을 얻지 않음 | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment