Guest User

Untitled

a guest
Jul 18th, 2018
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.20 KB | None | 0 0
  1. /**
  2. * 객체들끼리 서로 밀어내며 자리를 찾아 지속적으로 동일한 간격을 유지하게 하는 프로그램 예제
  3. * @author 거친마루 <comfuture@_GMAIL_COM_>
  4. */
  5.  
  6. package
  7. {
  8. import flash.display.DisplayObject;
  9. import flash.display.Sprite;
  10. import flash.events.Event;
  11. import flash.events.MouseEvent;
  12.  
  13. [SWF(width=640, height=480, frameRate=30)]
  14. public class Main extends Sprite
  15. {
  16. private var director:Director;
  17.  
  18. public function Main()
  19. {
  20. super();
  21.  
  22. director = new Director();
  23. addEventListener(Event.ENTER_FRAME, onEnterFrame);
  24.  
  25. // 스테이지 그리기
  26. graphics.lineStyle(0x0);
  27. graphics.drawRect(0, 0, 640, 200);
  28.  
  29. // 왼쪽 벽
  30. var left:Wall = new Wall();
  31. left.x = 0;
  32. addChild(left);
  33.  
  34. // 오른쪽 벽
  35. var right:Wall = new Wall();
  36. right.x = 640;
  37. addChild(right);
  38.  
  39. // 공 10개 추가
  40. for (var i:int = 0; i < 10; i++) {
  41. addBall();
  42. }
  43.  
  44. // 공 추가 버튼
  45. var button:Sprite = new Sprite();
  46. with (button) {
  47. y = 220;
  48. graphics.beginFill(0x0000FF);
  49. graphics.drawRect(0, 0, 60, 25);
  50. graphics.endFill();
  51. addEventListener(MouseEvent.CLICK, addBall);
  52. }
  53. addChild(button);
  54. }
  55.  
  56. private function addBall(event:MouseEvent=null):void
  57. {
  58. var ball:Ball = new Ball();
  59. ball.x = Math.random() * 640;
  60. ball.y = 100;
  61. ball.addEventListener(MouseEvent.CLICK, removeBall);
  62. addChild(ball);
  63. }
  64.  
  65. private function removeBall(event:MouseEvent):void
  66. {
  67. var ball:Ball = event.target as Ball;
  68. removeChild(ball);
  69. }
  70.  
  71. override public function addChild(child:DisplayObject):DisplayObject
  72. {
  73. // 추가하려는 차일드가 Actor면 Director가 관리
  74. if (child is Actor)
  75. director.addActor(child as Actor);
  76.  
  77. return super.addChild(child);
  78. }
  79.  
  80. override public function removeChild(child:DisplayObject):DisplayObject
  81. {
  82. // 제거하려는 차일드가 Actor면 Director로부터도 제거
  83. if (child is Actor)
  84. director.removeActor(child as Actor);
  85. return super.removeChild(child);
  86. }
  87.  
  88. private function onEnterFrame(event:Event):void
  89. {
  90. var a:IAlignable;
  91. var b:IAlignable;
  92.  
  93. // NOTE: 차일드의 갯수만큼 반복하여 해당 차일드보다 인덱스가 큰 나머지 차일드와
  94. // 배척 테스트를 실시한다.
  95. for (var i:int = 0; i < director.numActors - 1; i++) {
  96. // XXX: 이 프로그램에선 액터는 IAlignable 밖에 없다고 가정.
  97. // 실전에선 이런 가정이 버그를 만든다.
  98. a = director.getActorAt(i) as IAlignable;
  99. for (var j:int = i + 1; j < director.numActors; j++) {
  100. b = director.getActorAt(j) as IAlignable;
  101. a.repulse(b);
  102. }
  103. }
  104.  
  105. // NOTE: 매 프레임마다 tick을 발생한다. 플래시 플레이어는 머신 성능에 맞추어
  106. // 프레임레이트를 조절해주므로
  107. // 복잡한 연산이 필요하지 않은 대부분의 경우 enterframe을
  108. // tick 대용으로 쓰기에 문제가 없다.
  109. director.tick();
  110. }
  111. }
  112. }
  113.  
  114. import flash.display.Sprite;
  115. import flash.text.TextField;
  116.  
  117. /**
  118. * 엑터들을 관리하는 감독(매니져) 클래스
  119. * 틱을 관리하고 틱 마다 액터들에게 onTick 을 실행시키는 역할을 한다.
  120. */
  121. internal class Director
  122. {
  123. protected var actors:Vector.<Actor>;
  124.  
  125. public function Director()
  126. {
  127. actors = new Vector.<Actor>();
  128. }
  129.  
  130. /**
  131. * 관리될 actor를 추가한다.
  132. * 추가된 actor는 다음 tick 부터 onTick 메소드를 호출당한다.
  133. * @param actor 액터
  134. */
  135. public function addActor(actor:Actor):void
  136. {
  137. actors.push(actor);
  138. }
  139.  
  140. /**
  141. * actors로부터 actor를 제거
  142. * @param actor 제거할 actor
  143. */
  144. public function removeActor(actor:Actor):void
  145. {
  146. var found:int = actors.indexOf(actor);
  147. if (found > -1)
  148. actors.splice(found, 1);
  149. }
  150.  
  151. public function get numActors():int { return actors.length; }
  152.  
  153. /**
  154. * index 번째 액터를 반환한다.
  155. * @param index 순번
  156. * @return index번째 액터
  157. */
  158. public function getActorAt(index:int):Actor
  159. {
  160. if (index >= 0 && index < numActors) {
  161. return actors[index];
  162. }
  163. throw Error("Index out of range");
  164. }
  165.  
  166. /**
  167. * 관리당하는 Actors 의 동작을 각각 1턴씩 실행시키는 tick 을 발생한다.
  168. */
  169. public function tick():void
  170. {
  171. for each (var actor:Actor in actors) {
  172. actor.onTick();
  173. }
  174. }
  175. }
  176.  
  177. /**
  178. * onTick 함수를 가지고 있는 DisplayObject 원형
  179. * Director::addActor 메소드로 추가될 수 있다.
  180. */
  181. internal class Actor extends Sprite
  182. {
  183. public function Actor()
  184. {
  185. super();
  186. }
  187.  
  188. /**
  189. * Actor는 onTick 퍼블릭 메소드를 가지며
  190. * 매니져클래스가 매 tick마다 이 메소드를 호출해줌으로써
  191. * 머신의 성능과 관계 없이 동일한 속도의 애니메이션을 구현할 수 있도록 한다.
  192. * 이 메소드는 반드시 재 구현해야 하므로 override 된 메소드에서
  193. * super.onTick() 으로 호출하지 않도록 주의한다.
  194. */
  195. /* abstract */ public function onTick():void
  196. {
  197. throw new Error("Must implement this");
  198. }
  199. }
  200.  
  201. /**
  202. * 정렬 가능한 객체의 인터페이스
  203. */
  204. internal interface IAlignable
  205. {
  206. /**
  207. * x 좌표를 알 수 있어야 한다.
  208. */
  209. function get x():Number;
  210.  
  211. /**
  212. * IAlignable 을 배척할 수 있어야 한다.
  213. * @param opponent 배척할 상대 정렬가능 객체
  214. */
  215. function repulse(opponent:IAlignable):void;
  216.  
  217. /**
  218. * 가속도를 얻을 수 있어야 한다.
  219. * @param value 얻을 가속도
  220. */
  221. function addAccel(value:Number):void;
  222. }
  223.  
  224. /**
  225. * 공 클래스.
  226. * 주위 객체들과 가로 방향으로 서로 밀어내며 위치를 찾는다.
  227. */
  228. internal class Ball extends Actor implements IAlignable
  229. {
  230. private var accel:Number;
  231. private var factor:Number;
  232. private var dropMode:Boolean = false;
  233.  
  234. public function Ball()
  235. {
  236. super();
  237. accel = 0;
  238. factor = 10;
  239.  
  240. graphics.beginFill(0xFF0000);
  241. graphics.drawCircle(0, 0, 10);
  242. graphics.endFill();
  243.  
  244. //tf = new TextField();
  245. //addChild(tf);
  246. }
  247.  
  248. override public function onTick():void
  249. {
  250. x += accel;
  251. accel *= 0.95; // 가속력 5% 씩 자연 감소
  252.  
  253. // 벽에 부딛치면 속력 90% 잃고 반대방향으로
  254. if (x < 0) {
  255. accel = 0;
  256. x = 1;
  257. }
  258. if (x > 640) {
  259. accel = 0;
  260. x = 639;
  261. }
  262. }
  263.  
  264. public function repulse(opponent:IAlignable):void
  265. {
  266. var distance:Number = x - opponent.x;
  267. if (Math.abs(distance) > 320) return;
  268. var amp:Number = (1 / distance) * factor;
  269.  
  270. // 보정
  271. if (amp > 10) amp = 10;
  272. if (amp < -10) amp = -10;
  273. addAccel(amp);
  274. opponent.addAccel(-amp);
  275. }
  276.  
  277. public function addAccel(value:Number):void
  278. {
  279. accel += value;
  280. }
  281. }
  282.  
  283. /**
  284. * 벽 클래스.
  285. * 공과 마찬가지로 근처 객체들을 배쳑하지만 자기 자신은 밀려나지 않고 자신을 배척하는 객체에
  286. * 반대방향으로 2배 강한 가속력을 반영한다.
  287. */
  288. internal class Wall extends Actor implements IAlignable
  289. {
  290. private var factor:Number;
  291.  
  292. public function Wall()
  293. {
  294. super();
  295. factor = 20;
  296. }
  297.  
  298. override public function onTick():void {}
  299.  
  300. public function repulse(opponent:IAlignable):void
  301. {
  302. var distance:Number = x - opponent.x;
  303. if (Math.abs(distance) > 160) return;
  304. var amp:Number = (1 / distance) * factor ;
  305.  
  306. // 보정
  307. if (amp > 20) amp = 20;
  308. if (amp < -20) amp = -20;
  309.  
  310. opponent.addAccel(-amp);
  311. }
  312.  
  313. public function addAccel(value:Number):void
  314. {
  315. // NOTE: 벽은 가속력을 얻지 않음
  316. }
  317. }
Add Comment
Please, Sign In to add comment