2009년 6월 18일 Tweener의 개발종료를 선언하다.

Programming/ActionScript 3.0 2009. 8. 20. 00:15

본인이 ActionScript 3.0을 처음 접할 때 사막의 오아시스처럼 큰 도움을 주었던 Tweener 라이브러리가 최종 버전을 끝으로 개발을 종료한다고 한다. 현재 본인은 TweenLite, TweenMax를 사용하고 있지만 ActionScript 3.0을 재미있게 공부하고, 연구할 수 있도록 나에게 동기를 준 멋진 라이브러리가 아닌가 생각한다.

MC Tween 시절부터 플래시의 발전 속에서 역사가 깊은 라이브러리이기에 여러 가지 생각이 머리 속에서 스쳐 지나간다. Zeh Fernando씨에게 박수를 보낸다. 아래는 원문을 번역한 내용이다. 명확히 알 수 없는 내용은 포함하지 않았으며 일부 문장은 나름대로 재 해석한 관계로 내용 전달이 정확하지 않을 수도 있지만 전체적인 요점은 파악할 수 있을 것이라 생각한다.


========================================================================================
원문 : Zeh Fernando Blog Archive Tweener, 4 years later - A post mortem

우선 시작부터 이야기 하자면 나는 몇 년 전에 Flash 개발 과정에서 애니메이션이 필요하여 MC Tween를 개발했다. MC Tween는 ActionScript의 기본적인 tween을 확장하여 사용했다. 당시에 뛰어난 tween 확장 기능이 존재하고 있었지만 모두 나의 취향과 맞지 않았다. API의 대부분이 너무 추상적이었고 내가 요구하는 것과 달랐기 때문에 prototype 형식을 채용하여 MovieClip의 오브젝트형에 새로운 기능을 추가해서 만들었다. MovieClip에 새로운 기능을 추가하는 형태에 찬사를 주는 사람들이 있었기 때문에 그만한 인기를 얻을 수 있었다.

그러나 2005년 해가 되면서 MC Tween의 변화가 필요하게 되었다. MC Tween은 의도대로 움직이고 있었지만 ActionScript의 문법이나 패러다임(특히 AS2의 등장)이 변화하고 객체지향프로그래밍을 이해하기 시작하면서 MC Tween은 이미 나의 개발 워크플로우에 맞지 않는다는 것을 깨닫게 되었다. 더욱이 MC Tween의 개발이 꽤 정체되어 있었다.

그러던 그 해 6월부터 나는 클래스를 사용하여 새롭게 tween 확장 기능을 실험적으로 개발하기로 했다. 개발 당초에는 인스턴스 베이스(tween 인스턴스를 생성)였지만 이후에 addTween() 이라는 하나의 메소드에 의해서 모든 tween을 생성하는 정적인 클래스 구조로 변경했다. 그리고 stopTween(), getTween()과 같은 부속 메소드를 사용하여 여러 가지 기능을 조작할 수 있도록 했다.

이후에도 클래스는 매우 많은 변경이 있었다. 클래스명이 바뀌거나(초기에는 Twina였던 것이 Tweener가 되고 ZTweener가 되었다가 다시 Tweener로 되돌아옴)  패키지의 위치가 바뀌거나(generic *에서 zeh.easing.*으로, 그리고 다시 caurina.transitions.*)  API가 변경되거나 인스턴스 베이스에서 정적 클래스로 변경한 것은 말할 것도 없고 그 외에도 내부 구조의 변경 등이 많이 있었다. 이러한 과정에서 스스로가 많이 배웠다는 것이 이 글의 취지이지만 자신을 위해서 무엇인가를 만드는 경우, 결과를 누군가가 보고 평가하거나 더욱이 그것을 누군가가 매우 소중한 일에 사용하지 않을 것이라고 생각하고 만든다면 결과적으로 많은 실수를 허용하게 된다. 그러나 그 과정에서 보다 좋은 방법을 찾아내게 되는 것이다.

내가 이 프로젝트를 시작했을 무렵, tween 확장 기능으로서 제일 유명했던 것은 Fuse Kit이였다. 나는 이것과 겨룬다는 생각은 없었다. 다만 나 자신을 위해서 무엇인가를 만들고 자신의 요구에 맞게 변경해 나가는 자유를 즐기고 있었다. Tweener는 긴 시간동안 비공개(나 자신만 사용) 였던 것이 그러한 이유다. 무엇보다 Gringo를 위한 프로젝트를 위해서 사용하고 있었지만 공개된 것은 2007년 1월 최초의 버전을 개발하고 나서 대략 2년 후였다. Nate Chatellier가 팀에 참가하여 AS3버전의 Tweener를 만들었었기에 이대로 비공개로 하는 것은 공정하지 않다고 생각했다. 더욱이 그 시점에서 생각하기에 앞으로 API에는 큰 변화가 있을 것 같지 않았기 때문에 다른 사람들로부터 피드백을 받고 싶은 생각도 있었다.

Tweener는 특별히 참신한 것도 아니고 API는 새로운 것이 없었다. Tweener가 채용한 새로운 tween생성 방식도 다른 tween의 확장에서도 채용되고 있었다. AS1 베이스 확장에서도 채용되고 있었다. 그렇지만 그것은 그 시기에 올바른 구문이었다. 그러한 형태는 인기가 있었고 다른 언어판까지 나오게 되었다.

이는 4년전의 이야기.(로그를 보면 Tweener은 2005년 6월 15일에 개발 개시한 것으로 되어 있다.) 현재는 이 밖에도 많은 tween 확장판이 등장하고 있고, 특히 유명한 것은 Go, TweenLite / TweenMax, GTween, BetweenAS3 등이 있다. 라고 하는 것은? 그래, 또 그 때가 찾아왔다고 하는 것이다. 현재와 같이 AS3버전이 있다고 해도 Tweener가 가지는 패러다임의 대부분은 이미 시대에 뒤떨어져 버렸다. 나는 점점 불안을 느끼게 되었다. 나는 그동안 많은 것을 배웠다. 이제 움직이기 시작할 때다.

바로 움직이기 시작할 수도 있었지만, 그 전에 되돌아보고, 잘 된 것, 가지 않았던 것을 되짚어 보려고 했다. 이 글은 말하자면 Tweener의 사망선고 글, 4년간 내가 무엇을 배웠고, Tweener와 같은 라이브러리가 어떻게 변화해 왔는가 하는 점에 대한 나름의 분석이다.

그런데 AS2에서 AS3로 이동하는 시점에 고려해야 할 중요한 포인트가 한 개 있다. ‘에러’다. AS2 에러는 null 오브젝트의 프로퍼티를 변경하는 스크립트를 실행해도 FlashPlayer는 그대로 지나쳐 버린다. 물론 오브젝트가 존재하지 않기 때문에 스크립트 자체는 기능하지 않지만 그것을 알려주는 에러 메시지가 없다.

이것은 엄밀한 동작이 기대되는 경우에는 문제가 된다. 취득한 데이터가 의도한 것인지를 알기 위해서는 몇 개의 레벨의 검증이 필요하고, 그렇게 해서 다른 방법으로 유저에게 경고를 보낼 수 있었다. Tweener의 AS2 버전에서는 유저에게 보다 안전하게 동작할 수 있도록 노력했다. 구체적으로는 tween 중에 대상이 되는 오브젝트가 존재하는지를 체크하고, tween 되고 있는 프로퍼티에 디폴트의 값이 설정되어 있는지를 체크하고 있다.

하지만 AS3 버전으로 만들면서 그 기능은 필요 없게 되었다. 존재하지 않는 오브젝트나 프로퍼티에 액세스 하려고 하면 코드의 실행은 중단되게 되었다. 이것은 좋은 일이다. 유저가 자신이 무엇인가 실수를 범하고 있고, 그것을 수정하지 않으면 안 된다고 하는 것을 이해하는데 도움이 되기 때문이다.

한편, AS3 버전으로 임포트하는 시점에 Tweener는 이러한 AS2의 패러다임을 계승해 버렸다. 조금 전에 쓴 것과 같이 체크 기능도 많이 남아 있다. 또한 존재하지 않는 프롭퍼티의 값을 tween하려고 하면 FlashPlayer의 에러가 아닌, Tweener 내에서 설정한 커스텀 에러를 표시하게 되어 있다.

if (rScopes[0][istr] == undefined) {
     printError("The property '" + istr + "' doesn't seem to be a normal object property of " + String(rScopes[0]) + " or a registered special property.");
}

속성을 업데이트하기 위한 반복 루프에서도 마찬가지다. 업데이트하는 개체가 있는지 확인하고, 속성이 존재하는지 확인하고 있다. 이 방식으로 인하여 성능이 저하되고, 크기가 증가라는 부작용도 제기됐다.

새로운 tween을 적용할 때, Tweener는 비슷한 tween (동일한 개체의 동일한 속성에 적용하는 tween)이 있는지를 찾아 그들을 제거하려고 한다. 별도로 애니메이션을 하기 위해 요구되는 행동이지만, 이로 인해서 2개의 문제가 발생한다. 먼저 tween 덮어쓰기를 강제로 실행하면서 옵션은 없다는 것, 그리고 새 tween을 생성할 때 성능을 크게 저하 시킨다는 것, 이미 많은 tween이 동일한 위치에 있는 경우에는 더욱 그러하다.

최근 tween 엔진 성능을 비교해보면 문제는 더 명백해 진다. 실제 tween 갱신에 소요되는 시간과 메모리 소비 등은 나쁘지 않지만, 생성 tween 양이 늘어나면 늘어날수록 Tweener 처리는 느려진다. 새로운 tween이 생성될 때마다 기존의 모든 tween과 충돌을 체크하기 때문에 tween 생성에 소요되는 시간이 증가하는 것이다. tween 수가 1000을 초과한 상태에서 새 tween을 생성하려고 하면, 애니메이션 자체의 소요 시간을 초과하거나 FlashPlayer가 잠깐 멈추는 경우도 종종 있다. Tweener는 tween 목록을 단지 하나의 배열에 관리하고 있기 때문이다. 더 유용한 AS3 기본 기술을 이용하여 위 사항은 해결할 수 있는지도 모른다. 어쨌든 Tweener은 너무 안전하게 작동하려고 한다. 사용자가 성능을 향상시키고 싶은 처리를 허용하지 않는다.

오늘 Tweener에 대해 언급하는 것은 더 이상 최적화 문제가 아니라고 생각하기 때문이다. 보완할 수는 있다. 몇 가지 검사하는 기능을 제거, 또는 Array 대신 Dictionary와 같은 AS3의 새로운 기능을 추가하여 목록을 관리하거나, Vector 기능을 추가하거나 할 수 있다. 하지만 솔직히 말해서 Tweener는 그 전성기가 끝났다고 나는 확신한다. 그렇기 때문에 그러한 변경을 해도 곧바로 모든 것이 단순히 해소될 수 없다. 그러니 더 이상 Tweener을 업데이트 하는 것은 무의미하다. 물론(특히 동시에 1000개 이상 같은 tween을 수행할 필요가 없는 경우) 현재도 작동하고, 앞으로도 계속 도움이 될 것이다.

숨어 있던 새로운 버그가 나타나지 않는다면 Tweener를 업데이트할 생각이 없지만 최근에 있었던 이슈들을 업데이트했다. 새로운 버전의 1.33.74 Google Code 프로젝트 페이지 subversion 서버에 공개된다. 이 업데이트는 기본 tween 덮어쓰기 내용은 남겨두면서 overwrite라는 새로운 매개 변수를 추가하고 (이 값을 true로 하면 그 동안의 기능과 같다.) autoOverwrite는 새로운 정적 속성을 추가했다.

Tweener Comparison

위 그림에서 파란색 그래프는 tween없는 상태를, 오렌지 그래프는 Tweener 1.31.74를, 노란색 그래프는 Tweener 1.33.74에서 overwriting을 false로 설정한 상황을 보여주고 있다.

대단한 일이 아닐지라도, 이것은 이 프로젝트에 참여했던 몇 년간 내가 받은 지원, 조언, 배움, 그리고 훌륭한 경험에 대한 감사의 표시로 받아들여 주길 바란다. 프로젝트를 직접 지원해 준 회원 뿐 아니라, 이 프로젝트를 다양한 측면에서 지원해 준 모든 분들에게 진심으로 감사한 마음이다.

내가 Tweener의 개발을 Google Code 사이트로 옮긴 후부터 집계해온 재미있는 그래프를 보여 주겠다. 이것은 버전별 안정 버전 Tweener 다운로드 비율(전체 다운로드 회수)을 비교한 것이다. AS3가 차지하는 비중이 늘고 있다는 것을 알 수 있다. 덧붙여서,

Tweener download statistics

오늘 출시 버전은 포함하지 않았다.

Tweener download statistics

후기로 여러분에게 전달하고자 하는 것이 있다. 나는 현재 tween에 있어서 개인적으로는 Tweener에 의해 소개된 것과 다른 접근을 사용하고 있다. 내 자신의 워크플로우는 조금 바뀌었다. 색 트윈 및 기타 특별한 지름길은 사용하지 않는다. 대신 독립적인 클래스와 getter / setter 및 decorator 등을 통한 특정 기능을 사용하게 되었다. 내가 Tweener를 개발한 이유는, 자신의 개발 흐름에 맞게 무언가를 적용하고, 수요가 있으면 다른 사람들이 사용할 수 있도록 하는 즐거움에 있었다. Tweener를 공개하는 데 많은 시간을 할애한 것은 그 때문이다. 나는 현재, 모든 사람의 요구에 부응하기 위해 만들어진 것을 사용하기보다는, 특정한 누구를 위해 만들어진 것을 사용하는 것을 선호한다.

분명한 것은, "Tweener2"나 그런 것은 나오지 않는다는 것이다.
다시 한번 감사합니다!

========================================================================================

세상의 모든 것들은 시간의 흐름에 따라 변화하고, 소멸하고, 다시 새로운 것이 탄생하기를 반복한다. 플래시의 경우도 예외가 아니다. 플래시는 1년이 멀다 하고 새로운 API와, 흥미로운 기능들이 추가되며 발전해 왔다. 하지만 그 화려한 변신에 가려진 개발자들의 눈물겨운 노력은 일반 사람들에게는 잘 알려지지 않는다. 더욱이 플래시라는 분야를 재미없는, 해야만 하는 일로 생각하는 개발자라면 그 정도는 더욱 심했을 것이다.

Zeh Fernando씨가 Tweener의 사망선고하는 글을 올리기까지 얼마나 많은 노력과 시간을 투자했을지, 그리고 스스로에게 의미가 있는 프로젝트를 종료하기까지 많은 고민과 생각을 했으리라. 다시 한번 멋진 프로젝트를 진행했던 Zeh Fernando씨에게 박수를 보낸다.

어쩌면 Zeh Fernando씨가 우리에게 도움을 준 것 보다 Tweener를 의미 있는 작업에 활용하며 피드백을 주었던 수 많은 사람들로부터 받은 관심이 Zeh Fernando씨가 불특정 다수에게 감사를 표하는 가장 큰 이유일 것이다. Tweener는 종료되었지만 앞으로도 더욱 다양한 작품으로 만날 것을 기대해 본다.

    

설정

트랙백

댓글

  • 지돌스타 2009.08.20 09:34 ADDR 수정/삭제 답글

    짝짝짝!!!!

  • 검쉰 2009.08.20 13:12 신고 ADDR 수정/삭제 답글

    짝짝짝!!!!

  • 제이디 2009.08.24 02:42 ADDR 수정/삭제 답글

    한편의 드라마를 본듯한 느낌입니다.
    그리고, 자수님께 감사합니다. 해석 않해주셨으면,
    '뭐야? 끝난거야?' 하고 넘어갔을 법한 일이 될뻔 했네요..

    • jasu 2009.08.31 02:33 신고 수정/삭제

      개발자가 본인의 작업물을 공유하고자 하는 의도와 그것을 보는 다른 개발자들의 니즈가 충족하는 것은 개발자의 중요한 가치가 아닐까요. 한국은 외국보다 그러한 가치가 충족되지 않는 듯하여 조금은 아쉬움이 있습니다. 하지만 예전보다는 많이 나아졌다고 봅니다. ^^

  • Doworld 2009.08.24 14:08 ADDR 수정/삭제 답글

    짝짝짝!!!!

  • lovedev 2009.09.04 01:07 신고 ADDR 수정/삭제 답글

    짝짝짝 해줘야 하는 분위기네 ^^ 멋져~!!

  • 리노아 2009.09.08 15:02 ADDR 수정/삭제 답글

    가끔 이런걸 해석해 놓은걸 보면 감성적이기도 하고,
    볼링 한판? ㅋㅋㅋ

정보의 가시화 그리고 플래시 개발자의 역할

Programming/ActionScript 3.0 2009. 5. 31. 08:12


정보의 가시화.
컴퓨터가 발달하지 않았던 시대에는 그래프의 탄생이 정보의 가시화에 혁명처럼 다가왔던 시대가 있었다. 그로부터 몇 백 년이 지난 지금은 어떠할까, 컴퓨터가 발달하고 인터넷이 빠르게 발전하면서 대량의 정보, 그 자체를 분석하고 처리하는 능력은 그때와는 비교도 할 수 없을 정도로 발전했지만 아직까지도 정보를 효과적이고 완벽하게 가시화 할 수 있는 방법은 존재하지 않는 것 같다. 가면 갈수록 컴퓨터의 정보처리 능력과 더불어 인문학이 주요 이슈로 떠오르고 있는 이유도 여기에 있는 것이 아닐까.

데이터는 데이터 자체로 의미를 지닐 수는 없다. 데이터는 인간이 이해할 수 있는 것으로부터 그 가치를 가지게 된다, 그렇다면 데이터를 인간이 이해하기 편하게 표현하려면 어떻게 해야 할까.

정보 가시화에 필요한 기본적인 시각 요소들은 사이즈, 색채, 관련성, 좌표 등이 있다. 흑백 인쇄와 같이 제한적인 환경이 아닌 인터넷에서는 이러한 기본적인 시각 요소들을 다양하게 사용할 수 있다. 더욱이 모든 이용자의 접근성을 위한 대체 컨텐츠를 제공 해야 하는 부담을 줄이기 위해서는 앞에서 열거한 모든 요소들을 적절히 활용하는 것이 필요하다.



또한 인터넷 매체로 넘어오면서 정보를 단순히 가시화해서 보여주는 것에 머무르지 않고 사용자와 시스템간에 상호 의사소통을 함으로써 인간이 데이터를 이해하는데 보다 많은 도움을 주고 있다. 그러한 관점에서 본다면 플래시는 이러한 시대를 제대로 만났다고 할 수 있다. 플래시는 발전을 거듭하면서 데이터 분석과 처리를 효율적으로 수행하고 있으며 플래시만의 특화된 디자인적인 요소를 충분히 활용함으로써 다양한 시각화를 표현 할 수 있게 되었다. 물론 좋은 펜을 가지고 있다고 하여 글을 잘 쓰는 것은 아니겠지만 정보를 효과적으로 가시화할 수 있는 발판을 마련했다는 점에서 의미가 있다고 하겠다.

플래시는 앞으로도 많은 발전을 거듭하겠지만 그 동안은 도구 자체로써 발전을 했다면 이제는 그 도구를 최대한 활용하여 효과적이고 최적화된 콘텐츠를 생산하는 인력을 키우는데 노력 해야 할 것이다. 앞에서 언급한 것처럼 정보는 정보 자체로 그 의미를 지닐 수 없듯이 말이다.

플래시 개발자의 역할.
위에서 말한 효과적인 컨텐츠를 생산하기 위해서는 플래시 개발자에게는 다양한 역량을 요구하게 된다. 플래시 기술을 보유한 엔지니어를 넘어 정보를 어떻게 가공하여 가시화 할 것인가에 대한 근본적인 문제를 효과적으로 구상할 수 있는 기획력, 그리고 그러한 표현을 현실화 할 수 있는 디자인 능력이 요구된다. 물론 요즘은 전문적인 역량을 요구하게 되면서 각 분야의 기술력이 높아졌지만 그러한 업무 분담 시스템으로 인해 결과적으로는 컨텐츠의 퀄리티가 매끄럽지 않은 경우가 많이 발생한다.

이런 문제점을 보완하기 위해서는 플래시 개발자뿐만 아니라 모든 작업자는 수동적인 작업자가 되어서는 안 된다고 생각한다. 각 분야의 전문가들의 의견을 최대한 수렴하고 존중하되, 기획, 디자인, 플래시 기술을 떠나서 최종 사용자의 입장에서 문제점을 지적하고 더 나은 결과물을 얻기 위해 노력해야 한다. 따라서 끊임없이 각 분야의 전문가들과 커뮤니케이션을 해야 하는 것이다.

사실 본인 또한 다른 작업자들을 설득하는 것에 많은 부담을 갖는 것이 사실이다. 하지만 주관적인 자신의 생각이 아닌, 사용자의 입장에서 충분히 생각하고 제시하는 객관적인 설득은 다른 작업자들도 충분히 공감을 할 수 있을 것이라고 믿는다.

플래시라는 기술은 업무의 특정이 완벽하게 구분되는 분야가 아니다. 구조적인 부분에서는 기획, 비주얼 부분에서는 디자인, 기술적인 부분에서는 프로그래밍을 항상 고민해야 하는 특성이 있다. 따라서 플래시 개발자의 역할은 모든 작업자들에게 보다 많은 커뮤니케이션을 유도하는 윤활유 역할을 수행할 필요가 있다.

각 분야의 전문가들은 자신이 바라보는 관점에서 욕심을 내기 마련이다. 하지만 그 욕심이 해당 프로젝트가 나아갈 방향에 부합하지 않거나, 사용자의 사용 패턴을 충분히 고려하지 않은 욕심이라면 다시 생각해볼 필요가 있다. 보통 일선에서는 이러한 역할을 기획에서 하는 경우가 많지만 기획자의 역량에도 한계가 있기 때문에 무조건 기획자에게 책임을 전가해서는 안 된다고 생각 한다.

사실 본인도 그러한 역할을 조금이나마 수행하기 위해서 노력은 하고 있지만 커뮤니케이션 스킬이 많이 부족하다 보니 어려움이 많은 것이 사실이다. 하지만 이러한 노력조차 하지 않는다면 해당 프로젝트는 철학이 없는 이벤트로 끝날 가능성이 크다고 생각한다.

따라서 플래시 개발자는 모든 작업자의 편의를 위해 개발하기 보다는 최종 결과물을 받아들이는 사용자 입장을 항상 고민하고, 그것이 완벽하게 옳다고 스스로 판단되지 않을 경우에는 프로젝트의 완성도를 위한 커뮤니케이션을 회피해서는 안될 것이다.

물론 현실적으로 어려움이 있는 것은 사실이다. 프로젝트의 일정상 어려움도 있을 것이고 커뮤니케이션 과정에서 다른 작업자의 영역을 침범한다고 좋지 않게 바라볼 수도 있다. 하지만 자신이 옳다고 판단하는 것에 대해 다양한 의견을 들어보는 것만으로도 프로젝트 뿐만이 아니라 모든 작업자들에게 도움이 될 것이라고 생각한다.


 

    

설정

트랙백

댓글

  • 지돌스타 2009.06.01 13:04 ADDR 수정/삭제 답글

    글에 전적으로 동감하는 바입니다.
    제가 Flex이긴 하지만 디자인적인 성향은 거의 배제되어 있어 글의 모든 부분을 수용하기 힘들지만 능동적이고 커뮤니케이션에 적극적이어야하는데는 꼭 Flash/Flex/AIR 개발자가 가져야할 필수 덕목이라는 데는 의심할 여지가 없을 것 같습니다.

    저는 회사에서 팀장으로 일하고 있는데.... 개발자이면서 팀장은 정말 힘든 보직같습니다.
    개발자끼리 커뮤니케이션은 어느정도 되는데... 팀장으로서 사장님과의 커뮤니케이션은 기술적 문제를 배제하고 말해야하고 또 설득해야하기 때문에 언변 능력이 부족한 저로서는 매우 힘들더군요. 하지만 이 상황을 개인발전을 위한 긍정적인 요소로 판단하고 적극적으로 좋은 방향으로 바라보면서 행동하는 것이 무엇보다 중요할 것 같다는 생각이 듭니다.

    • jasu 2009.06.02 20:29 신고 수정/삭제

      프로젝트에 도움이 되는 일이라면 해 보는게 좋다는 취지의 내용입니다. ^^ 저도 가끔 느끼는 것이지만 이해가 있는 대상에게 설명하고 설득하는 것 보다 이해가 없는 대상에게 설명하기가 무척 어렵더군요 그것도 하나의 능력이 아닐까 싶어요 ^^; 저도 그런 능력이 워낙 없다보니 스스로 답답해할 때가 간혹 있습니다. ^^

  • 리플래시 2009.06.04 08:58 ADDR 수정/삭제 답글

    참 좋은 글이네요.
    프로젝트를 하면 많은 의견과 많의 제시와 검토인거 같습니다
    플래시 개발자만이 가장 플래시 결과물을 낼수 있는건 아닌거 같아요
    생각지도 못한 것을 기획자와 디자이너분들이 말해 줄수도 있으니까요
    패쇄적인거보다는 공객적이고 적극적인 개발자가 되야 할것 같아요

    • jasu 2009.06.06 01:08 신고 수정/삭제

      말씀 감사합니다. 흔히 각 분야의 전문가들은 그들만의 성향이 있다는 이야기를 많이 합니다. 기획, 개발, 디자인에 따라 서로 다른 성향을 가지고 있다고 하죠. 어찌보면 이런 성향의 한 구석에는 보유하고 있는 기술력과 본인의 업무 처리 프로세스에서 벗어나지 못하는 생각에서 발생하는 경우가 적지 않은 것 같습니다. 아이디어 자체는 특정 분야를 떠나서 서로 다른 환경에서 생각하는 다양한 시각이 필요한 공통분모가 아닐까 싶습니다. 오히려 자신의 기술력 안에서 생각하는 사람보다 밖에서 생각하는 것이 더 자유로울 수도 있다는 생각입니다. ^^ 물론 작업자 입장에서는 업무량이 늘어날 수도 있지만 그런 것이 자신을 능력을 키우는 힘이 되는 것이 아닐까 싶기도 합니다.

  • 오창훈 2009.06.05 21:34 ADDR 수정/삭제 답글

    생각이 어쩌면 이렇게 비슷할수있을까요
    동감백배

    • jasu 2009.06.06 01:11 신고 수정/삭제

      감사합니다. 그러시다면 제 생각이 바른 생각일 확률이 높아지겠군요 ^^ 다른 분들도 비슷한 생각은 하고 있을 것 같습니다. 그것을 실천하는 것과 하지 못하는 차이겠지요 저도 노력중입니다.

  • GEEKTOO 2009.06.06 09:06 ADDR 수정/삭제 답글

    사실 이부분은, 2000년대 초반부터 부각되었고, 세계적 flash 경진대회 등에서 이미,
    수상한 경력이 있는 아이디어 들입니다. 몇년전 부터는 mash up 이라고 해서, 정보를 다양한 형태로 변형하고 발전시키는 Design 방법이 물위로 떠오르고 있죠.

    참조가 많은 글의 랭킹을 색상으로 표현한다거나, Impact를 주거나, 혹은 물리적인 방법을 이용해서
    해당 참조글의 느낌을 사용자에게 전달해 주거나 말이죠.

    앞으로는.

    인간의 5감 + 1감 을 더하여, 더 다양한 방법으로 전개 될 것입니다.
    Performance가 받쳐 준다면. 아주다양해질 방법으로, SOUND가 있겠죠.

    1~3년 안으로.

    2가지 인터페이스 시장이 발달 될겁니다.
    이미 기존에 존재하는 기술의 확장이죠.

    음성인식 / 멀티터치의 일반화,보급화 입니다.

    1. 음성인식

    이미, 존재하는 기술 입니다. 이 기술이 WEB과 합쳐지면, 전혀 다른 세상이 됩니다
    마치.
    Irom man 의 Jarbis 같은 음성인식 인터페이스가 될거겠죠

    "야! 파이어폭스! 오늘 메일중, 내친구들에게 온 메일부터 읽어줘. 난 간식을 먹어야겠어"

    2. 멀티터치

    이미, 완벽히 구현되었고, 발전되고있죠.

    멀티터치 PAD는. $50 정도의 가격으로 보급화가 되면, 스크린 인터페이스 시장이 발달 될겁니다.
    이미, IPOD, HAPTIC 같은 상품들이 적용 되었지요.

    이 장치와 기술이 보급이 되면, 사용자의 인터페이스가 좀더 발달이 되겠죠.


    음성과 멀티터치 그리고 DATA의 결합은. 인간의 생각의 범위를 좀더 넓혀줄것입니다.

    이상 GEEKTOO 입니다.

    • jasu 2009.06.08 03:21 신고 수정/삭제

      위 포스트의 내용은 디바이스의 기술적인 부분 보다는 인간의 감성적인 개발 접근 방법에 대한 고찰 정도로 이해 하시면 좋을 것 같습니다. ^^ 아무리 기술이 발달해도 그것을 개발하는 것은 인간인 만큼 기술발전에 의지하기 보다는 사용자의 입장을 좀더 헤아릴 필요가 있다는 정도로 이해하시면 좋을 것 같습니다. ^^ 앞으로의 기술발전은 저도 사뭇 궁금합니다. 말씀하신 것처럼 그 방향성은 어느 정도 잡은 것으로 보이지만 기술 발전과 습관과 관습에 묶여 있는 인간의 사고방식이 얼마나 많은 시간을 요구할 것인가는 또 다른 문제가 아닐까요…

  • lovedev 2009.06.08 11:31 신고 ADDR 수정/삭제 답글

    근데 참... 위의 플래시는 소셜냄새가 가득히 나네요 ^^

    • jasu 2009.06.08 23:02 신고 수정/삭제

      쿠쿠 그냥 라인 모션가지고 끄적거리다가 사이트맵 데이터 가지고 만들어 본 거에요. 포스트 내용과는 별로 관련이 없는데 글만 있으면 재미없을 듯하여 올려놓은 거랍니다. ^^

  • jin_u 2009.06.09 13:46 ADDR 수정/삭제 답글

    이성을 어떻게 컨트롤 할 것인가...
    감성을 어떻게 노출 시켜야 할 것인가...
    타인을 어떻게 이해 시킬 것인가...
    여성을 어떻게 꼬셔 볼 것인가...
    킥킥~

    • jasu 2009.06.09 20:33 신고 수정/삭제

      쿠쿠 비도 오는데 좀 쉬어라 많이 피곤해 보인다

  • mahabanya 2009.08.11 03:28 ADDR 수정/삭제 답글

    가끔 BBC에서 정보의 가시화 관련된 영상을 보면 ㅎㄷㄷ한데
    상상력이 현실이 되는 시대에 살고 있네요. 우리는.

    • jasu 2009.08.12 16:30 신고 수정/삭제

      생각하는 기술과 상상하는 기술의 차이가 많이 접혀진 시대에 살 고 있는 것은 사실인 것 같네요 다만 우리가 생활속에서 인지하지 못할 뿐인것 같습니다. ^^

[AS3] 좋은 코드를 작성하기 위한 길

Programming/ActionScript 3.0 2008. 12. 27. 11:30
플래시는 에니메이션 저작툴이라는 디자인적인 탄생 배경을 탈피하고 많은 프로그래머들이 매력을 느끼는 컴퓨터 프로그래밍 언어로 발전하였다. 나는 어린 시절 장래 희망을 물어보면 컴퓨터 프로그래머라고 이야기하던 시절이 있었다.(그때는 5.25인치 디스크 한 장에 게임 하나가 들어가던 시절이었는데 아마도 게임을 하면서 스토리를 내 마음대로 바꾸고 싶었던 것 같다.)

하지만 그런 꿈은 삶의 역경 속에서 잊혀지고 나아가 컴퓨터 프로그래머라는 직업이 돈이 되는 직업은 아니라는 것을 알았을 무렵에는 이내 나의 꿈은 컴퓨터 프로그래머가 아니었다고 부정하였다. 결국 부정하던 장래희망의 굴레에 나를 몰아넣은 것은 플래시라고 할 수 있다. 내가 플래시를 처음 접했을 때는 이런 형태로 발전할지는 꿈에도 몰랐었으니 고로 나는 플래시에게 사기를 당한 것이다. ^^


나는 배우는 과정에 서있다. 항상 플래시의 발전을 따라가느라 정신 없이 허우적거리는 생활을 반복하고 있으니 아마도 내가 플래시라는 툴에서 손을 놓을 때까지 이러한 배움의 길은 끝이 없을 듯싶다.

배우는 과정에서 느꼈던 좋은 코드를 작성하는 방법에 대하여 이야기 해 볼까 한다. 본 내용은 일본 잡지에 실린 연재 코너의 내용을 ActionScript 버전으로 본인의 생각을 덧붙여 작성한 것임을 밝혀둔다.

좋은 코드란?
좋은 코드는 조직이나 프로젝트, 프로젝트 메니저에 따라서 그 정의가 다르게 해석될 수 있다. 하지만 보편적으로 좋은 코드로서 바람직한 방향은 있다.

정확하게 동작하는 것.
정확한 결과값을 도출하는 것은 신뢰할 수 있는 코드다.

빠르고 효율적으로 동작 하는 것.
결과 값을 도출하는 방법은 여러 가지가 있을 수 있다. 좋은 코드는 적절한 퍼포먼스로 동작한다.

방어적으로 버그를 생산하지 않는 것.
방어적 프로그래밍 방법론에 기초하여 정상적인 값이 들어 올 것이라고 가정하지 않고 부정확한 값이 와도 문제가 발생하지 않도록 방어적으로 코드를 작성한다. 이것은 처음에 열거한 정확하게 동작하는 것을 도와준다.

유지보수를 하기 쉬운 것.
프로젝트는 단기간에 수명을 다할 수도 있지만 우리가 상상하는 것보다도 길게 생명을 유지하는 것도 많다. 유지보수성을 높이는 것도 좋은 코드에 있어서 중요하다.

다른 사람이 봐도 이해하기 쉬운 것.
현재 작성한 코드를 미래에 자신이 보는 것과 현재 타인이 보는 것은 비슷하다고 볼 수 있다. 미래에 자신이 봐도 이해할 수 있는 코드는 좋은 코드라 할 수 있다.

쓸데없는 부분이 없는 것.
쓸데없는 코드를 작성하는 개발자는 없을 것이다. 다만 코드의 구현과정에서 기능 추가 및 다른 로직과의 연동 과정에서 불필요하게 파생하는 코드들은 지양할 필요가 있다.


좋은 코드를 작성하면 무엇이 좋은가?
좋은 코드는 프로젝트를 추진하고 성공적으로 이끌기 위한 기본적인 요소가 된다. 프로그래밍의 달인들은 심플하고, 유지보수성이 좋고 안정적인 코드를 빠른 속도로 작성한다. 테스트가 어려운 코드를 테스트가 가능하고 검증할 수 있는 코드로 변경함으로써 품질이나 생산성을 수백 배 높이기도 한다. 이것은 프로젝트의 성공에 있어서 큰 요소이다. 물론, 좋은 코드가 있으면 반드시 프로젝트가 성공하는 것은 아니다. 개발 프로세스나 메니지먼트, 커뮤니케이션등으로 좌우되는 경우가 더 많지만 이런 것들을 제외한다면 개발에 있어서 좋은 코드의 힘은 크다고 볼 수 있다.

프로그래머로서의 평가가 높아진다.
좋은 코드를 작성하는 프로그래머는 대체적으로 프로그래머로서 신뢰한다. 프로그래머로서의 평가가 조직으로서의 실제 평가나 이익에 결합될지는 소속하는 조직의 평가 제도나 프로그램 이외의 일도 포함하여 정해지는 것이 현실이다. 그렇다고 좋은 코드를 쓸 수 있는 것이 마이너스 평가로 이어지지는 않을 것이다.

일에 대한 만족감이나 자신감을 가질 수 있다.
두 번 다시 손대고 싶지 않은, 유지보수가 불가능한 코드를 써본 적이 있을 것이다. 이러한 낮은 퀄리티의 일을 해 놓으면 일에 대한 만족감을 얻을 수 없다. 반면 자신의 의지로 적절히 좋은 코드를 작성함으로써 품질이 높고 안정된 소프트웨어를 개발했을 때는 그에 대한 만족감도 높고 자신감을 갖고 일에 임할 수 있다. 앞으로 오랜 시간을 프로그래머로써 살아갈 것이라고 생각한다면 좋은 코드를 쓸 수 있는 레벨을 목표로 하는 것은 합리적인 일이다.

사실 좋은 코드를 작성하기 위해서는 하루아침에 이룰 수 없다. 그렇다면 좋은 코드를 작성하기 위해 구체적으로 무엇을 어떻게 해야 하는지를 살펴보자.

코드 리딩 - 읽어라, 코드를 읽고, 읽고, 또 읽어라.
음악이나 회화, 건축의 세계에서도 자신만의 발상으로 작품을 완성시키는 예술가는 없다. 다른 사람들의 작품을 보고 영향을 받거나 좋은 곳을 훔치거나 해서 자신의 작품을 만드는 것으로 작품을 낳아 왔다.

프로그래밍도 같다. 좋은 코드를 작성 하려면 좋은 코드이건 나쁜 코드이건 간에 다른 사람이 작성한 코드를 평소에 의식하고 읽는 것이 중요하다. 플래시는 특히 많은 오픈 소스가 인터넷에 열려 있기 때문에 다른 사람이 작성한 좋은 코드를 언제라도 부담 없이 읽을 수 있다. ActionScript 중급 정도의 실력자이지만 구조를 어떻게 만들어야 하는지 막막한 분은 특히 주목할 필요가 있다. 이런 단계에 머물러 있는 분이라면 코드리딩을 통해서 한 단계 발전한 자신을 발견할 수 있을 것이다.

코드리딩의 좋은 점은 알아도 코드를 읽는 방법을 모른다면 시작하기 힘든 일이다. 아래의 간단한 코드를 보면서 이야기 해보자.

package classes.data{

    import flash.events.Event;
    import classes.data.*;
    import classes.net.SimpleXMLLoader;
   
    public class DProvider extends SimpleXMLLoader{ // [1] 여기부터
           
        private var _xmlUrl:String;   
        private var _keywords:Array;
       
        public function DProvider(inUrl:String):void { // [2] 여기부터
            _xmlUrl = inUrl;
            addEventListener(Event.COMPLETE, onLoadedXmlHandler);
            loadXML(_xmlUrl);
        }    // [2] 여기까지

        private function onLoadedXmlHandler(e:Event):void { // [3] 여기부터
            var xml:XML = XML(data);
            _keywords = [];
           
            var len:int = xml.item.length();
            for (var i:int = 0; i < len; i++)
            {
                // [4] 여기부터
                _keywords.push(createKeyword(xml.item[i]));
            }
        }    // [3] 여기까지
       
        private function createKeyword(inKeywordNode:XML):KeywordBase
        {
            var keyword:KeywordBase;
            switch(int(inKeywordNode.level)) {
                case 1: keyword = new Keyword1(inKeywordNode);
                break;
                case 2: keyword = new Keyword2(inKeywordNode);
                break;
                case 3: keyword = new Keyword3(inKeywordNode);
                break;
                case 4: keyword = new Keyword4(inKeywordNode);
                break;
            }
            return keyword;
        } // [4] 여기까지
       
        public function get keywords():Array { return _keywords.concat(); } // [5]
    } // [1] 여기까지
}

위 클래스는 본인이 실무에서 작업했던 태그클라우드에서 사용했던 코드이다. 클래스의 기능은 xml데이터를 불러들여 level 노드 값에 따라서 해당 클래스들을 배열로 생성하여 제공한다.

위 클래스 외적으로 사용된 클래스는 다음과 같은 기능을 포함한다.
SimpleXMLLoader : 단순히 xml 데이터를 불러오는 기능을 한다. loadXML 메소드가 포함되어 있다.
KeywordBase : 키워드 무비클립의 기본이 되는 기능을 제공한다. (마우스 다운, 오버, 아웃등)
Keyword1 ~ Keyword4 : KeywordBase 를 상속하는 각 레벨에 따라 디자인이 서로 다른 클래스들

코드리딩을 할 때는 기본적으로 nest 단위로 읽어 내려가면 된다. 중간에 나타나는 다른 클래스들은 현재 블록을 전체적으로 훑어 보면서 유추하도록 하자. 중간에 다른 파일을 열어 읽게 되면 현재 읽고 있는 흐름을 놓칠 수 있기 때문이다.

50줄도 안 되는 코드지만 이 코드만 가지고도 작업된 클래스들의 절반 이상은 이해할 수 있다. 복잡한 기능을 하는 클래스는 아니기 때문에 읽으면서 구조적으로 어떻게 작성이 되었는지 알 수 있을 것이라 믿는다. 이런 훈련을 반복 하다 보면 현재 읽고 있는 클래스 이외의 다른 클래스들도 머리 속으로 그리는 과정을 얻게 된다. 이를 통해서 하나를 보면 열을 알게 되는 경지에 다다를 수 있을 것이다. ^^

구글에서 코드 검색엔진을 통해서 웹에 있는 원시 코드들을 검색할 수 있는 서비스를 제공하고 있다. 자신이 원하는 기능의 클래스명이나 메소드명으로 검색해서 코드리딩 연습을 하는 것도 좋은 방법이다. 또한 많이 알려진 클래스나 패키지들은 구조적으로 잘 설계된 것들이 많이 있다. 구조적인 관점에서는 그런 것들을 분석해 보는 것도 큰 도움이 된다.

http://www.google.com/codesearch
인터넷상에 공개되어있는 Subversion(repository)나 archive파일 등을 기계적으로 빠르게 검색 할 수 있다.

좋은 이름을 붙이자.
우리가 프로그래밍을 하고 있을 때 가장 막히는 부분은 변수명, 메소드명, 클래스명 이름을 붙이는 것이다. 그만큼 좋은 이름을 붙이는 것은 중요하다. 좋은 이름을 붙이는 것이 중요한 이유는 위에서 언급했던 코드리딩에서도 느낄 수 있듯이 관련 기능에 부합하는 좋은 이름을 붙이지 않으면 코드를 읽기가 어려워진다.(생각해보니 위에서 예로 든 코드에서도 어려움을 느낀 분들이 있을 것 같다 ^^;)

그렇다면 좋은 이름의 조건이 있을 법하다.

좋은 변수명, 메소드명, 클래스명은 이름이 그 코드의 내용을 올바르게 나타내고 있다. 그러한 이름은 이름을 보는 것만으로도 코멘트를 읽을 필요도 없이 그 역할을 이해할 수 있다. 좋은 이름은 코드의 이해를 돕지만 나쁜 이름은 읽는 사람을 혼란 시키고 착각을 낳아 버그 발생을 조장한다.

위 코드를 예로 들면 onLoadedXmlHandler 메소드 명을 onComplete로 했을 경우에 어떤 것이 Complete 되었다는 것인지 인지하기 어렵다. 위 클래스의 경우는 단순한 클래스이지만 클래스의 내용이 많고 complete 핸들러 함수를 여러 개 포함하고 있을 경우에는 메소드의 중복이 발생할 수도 있다.

public function get keywords():Array { return _keywords.concat(); }
의 경우에는 keyword에 복수를 뜻하는 s를 붙임으로써 전달 받는 keyword가 하나가 아니라 복수이며 배열이라는 것을 유추할 수 있다. 이 밖에도 아래와 같은 방법이 있다.

어두 이외의 모음을 삭제 (image ->img)
강한 소리를 남긴다. (server -> svr)
약어의 이용 (database -> db)

일관성이 있다.
좋은 이름은 코드 전체에서 일관된 흐름을 가져야 한다.

대칭성을 유지하는 것
begin <-> end
write <-> read
on <-> off

단어의 조합의 일관성
scoreAvg
scoreAverage
avgScore
위 이름은 하나의 클래스에서 중복 사용하지 않을 것.

관용어에 따라서
언어, 프로젝트, 회사나 팀 마다 명명에 관한 관용어(관습)가 있다. 예를 들면 Java의 경우는 메소드명은 소문자로 시작하는 것이 관습이며, C#은 대문자, C++은 멤버 변수에 prefix로 m_를 붙이는 것이 일반적이다. 관용어에 따른 명명은 누가 보더라도 알기 쉬운 이름이라고 이야기 할 수 있다.(ActionScript의 경우는 보통 자바와 언어적 문법이 비슷하기 때문에 자바와 같은 명명 관용어를 사용하는 경우가 많지만 개인적인 취향에 따라 다르게 사용하는 경우가 대부분이다.)

코딩 표준에 따라서
위와 같이 좋은 코드의 조건을 채우기 위해서도 코딩 표준이나 명명 규약을 정해 팀 멤버 전원이 맞추는 것이 중요하다. 작업자 1명이 단기적으로 작업하는 프로젝트에서는 본인이 원하는 규칙을 사용하면 되겠으나 조직의 힘을 바탕으로 얻을 수 있는 큰 프로젝트의 경우는 협업의 중요성이 대두되므로 이러한 코딩 표준을 맞추는 것이 장기적으로는 바람직하다고 볼 수 있다.

좋은 이름을 붙이기 위한 습관
항상 좋은 이름을 붙이는 것을 의식한다.
좋은 이름을 붙이려면 우선 의식적으로 노력을 해야 한다. 이것은 A라는 이름이 좋은가? 아니면 B라는 이름이 좋은가를 항상 신중하게 검토해 보고 적절한 이름을 결정하는 프로세스를 반복할 필요가 있다.

코드의 리딩이나 리뷰
자신이 모르는 완전히 새로운 이름을 만드는 것은 코드를 분별없게 만들 가능성이 크다. 본인이 작성한 코드를 스스로 리딩해 보거나 다른 사람에게 리뷰를 함으로써 사용할 수 있는 이름을 조금씩 늘려간다. (본인 같은 경우는 아는 단어의 수준이 메롱이기 때문에 코드작업을 할 때 항상 사전을 열어놓고 작업을 하는 습관이 있다. 이때도 주의할 것은 일회성으로 모르는 단어를 만들어 명명하는 것 보다는 그 단어를 충분히 숙지한 상태에서 이름으로 사용하는 것이 바람직하다 – 간혹 내가 만든 이름을 내가 이해하지 못하는 어처구니 없는 경우가 발생 하기도 한다. 메롱;;)

좋은 변수명
설명적인 변수명
변수에는 값이나 오브젝트가 대입된다. 변수명을 보는 것만으로도 무엇이 어떠한 역할을 하는지 명확한 것이 좋은 이름이라 할 수 있다.

예를 들어
var n:int;                                                 // 무슨 수치?
var languages:Array = [“kr”, “en”];     // 무슨 언어?
var flg:Boolean = false;                      // 무슨 플래그?
var userAgent:UserAgent                  // 무슨 유저 에이전트?

위와 같은 변수명은 나중에 되돌아보면 변수의 역할을 알 수 없다. 아래와 같이 좀더 구체적이고 명확한 이름으로 해 두면 되돌아 보거나 다른 사람이 봐도 이해하기 쉬운 코드가 된다.

var orderCount:int;                                                // 오더수
var availableLanguages:Array = [“kr”, “en”];     // 이용 가능한 언어
var existsSameName:Boolean = false;           // 동성동명이 존재할까?(존재 true)
var unknownUserAgent:UserAgent                  // 미지의 유저 에이전트

다만 변수는 변수의 종류와 그 변수의 스코프(변수의 값을 참조할 수 있는 범위, 변수의 선언으로부터 시작되어 변수의 값을 참조할 수 없게 될 때까지의 범위)에 의해서 좋은 이름의 성질이 다르다. 스코프가 넓으면 다양한 곳으로부터 참조되므로 영향 범위가 크다고 할 수 있다. 따라서 보다 구체적인 이름이 요구된다. 종류별로 보면 아래와 같다.

필드 변수, 클래스 변수
필드 변수는 인스턴스 변수이다. 필드 변수, 클래스 변수는 로컬 변수등과 비교하면 변수의 스코프가 넓기 때문에 특히 그 변수의 의미를 올바르게 표현한 이름이 바람직하다.

메소드의 파라미터
파라미터명은 알기 쉽고 간결한 이름이 좋을 것이다. 파라미터명은 이용자가 API레퍼런스로 참조하거나 Eclipse, FlashDevelop등의 통합 개발 환경으로부터 변수명의 후보로서 이용되므로 극단적으로 짧은 이름을 붙이는 것은 피해야 한다.

로컬 변수
메소드 내에서 일시적으로 선언되는 변수이다. 스코프가 긴 것도 있지만 for문과 같이 짧은 것도 있다. 스코프가 긴 것은 필드 변수와 같이 변수의 의미를 올바르게 표현하는 구체적인 이름을 붙이는 것이 좋다. 스코프가 짧은 것은 아래와 같이 사용구분만 적당히 해주면 된다.

관용어에 따르는 또는 따르지 않는다.
배열의 내용을 순서대로 처리하는 루프 카운터 변수(i,j,k)등과 같이 잘 사용되는 관습적인 변수명은 그대로 관용어에 따르는 편이 알기 쉬운 코드가 된다.
// 루프 카운터의 변수명이 관습적이지 않고 너무 길다 [X]
for (var empCounter:int=0 ; empCounter < employes.size ; empCounter++) {
          var emp:Employee = employees[empCounter];
    ...
}

// 루프 카운터의 이름이 관습적으로 짧고, 가독성이 높다 [O]
for (var i:int=0 ; i<employes.size ; i++) {
         var emp:Employee = employees[i];
    ...
}


다만 예외적인 경우도 있다. 구체적인 이름을 변수명으로 하는 편이 알기 쉬운 경우는 그렇게 사용한다. 예를 들어 좌표계를 취급하는 경우에는 아래와 같이 사용하여 가독성을 높일 수 있다.
// i,j의 어느 쪽이 x좌표, y좌표인지를 모른다 [X]
for (var i:int=0 ; i<width ; i++) {
    for (var j:int=0 ; j<height ; j++) {
        var color:uint = getColor(i, j);
        ...
    }
}

// 변수명을 x,y로 했으므로 알기 쉽다 [O]
for (var x:int=0 ; x<width ; x++) {
    for (var y:int=0 ; y<height ; y++) {
        var color:uint = getColor(x, y);
        ...
    }
}

위 for문의 경우, 중첩되는 var y:int=0 변수 선언은 for문 밖에서 선언해 주는 것이 바람직하다. 중첩된 for문 안에서 x가 카운팅 될 때마다 메모리상에서는 y라는 변수의 어드레스를 매번 push해야 하는 불필요한 리소스 낭비가 발생하기 때문이다. (이 부분에 대한 논쟁 이슈가 있다. 이후에 이야기할 로컬 변수의 스코프 부분에서 로컬 변수의 스코프는 가능한 작게 한다는 변수의 의존성에 따른 대원칙에 위배되는 것이기 때문이다. 이것은 사용하는 상황에 따라 적절히 혼용하는 것이 좋을 것이다.)
var x:int;
var y:int;
for (x=0 ; x<width ; x++) {
    for (y=0 ; y<height ; y+) {
        var color:uint = getColor(x, y);
        ...
    }
}

변수명을 짧게 하는 편이 가독성이 향상되는 경우도 있다.
충분히 인지할 수 있는 범위인 경우로 루프내의 변수나 짧은 메소드 내의 변수처럼 일시적인 변수는 짧게 하는 편이 반대로 가독성이 향상되는 경우도 있다.
// 변수명 siteContactChangelog는 너무 길다 [X]
for (var i:int=0; i<siteContactChangelogs.length ; i++) {
    var siteContactChangelog:SiteContactChangelog = siteContactChangelog[i];
    siteNames[i] = siteContactChangelog.getSiteName();
    siteTitles[i] = siteContactChangelog.getSiteTitle();
    sitePicIds[i] = siteContactChangelog.getPicId();
    sitePicNames[i] = siteContactChangelog.getPicName();
}

// 변수명 log는 충분히 그 의미를 이해할 수 있기 때문에 가독성이 좋다.[O]
for (var i:int=0; i<siteContactChangelogs.length ; i++) {
    var log:SiteContactChangelog = siteContactChangelog[i];
    siteNames[i] = log.getSiteName();
    siteTitles[i] = log.getSiteTitle();
    sitePicIds[i] = log.getPicId();
    sitePicNames[i] = log.getPicName();
}

좋은 메소드명
좋은 메소드명은 이름으로부터 그 기능을 예상할 수 있다. 메소드는 처리를 담당함으로 메소드명은 동사+목적어 형태인 것이 많다. 아래는 자주 사용되는 메소드명의 예이다.
 메소드의 역할                                         메소드명
 값 취득에 관한 메소드                           getXXX
 값 세트에 관한 메소드                           setXXX
 생성에 관한 메소드                                create, build, make, generate
 초기화에 관한 메소드                            initialize, setupXXX
 파기에 관한 메소드                               destroy, dispose
 상태 확인에 관한 메소드                      contains, exists

인스턴스 메소드는 dataFormat.parse와 같이 오브젝트명으로 조합하므로 합쳐졌을 때는 중복 없게 의미가 통하는 이름으로 한다. 메소드와 클래스명도 이와 동일하다.
// parseDateString은 클래스명 DateFormat과
// date라는 이름이 중복되어 약간 장황
var dateFormat:DateFormat = new DateFormat("yyyy-MM-dd");
var startDate:Date = dateFormat.parseDateString("2008-04-01");

// 클래스명 DateFormat과 메소드명 parse로
// 무엇을 처리하는지 충분히 이해할 수 있음.
var dateFormat:DateFormat = new DateFormat("yyyy-MM-dd");
var startDate:Date = dateFormat.parse("2008-04-01");

좋은 클래스명
변수명이나 메소드명과 비교해서 클래스명은 가용 범위가 크기 때문에 적절하고 좋은 클래스명을 붙이는 것이 중요하다. 좋은 클래스명은 이름만으로 무엇을 실시하는 클래스인가를 알 수 있다.

클래스명이 잘 떠오르지 않을 때는 자신이 만들려고 하는 클래스의 역할을 제대로 정리 할 수 있는지 없는지를 판단해 보아야 한다. 1개의 클래스에 복수의 책무를 넣거나 역할이 애매한 기능은 없는지를 생각해보고 해당 클래스에서 해결하고자 하는 문제를 차분히 생각해보고 클래스명을 다시 선택할 필요가 있다.

클래스명의 어휘 설계 능력
이름 명명에 관하여 자신이 모르는 표현, 개념은 쉽게 생각하기 어렵다. 보다 나은 표현을 선택하려면 여러 가지 코드나 서적을 읽거나 실제로 코드를 쓰고 시험하는 것이 중요하다. 그 경험을 통해서 이름에 관한 어휘가 조금씩 늘어난다. 본인 같은 경우는 영어권의 개발자가 작성한 기능과 메소드명을 보면서 의미해석을 한다. 사실 프로그래밍 과정에서 이름을 짓는 것은 생활에서 보편적으로 사용하지 않는 단어들도 많이 존재한다. 하지만 그만큼 자주 사용되는 단어들은 한정되어 있기 때문에 틈나는 대로 기억을 되살려 사용해 보는 것이 중요하다.

좋은 패키지명
ActionScript의 패키지명은 클래스나 자원의 논리적인 그룹을 만들어 계층 구조를 나타낸다 이것은 주로 이름의 충돌을 막기 위해서 사용된다. 패키지명은 그룹의 논리적인 내용을 나타내는 간결한 명사를 선택한다.

간혹 클래스를 만들지 않고 라이브러리에서 특정 무비클립을 동적으로 참조하기 위하여 Linkage에 클래스명만 기입하여 사용하는 경우가 있다. 이럴 경우 클래스가 플래시 컨텐츠전역에 오픈 되기 때문에 팀의 협업에 있어서 클래스명의 충돌을 야기할 수 있다. 이럴 경우 해당 클래스가 없더라도 관련된 패키지명을 명시함으로써 그러한 충돌을 줄일 수 있다. 

처음부터 좋은 이름을 사용할 수 있는 사람은 없다. 좋은 이름에 대해서 의식적으로 사용하려고 노력하는 것이 중요하다. 누구라도 알기 쉽고, 이해하기 쉬운 코드라고 하는 것은 항상 의식하고 노력하다 보면 점차적으로 좋은 이름을 지을 수 있는 요령이 생길 수 있을 것이다.


스코프를 의식한 프로그래밍
사실 모든 프로그래밍에서 스코프는 존재한다. 의식적으로 스코프를 컨트롤 할 수 있으면 보다 좋은 프로그래밍 스타일에 가까워질 것이다. 이번에는 스코프에 대한 이야기를 해보자.

우선 스코프는 Wikipedia에 다음과 같이 정의되어 있다.
프로그래밍에서 스코프란, 어느 변수나 함수가 특정 이름으로 참조되는 범위, 어느 범위의 밖에 있는 변수 등은 통상 그 이름만으로는 참조할 수 없다. 이때 이러한 변수는 스코프 밖에 있어 보이지 않는다 라고 말한다.

스코프는 변수, 메소드, 클래스등이 보이는 범위다. 그렇다면 보인다는 의미는 무슨 뜻일까? 보인다라는 것은 프로그래밍상에 있다는 것이다. 변수이면 변수명을 지정해 값을 읽고 쓰기가 가능하고 메소드는 호출해 사용할 수 있는 범위에 있는 것이다.

사용할 수 있다라는 것은 바꾸어 말하면 그것에 의존한다라고 이야기할 수 있다. 하나의 코드를 변경하고 싶을 뿐인데 수십 곳을 수정할 필요가 있을 수 있다. 이것은 변경하고자 하는 코드가 여러 곳에 의존하고 있으면 이와 같은 변경이 다른 부분에 영향을 준다.

스코프 == 보이는 범위 == 사용할 수 있는 범위 == 의존하는 범위

변수나 메소드의 스코프를 작게 하는 것으로 보이는 범위가 작아져 사용할 수 있는 범위, 의존하는 범위도 작게 할 수 있다. 스코프를 작게 하는 것으로 보다 의존성이 적어 변경이 용이한 프로그램을 작성 할 수 있는 것이다.

기억해 두는 것을 줄이자.
의존이 작아지는 것 이외에도 스코프를 작게 하는 것으로부터 도움이 되는 것이 있다. 프로그래밍은 본질적으로 복잡한 것이다. 복잡함에 대한 대책으로서 문제 영역을 가능한 작고, 이해 가능한 상태로 취급하는 것이 중요하다. 스코프를 의식적으로 작게 하는 것으로 프로그래머가 기억해 두지 않으면 안 되는 것, 주의하지 않으면 안 되는 범위는 작아져서 쉽게 이해할 수 있게 된다. 이것이 스코프를 작게 하는 것의 본질이라고 할 수 있다.

로컬 변수의 스코프
로컬 변수란 메소드 내에서 선언된 일시적인 변수다. Java나 Ruby의 로컬변수는 선언된 장소로부터 스코프가 시작되어 선언된 블록이 끝나면 스코프가 종료된다. ActionScript 2.0 에서도 순차적으로 메모리 할당이 이루어 졌기 때문에 메소드 내에서 상위에 선언된 변수와 하위에서 선언된 변수가 서로 다른 영역 범위의 스코프를 갖기 때문에 컴파일 시에 충돌이 발생하지 않았다.(Java, Ruby와 동일)

반면 ActionScript 3.0에서의 로컬변수는 스코프의 시작은 컴파일러가 블록에 접근했을 때 블록 내의 위치와는 상관없이 미리 메모리 주소가 할당된다. 이는 컴파일 시에 메모리 할당이 한꺼번에 선행되어 스코프가 동일하기 때문에 변수명 중복 에러 메시지를 출력하는 것이다.

하지만 일반적인 프로그래밍 언어에서는 변수의 의존도를 최소화하여 프로그램의 변경이 쉽게 하기 위하여 [로컬변수의 스코프는 가능한 작게 한다.] 라는 것이 대원칙이다.

필드 변수의 스코프
필드 변수는 인스턴스 변수다. 필드 변수의 스코프는 private / public 등과 같은 키워드를 통해서 정해진다. ActionScript의 경우 필드 변수에 대한 가시성은 스코프가 작은 순서로 4개가 지원된다.
private    : 오브젝트 내에서만 변수에 액세스 할 수 있다.
internal    : 같은 패키지 내에서 액세스 할 수 있다.
protected : 오브젝트 내 그리고 하위 클래스로부터 액세스 할 수 있다.
public : 오브젝트 밖에서 액세스 할 수 있다.

필드 변수는 모두 private가 기본 전략이다. 필드 변수에 외부나 하위 클래스로부터 액세스 하고 싶은 경우에는 set/get 등 액세스용 메소드를 따로 만들어 공개하는 것이 캡슐화에 도움을 준다. 하지만 기본 전략이 바람직하다고는 하지만 상속에 따른 장황함을 배제하기 위해서 protected나 public 접근자를 사용하는 경우도 발생한다.

인스턴스 메소드의 스코프
인스턴스 메소드는 인스턴스에 속하는 메소드를 말한다. ActionScript에서 메소드의 스코프 가시성도 필드 변수와 같이 4개이다. 메소드의 접근 제한은 최소인 private로부터 시작하여 점차적으로 internal -> protected -> public으로 나아가는 것이 바람직하다.

메소드 파라미터의 정보량
스코프에서 조금 벗어난 이야기이지만 메소드의 인수로 건네주는 정보량을 어느 정도로 하는 것도 의존성이라는 관점에서 보면 중요한 선택이다.

예를 들면 아래의 두 코드는 사원 정보를 취득하는 메소드이지만 1번은 인수가 사원ID이고 2번은 인수가 사원 오브젝트이다. 이 두 개의 코드 중에 어느 쪽이 좋은 코드라고 할 수 있을까?
// [1] 인수가 사원ID인 경우
public function getEmployee(inEmpId:int):Employee {
    return empDao.findById(inEmpId);
}

// [2] 인수가 사원 오브젝트의 경우
public function getEmployee(inEmp:Employee):Employee {
    return empDao.findById(inEmp.getId());
}

일반적으로 1번이 인수의 정보량이 적기 때문에 의존이 적고 좋은 코드라고 할 수 있다. 반면 2번은 사원 오브젝트가 가지는 모든 정보로 액세스가 가능하기 때문에 의존이 커지게 된다. 필요한 것은 사원의 ID이므로 그것에만 의존하여 코드를 작성하는 것이 바람직하다.

메소드를 이용하는 측면에서 사원 ID만으로 메소드를 이용할 수 있는 것과 사원 오브젝트가 필요한 것은 전혀 다르다. 더욱이 2번 메소드 내에서 구체적인 처리는 사원 오브젝트의 사원 ID만을 사용해 사원 정보를 검색하고 있다. 이것이 문서화 되어 있지 않을 경우, 코드를 읽지 않으면 그 사실을 알지 못한다. 인수에 불필요한 정보가 포함되어 있으면 사원 ID가 포함된 사원 오브젝트를 건네주어야 한다는 암묵적인 요구가 발생하기 쉽다.

위와 같은 문제 때문에 메소드의 인수는 필요 최저한의 정보를 가지는 것이 의존성이 적고 좋은 코드라고 말할 수 있다.

다만 인수가 너무 많아지는 경우는 인수를 오브젝트로 변경하는 편이 좋다. 기준으로서 인수의 개수가 5개를 넘는 메소드는 인수를 오브젝트로 변경하는 것을 검토할 필요가 있다.

static 메소드
static메소드(클래스 메소드)는 클래스에 속하는 메소드이다. ActionScript에서는 static 키워드를 붙여서 선언한다. static 메소드의 가시성은 인스턴스 메소드의 가시성과 같다. 반면 다른 점은 static 메소드는 필드 변수에 액세스 할 수 없다. static 메소드는 메모리에 미리 할당이 되는 반면 인스턴스 변수는 오브젝트가 인스턴스화 된 시점에서 메모리 할당이 되기 때문에 static 메소드 내에서 인스턴스 변수를 참조할 방법이 없는 것이다.

필드 변수에서 보면 인스턴스 메소드를 static 메소드로 변경했을 경우, 자신이 영향을 주는 메소드가 줄어 들게 되어 결과적으로 스코프는 작아진다. 필드 변수에 액세스 할 필요가 없고, 오버라이드가 필요하지 않는 메소드는 static 메소드로 하는 편이 좋은 경우가 많다. 물론 무조건 static으로 하는 것이 좋은 것은 아니다. 인스턴스가 생성되지 않은 시점에서 메모리에 할당이 되기 때문에 사용하지 않는 클래스의 static 메소드가 메모리에 상주하는 메모리 차원에서의 단점도 있다.
// 인스턴스 메소드의 경우
private var count:int;                                                           ┓
...                                                                                           |
private function regexGroup(inRegex:String):String { |변수 count의 스코프
    // 필드에 액세스 가능                                                     |
    return "(" + regex + ")";                                                   |
}                                                                                             |
...                                                                                            ┛

//static 메소드로 변경했을 경우
private int count;                                                                  ┓
...                                                                                            ┛변수 count의 스코프
static private function regexGroup(inRegex:String):String {
    // 필드에 액세스 불가
    return "(" + regex + ")";
}
...     ―변수 count의 스코프


코드의 분할
몇 천행이 넘는 메소드로 너무 많은 기능을 포함하고 있거나 메소드를 너무 세세하게 분할하여 흐름을 파악하기 어려운 코드는 좋은 코드라 할 수 없다. 좋은 코드가 되기 위해서는 가독성이 좋고, 유지보수성이 우수한 것이라고 위에서 언급했다. 메소드를 적절한 단위로 분할하는 것은 좋은 코드를 만드는 것에 중요한 역할을 한다.

코드를 분할하면 무엇이 좋은가?

가독성의 향상
메소드 코드의 길이가 100줄을 넘으면 처리의 흐름을 읽는데 어려움이 있다. 반면 30행 이하이면 내용을 이해하는 것이 용이하다.

유지보수성의 향상
분할에 의해 변수의 스코프가 작아지거나 처리 기능이 본래 있어야 할 클래스나 메소드로 이동하는 것으로 의존관계가 정리되어 유지보수성이 향상된다.

재이용성 향상
코드를 분할하면 코드의 중복이 줄어들어 이용 가능한 부품으로서의 메소드나 클래스를 만들 수 있다. 이것은 OOP 언어에서 좋은 방법이다.

캡슐화를 지킬 수 있다.
객체 지향에서는 캡슐화라는 개념이 있다. 메소드나 클래스의 상속에 의한 구체적인 구현이나 오브젝트 상태를 몰라도 메소드를 호출하는 것만으로도 각각의 오브젝트가 처리를 이행해 주는 것이다.

클래스의 관점에서도 비슷한 이득을 얻을 수 있다. ActionScript는 타 언어보다 MVC 페턴을 예로 들면 view에 해당하는 클래스가 Model에 비해 상대적으로 비대하다. 따라서 구조 작업에 있어서 이러한 view 그룹을 어떻게 분할하느냐에 따라서 유지보수성의 성패를 좌우한다고도 볼 수 있다.

위에서 좋은 코드를 위한 방법에 관하여 이야기를 했다. 연재에 실린 내용과 그것을 ActionScript에 맞게 수정하는 관계로 문장이 다소 매끄럽지 않는 점이 있을 것이다. 그런 부분은  이해해 주길 바란다.

사실 플래시는 타 언어에 비해서 버그가 발생할 가능성이 크다. 그 이유는 플래시의 강점인 모션을 항상 고민해야 하는 작업이기 때문이다. 일반적인 언어에서는 어떤 오브젝트가 나타나고 사라지는 사이에 시간이라는 개념을 포함할 필요성을 인식하지 못하지만 플래시는 모션에 따라 그 사이에 시간이 존재할 수 있다. 모션이 있는 사이에 예측하지 않은 사용자 반응이 있을 경우에는 버그가 발생할 수 있다. 플래시 개발자는 항상 이런 부분까지 예상하고 방어적 프로그래밍을 해야 한다.

위에서 이야기한 좋은 코드를 작성하는 것은 플래시의 작업에 많은 도움을 주지만 그런 것이 플래시 개발의 모든 약점을 보완해 주지는 못한다. 때로는 일반적인 좋은 코드로서의 방향에 영향을 주지 않는 범위 내에서 플래시의 장점을 극대화 할 수 있는 방법을 고민 해야 하는 것이다.

간혹 좋은 코드를 작성하는 방법을 물어보시는 분들이 있다. 물론 그것이 모르는 부분을 빨리 이해할 수 있는 좋은 방법일 수 있지만 쉽게 얻은 지식은 지식으로 머물러 지혜로 발전하지 못하는 경우가 많다. 더구나 본인 또한 그 방법을 찾고자 고민하고 배워가는 입장이기 때문에 도움을 주지 못하는 경우도 있다.

또한 플래시의 발전은 지식에 목말라 스스로 지혜를 얻으려 노력했던 선배들의 도움으로 커왔다고 나는 믿고 있기 때문이기도 하다. 위에서 이야기 한 내용은 본인 또한 노력하는 부분이고 이 포스트를 읽는 분들도 지혜를 얻기 위해 노력하다보면 좋은 코드를 생산할 수 있을 것이라 믿는다.



    

설정

트랙백

댓글

  • ° 북극곰 ° 2008.12.27 15:39 신고 ADDR 수정/삭제 답글

    플래시를 전혀 모르는 사람이지만 대충봐도 대단한 글이네요 ~! 혹 플래시 배울일이 있으면 참고하겠습니다 ~! 수고많이 하셨어요 ~!!

    • jasu 2009.01.01 02:15 신고 수정/삭제

      안녕하세요 말씀 감사합니다. ^^

  • douglas9 2008.12.29 18:23 ADDR 수정/삭제 답글

    좋은 글 잘 읽고 가요^^

    • jasu 2009.01.01 02:16 신고 수정/삭제

      네네 저도 다시 한번 정리하는 차원에서 작성한 글입니다. ^^

  • neewoo 2008.12.29 21:01 ADDR 수정/삭제 답글

    좋은 내용 잘읽었습니다. 개인적으로 도움이 많이 되는글이네요

    • jasu 2009.01.01 02:16 신고 수정/삭제

      도움이 되었다니 기분 좋은 일입니다. ^^ 새해 복 많이 받으세요

  • BK2008 2008.12.30 10:21 ADDR 수정/삭제 답글

    자수형님~ 익히 알았지만... 형님은 말을 참 논리있게 잘 하세요~
    좋은 내용이었습니다. 잘 보고 이 글에 힘입어 공부하러갑니다.^^

    • jasu 2009.01.01 02:19 신고 수정/삭제

      부군~ ^^ 글 내용은 잡지에 실린 내용과 내 개인적인 생각을 짬뽕해 놓은 거니 하향 조정해도 될듯하네 ^^ 건강하고 새해 복 많이 받길~

  • 쿠나 2008.12.30 20:37 ADDR 수정/삭제 답글

    장문이군요. 좋은 코드를 쓰지 않으면 절대로 좋은 프로그램이 만들어지기는 어렵다는 것을 다시 한번 보고 갑니다 ㅎㅎ.

    • jasu 2009.01.01 02:20 신고 수정/삭제

      공부를 통해서 아는 것만으로는 이 업계에서 살아남기 힘들다고 하더군요 ^^ 저도 그래서 노력 중입니다.

  • 야매코더 2008.12.30 23:26 ADDR 수정/삭제 답글

    잘봤습니다.
    유익하고 공감이 많이 가는 내용이었는데요 ,.
    저는 클래스간의 관계나 변수들이 햇갈려서 앞으로 UML 을 그려 가며^^(상그럽지만 ..)
    할려고 하는데요 ,.어찌 생각하시는지 /> ? ㅋ
    (지금 시상식 보고 있어서 ㅡ,.- 덧글에 인터뷰를 하고 있을뿐이고 ,.ㅋㅋ)

    • jasu 2009.01.01 02:21 신고 수정/삭제

      머리속에 있는 것을 좀더 구체화 하는 훈련을 하는 것도 체계가 있고 단계를 따라 진행하면 좀더 효율적으로 머리속 자원을 쓸 수 있다는 생각이 드네요 다만 그 훈련 자체가 노력이 필요한 부분이니 작은 것부터 꾸준히 진행하세요 ^^

  • bluesoo 2009.01.12 10:25 ADDR 수정/삭제 답글

    정말 좋은 정보 감사합니다. ^^
    프로그래밍 공부에 대한 저의 갈증이 많이 해소된것같네요. 참고해서 저도 더 좋은 코드 만들도록 노력할게요

    • jasu 2009.01.12 15:17 신고 수정/삭제

      저도 이런 정보를 접하다보면 읽는 당시에는 아 그렇구나 그렇게 해야지 하면서도 막상 실 작업에서는 망각하는 경우가 많은 것 같아서 반성중입니다. 도움이 되셨나니 기분 좋은 일입니다. ^^

  • 최강쥐으니 2009.01.15 17:30 ADDR 수정/삭제 답글

    와~~유익한 정보 ^^
    멋지구먼~~~-0-b

    • jasu 2009.01.16 14:20 신고 수정/삭제

      무유익은 본인이 받아들여야 성립한다는 ^^
      술사~ ^^

  • lovedev 2009.01.21 20:32 ADDR 수정/삭제 답글

    정말 공감가는 내용입니다.. 저랑 생각이 어쩜..이렇게..
    잘 읽고 가요 ^^

  • 검쉰 2009.01.25 20:31 신고 ADDR 수정/삭제 답글

    좋은 글입니다. ;)

    • jasu 2009.01.28 12:50 신고 수정/삭제

      새해 좋은 일 가득하세요~

  • 지돌스타 2009.01.27 11:31 ADDR 수정/삭제 답글

    잘읽었습니다. ^^

    • jasu 2009.01.28 12:50 신고 수정/삭제

      저도 가끔 지돌스타님의 글에서 도움 많이 받아요 감사합니다.

  • kakiyata 2009.02.09 17:28 ADDR 수정/삭제 답글

    저한테 꼭 필요한 내용!! 그죠? ㅎㅎ

    • jasu 2010.02.12 11:22 신고 수정/삭제

      쿠쿠 본인도 시간이 지나면서 환경과 타협을 하게 된다는..

  • 삶의향기 2010.02.08 15:38 ADDR 수정/삭제 답글

    저같은 경우는 항상 생각을 하면서 작성을 하지만 이후 돌아보면 손이 갈곳이 많더군요.^^;;

    끊임 없이 닦고 조이고..

    좋은 글 잘 읽었습니다.

    • jasu 2010.02.12 11:25 신고 수정/삭제

      반복적인 작업이더라도 효율적인 방법을 찾게 되는 것 같습니다. 처음부터 너무 완벽하면 그 또한 인간답지 않겠죠. ^^

[AS3] swf가 임베드된 html 경로 알아내기

Programming/ActionScript 3.0 2008. 12. 25. 02:01
swf가 임베드 되어 있는 html의 도메인 경로를 알아내기 위해서는 아래와 같이 ExternalInterface를 이용하여 자바 스크립트 문법에 도움을 받아 location 경로를 리턴 받을 수 있다.

var locationUrl:String = ExternalInterface.call("document.location.href.toString");

그러나 이렇게 했을 경우 하나의 문제가 있다.

만약 임베드된 object의 id값을 설정하지 않거나 설정하더라도 동영상 플레이어처럼 여러 개의 swf를 하나의 페이지에 임베드 할 경우에는 오브젝트의 id값이 같기 때문에 ExternalInterface를 이용하여 자바스크립트 함수를 호출할 수 없는 상황이 발생한다. ExternalInterface를 사용할 경우 아래와 같은 경우에는 자바스크립트를 호출할 수 없다.

HTML 페이지의 Flash Player 인스턴스에 제공된 이름(object 태그의 id 속성)에 JavaScript에서 연산자로 정의된 하이픈(-)이나 다른 문자가 포함되어 있으면(예: +, *, /, \, . 등) Internet Explorer에서 컨테이너 웹 페이지를 보면서 ActionScript에서 ExternalInterface를 호출할 수 없습니다.
뿐 만 아니라 Flash Player 인스턴스를 정의하는 HTML 태그(object 및 embed 태그)가 HTML form 태그에 중첩되어 있는 경우에도 ActionScript에서 ExternalInterface가 호출되지 않습니다.

따라서 하나의 html 페이지에 여러 개의 같은 swf를 임베드 할 경우에는 각각의 object 아이디를 다르게 설정해 주어야 한다. 그러나 상황에 따라서 중첩되는 object태그들의 id를 서로 다르게 부여하기 위해서는 여러 가지 난제가 있을 수 있다. 그렇다면 object 의 id 값을 같게 하더라도 자바스크립트 함수를 호출할 수 있는 방법이 없을까? 위와 같은 상황이라면 IE가 파이어폭스처럼 object id가 같은 상황이라도 ExternalInterface가 자바스크립트 함수를 호출해 줄 수 있을 때까지 기다리거나 ExternalInterface가 위와 같이 호출할 수 없는 상황이 발생하지 않기를 바랄 수밖에 없다. 그렇다고 해결할 수 없는 문제로 남기기에는 플래시가 서운할 것이다. object id가 같아도 ExternalInterface가 자바스크립트 함수를 호출할 수 있도록 만들어 보자.

방법은 ActionScript에서 요긴하게 사용할 수 있는 SharedObject 객체이다. SharedObject객체는 기본적으로 도메인당 최대 100KB의 데이터로 공유 객체를 만들 수 있다. SharedObject의 data속성에는 String, Array, Number, Boolean, ByteArray, XML와 같은 공유 객체를 담을 수 있다.

위에서 언급한 상황처럼 같은 swf가 여러 개 임베드 되어 있고 object id가 같을 경우 IE에서는 첫번째 임베드 되어 있는 swf에서는 정상적으로 ExternalInterface를 통하여 자바스크립트를 호출해 준다. 그러나 아래에 임베드된 swf에서는 자바스크립트를 호출하지 못한다. 따라서 첫번째 임베드된 코드에서 제대로 리턴 받은 경로를 SharedObject를 이용하여 flush(쓰기)를 하고, 반면 ExternalInterface를 통해서 리턴 받은 값이 “null”일 경우에는 SharedObject를 통해서 저장된 기존의 domain 경로를 불러와서 사용하는 것이다.

아래는 그러한 방법으로 처리한 코드 예이다.

private function getLocationUrl():String
{
    var domain:String = String( ExternalInterface.call(" function(){ return document.location.href.toString();}"));
    var so:SharedObject = SharedObject.getLocal("location");
   
    if (domain != "null"){
        so.data.domain = domain;
        so.flush();
    }else{
        domain = so.data.domain
    }
   
    return domain;
}

위 방법은 그럴듯 하다. 그런데 문제가 있다. 브라우저가 자바스크립트를 호출해 주는 object를 먼저 참조하지 않는다는 것. 따라서 위 방법으로 했을 경우 페이지를 한 차례 재로드해 줘야 제대로 적용이 된다.

결국 object id 값을 서로 다르게 설정하는 것으로 가야만 했다는... 삽질의 길은 멀고도 험하구나...

    

설정

트랙백

댓글

  • 쿠나 2008.12.25 12:32 ADDR 수정/삭제 답글

    글 잘 읽었습니다. SharedObject를 이렇게 이용할 수 있네요
    더불어 도메인을 javascript를 이용하지 않고 Actionscript를 이용해서 구하는 방법도 잘 보고 갑니다 :D

    • jasu 2008.12.27 11:12 신고 수정/삭제

      동영상 플레이어와같은 형태의 퍼가기 기능의경우는 퍼가는 소스에 자바스크립트 함수를 포함할 수 없기 때문에 플래시 내에서 이런 형태로 호출하기도 합니다.

  • 경훈 2008.12.29 00:01 ADDR 수정/삭제 답글

    allowScriptAccess 가 never 로 되어있을 경우도 알려주세욧!! ^ ^~
    저 월,화 휴가에요, 31일에 보겠네요, 열흘만에 보는듯 쿠쿠~
    저 없다고 심심해하지 마세요~ 쿠쿠

    • jasu 2009.01.01 02:11 신고 수정/삭제

      쿠쿠 never일 경우 자바스크립트를 호출하는데 문제가 있겠지~ 설마 없다고 심심해 할까 ^^

[AS3] interface 에 관한 이해

Programming/ActionScript 3.0 2008. 12. 17. 17:04

이웃 블로그를 순방하다가 오랜만에 블로그에 글을 남기게 된다. 자수 블로그가 한동안 무척이나 푹~ 잠들었었다. 개인적으로 풀리지 않는 일들도 있고, 회사 일도 그렇고, 여러 가지로 말문을 열지 못하게 요인들은 앞으로 과감히 무시하고 이제는 조금씩 잃어버린 여유를 찾아서 나를 더욱 여유롭지 않게 해야겠다는 생각을 하게 된다.

오랜만에 땡굴이 형님의 불로그에 방문했다가 IEventDispatcher 인터페이스에 관한 설명들을 보고 보충해서 설명하고자 포스트를 쓴다. 일단 프로그래밍 언어(OOP언어)에서 인터페이스에 관한 것은 책에 많이 기술되어 있기 때문에 그 개념은 어느 정도 느끼고 있지만 그 활용 방법에 대해서는 구체적으로 떠오르지 않는 분들이 많은 것 같다. 사실 나 또한 그러하다. 설명하고자 하는 내용은 지극히 개인적인 작업을 바탕으로 설명하는 것임을 밝혀둔다.

단적으로 말해서 인터페이스는 open 개념이 아닌 close 개념에 가깝다. 이 이야기는 객체를 개방하는 것이 아닌 하나의 종속된 틀 속에 관련 객체를 구속하여 외부의 다른 잡음으로부터 보호하고 다른 객체와 대체할 수 있는 기반을 만드는 것이 주 목적 이라는 것이다.

예를 들어 “문” 이라고 일컬어 지는 것들은 대부분 공통의 요소가 존재한다. 손잡이, 열림, 닫힘…, 이런 요소들은 문이 창문이건, 여닫이, 미닫이이건 간에 상관없이 공통으로 사용할 수 있는 요소일 것이다. 따라서 프로그래밍 언어에서는 이러한 공통의 요소를 하나의  interface로 만들어 implements 키워드를 통해서 구체적인 구현을 클래스에서 이행하게 되는 것이다.

그렇다면 의문이 생길 수 있다. 이렇게 한다고 하여 개발자 입장에서 더 좋은 것이 무엇이냐고…, 물론 인터페이스를 굳이 사용할 필요가 없는 곳에서 사용을 하게 되면 손가락만 피곤하다. 하지만 위에서 언급한 “문”이라는 객체가 프로젝트 안에서 하나가 아니라 대문, 창문, 화장실문, 서랍장문… 등이 사용되고 이러한 문들은 행위자(문을 사용하는 사람)에 따라서 어떤 문이건 간에 손잡이를 잡고 열고 닫을 수 있어야 한다면 이야기는 달라진다.

여기서 간단한 클래스 구조를 통해서 위에서 이야기한 부분에 대해서 다시 한번 생각해 보도록 하자.

문인터페이스 : IDoor
package {
    public interface IDoor {
        function open():void;
        function close():void;
    }
}


대문 : Gate <- IDoor
package {
    public class Gate implements IDoor {
        public function Gate() {
        }
        public function open():void {
            trace("open in Gate Class");
        }
  
        public function close():void {
            trace("close in Gate Class");
        }
    }
}

창문 : Window <-- IDoor
package {
    public class Window implements IDoor {
        public function Window() {
   
        }
        public function open():void {
            trace("open in Window Class");
        }
  
        public function close():void {
            trace("close in Window Class");
        }
    }
}

행위자 : Person
package {
    import flash.events.Event;
    import flash.events.EventDispatcher;
    public class Person extends EventDispatcher{
  
        static public const OPEN_DOOR:String = "openDoor";
        static public const CLOSE_DOOR:String = "closeDoor";
        private var _door:IDoor;
  
        public function Person(inDoor:IDoor) {
            _door = inDoor; 
        }

        private function doAction(isOpen:Boolean):void {
            if(isOpen){
                _door.open();
                dispatchEvent(new Event(OPEN_DOOR));
            }else {
                _door.close(); 
                dispatchEvent(new Event(CLOSE_DOOR));
            }
        }
    }
}

메인 클래스 : MainDocument
package {
    import flash.events.Event;
    public class MainDocument extends Sprite {
        private var _person:Person;
        public function MainDocument() {
            _person = new Person(new Gate()); // or _person = new Person(new Window());
            _person.addEventListener(Person.OPEN_DOOR, onOpenHandler);
          _person.addEventListener(Person.CLOSE_DOOR, onCloseHandler);

            _person.doAction(true); // or _person.doAction(false);
        }
  
        private function onOpenHandler(e:Event):void {
            trace("open in Person Class");
        }
  
        private function onCloseHandler(e:Event):void {
            trace("close in Person Class");
        }
    }
}

위에서 설명한 바와 같이 클래스들을 보면 어느 정도 이해할 수 있으리라 생각한다. Person 클래스에서 정의한 속성 _door은 IDoor 인터페이스 형으로 선언이 되었다. 그리고 이 속성에는 메인 클래스에서 Gate 또는 Window 인스턴스를 생성하여 Person 생성자에 인자로 전달하여도 문제 없이 객체를 담을 수 있다. 이렇게 할 수 있는 이유는 IDoor 인터페이스에서 정의한 함수(open, close)를 두 객체(Gate, Window)에서 포함하고 있으며 IDoor 인터페이스를 implements 키워드를 통해서 이행하고 있기 때문에 가능한 일이다. 다시 풀어서 이야기하면 _door 속성에 할당된 오브젝트는 무조건 open, close 함수를 사용할 수 있다는 것으로 곧 IDoor 인터페이스를 이행하고 있는 클래스라면 모두 허용한다는 것이다.

따라서 위와 같이 클래스 구조를 작성하게 되면 MainDocument 클래스 내에서 Person을 생성할 때 인자로 전달하는 객체는 IDoor 인터페이스를 이행하고 있는 모든 클래스를 담을 수 있게 되는 것이다. 이것이 OOP언어에서 장점으로 이야기하는 폴리모피즘(다형성)에 기초한다.

추가적으로 위에서 Person 클래스에서는 EventDispatcher를 상속 받고 있다. EventDispatcher 클래스는 다시 IEventDispatcher 인터페이스를 이행하는 클래스로서 자신으로부터 이벤트를 전달하는 역할을 할 수 있는 권한을 갖게 된다.(권한을 갖는다는 의미는 EventDispatcher클래스를 상속함으로써 EventDispatcher클래스 안에서 이미 정의되어 있는 함수들을 사용할 수 있다는 의미)

그러므로 위 코드와 같이 Person 클래스 내에서는 doAction 함수의 분기에 따라서 이벤트를 전달(방송)할 수 있으며, MainDocument 클래스 내에서는 생성한 Person 객체의 인스턴스로부터 전달되는 이벤트를 청취할 수 있도록 addEventListener 메소드를 통해서 핸들러 함수를 정의할 수 있는 것이다.

그렇다면 EventDispatcher 클래스만 상속하면 모든 문제가 해결될 것 같다. 하지만 그렇지만은 않다. ActionScript는 extends 키워드를 통해서 상속 받을 수 있는 것은 하나의 슈퍼클래스만 가능하다. 자바의 경우는 복수의 슈퍼클래스 정의할 수 있으나 ActionScript는 그렇지 않다. 따라서 Person 클래스가 Kind라는 클래스를 상속해야만 하는 상황이라면 어떻게 해결할 수 있을까? 이럴 때는 Person클래스에서 Kind 클래스를 상속하고 implements 키워드를 통해서 IEventDispatcher 인터페이스를 이행하여 IEventDispatcher 인터페이스에 있는 함수들을 구체적으로 기술하는 것으로 해결할 수 있다.

또 한가지 방법은 OOP에서는 상속이라는 기술만이 폴리모피즘을 구현할 수 있는 것이 아니라 위임 또는 합성을 사용할 수도 있다. 이는 extends 키워드를 통해서 특정 슈퍼클래스를 상속하는 형태가 아니라 생성자, 또는 함수를 통해서 전달된 객체를 클래스 내부에서 연결 구현해줌으로써 다형성을 만들어 낼 수가 있다. 이때 필요한 것이 바로 인터페이스라 할 수 있다.(인터페이스는 implements 키워드를 통해서 복수의 인터페이스를 이행할 수 있다.)

쓰다 보니 내용이 길어졌다. 위 코드는 포스트를 작성하면서 개념을 설명하기 위하여 임의로 작성한 코드인 관계로 실제 컴파일에서 에러가 발생할 수 있다.

    

설정

트랙백

댓글

  • 땡굴이 2008.12.17 22:04 ADDR 수정/삭제 답글

    그래 이제 좀 말문을 열어~ ^^; 좋은 글 캐스트 좀 할께..

    • jasu 2008.12.24 09:44 신고 수정/삭제

      쿠쿠 네 저도 슬슬 밀린 공부좀 해야겠네요 ^^

  • 동강 2008.12.19 11:56 신고 ADDR 수정/삭제 답글

    인터페이스를 다시 이해할수 있게 해준 글 입니다. 잘 읽었습니다.

    • jasu 2008.12.24 09:45 신고 수정/삭제

      사실 이해하기는 쉬운데 이해한 것이 나에게 말을 걸기까지는 상당한 시행착오가 필요한 것 같네요 ^^ 저도 노력 중입니다.

  • 야매코더 2008.12.20 23:06 ADDR 수정/삭제 답글

    저도 요즘 어도비에서 나온 액션스크립트3.0 디자인 패턴 을 보고 인터페이스에 대해 다시 한번 생각해보고 있습니다 . 사실 잘 안썼는데 ,. 실력이 조금씩 늘면서 간과했던 부분이 왜 필요한지 깨닫는것 같습니다,. 잘봤습니다 ^^

    • jasu 2008.12.24 09:50 신고 수정/삭제

      저도 가끔 실세계에서 적용되는 오브젝트 개념으로 접근 했다가 뒤엎는 경우가 허다한 것 같아요 디자인 패턴이나 객체지향 적인 구조적 접근의 궁극적인 목적은 현재의 프로젝트의 유지보수성을 높이고 코드의 최적화를 통해서 원활하게 사용자와 커뮤니케이션을 하기 위함이니 코드 자체로서의 아름다움을 추구하기 위해 목적을 상실하면 안되겠죠? ^^ 저는 그게 무척이나 헷갈리네요;;

  • kkanchu 2010.07.11 16:36 ADDR 수정/삭제 답글

    정말 정말 감사합니다.. 인터페이스가 뭔지 몰라서 한참을 찾다가 여기 블로그까지 오게 되었네요.. 자세한 설명 감사합니다..

    • jasu 2010.07.14 17:37 신고 수정/삭제

      인터페이스는 처음에는 어렵게 느껴지지만 개념만 제대로 이해하시면 어려움이 없으실것 같네요. 인터페이스와 같은 다형성에 관련된 개념은 컴퓨터 프로그래밍의 거의 모든 언어에서 사용되는 개념이니 익혀두시면 좋을 것 같습니다. 감사합니다.

[AS3] ActionScript의 방향성

Programming/ActionScript 3.0 2008. 9. 3. 23:50
FlashPlayer9 발표 이후 adobe에서는 ActionScript를 ECMA-262 Edition 4 (ES4)에 준하도록 진행한다는 이야기가 있었다. ES4는 현재 Adobe, Mozilla, Opera, Google등이 주축이 되어 표준화가 진행 중이지만 작년 Microsoft와 Yahoo 주도로 ECMA-262 Edition 3.1(ES 3.1)의 워킹 그룹이 결성된 이후 위와 같이 두 개가 다른 ES3 후속 안으로 병존하는 상황이 계속되고 있다고 한다.

ES3.1은 ES4의 부분집합이 아니기 때문에 ActionScript 3.0은 ES3.1와 호환되지 않는다. 예를 들어 ES3.1의 문법에는 namespace, package가 포함되지 않는다. ES3.1은 추가 버전업을 진행하더라도 이러한 문법은 포함하지 않을 것을 분명히 하고 있다.

이러한 상황에 대해서 Adobe측에서는 정식으로 코멘트를 하고 있지 않지만 Adobe의 오픈소스팀 디렉터 Dave는 블로그를 통해서 아래와 같이 이야기를 전하고 있다.

* ECMAScript 표준화 위원회 참가 기업의 이해 불일치에 의하여 사양의 일원화가 어려운 상황이다.
* Web에 공통의 언어를 가지는 것이 필요하다는 관점으로부터 Harmony에 찬성한다.
* Web의 혁신을 더욱 진행하기 위해 ActionScript의 확장은 계속된다.
* 오픈소스 커뮤니티 활동의 발전도 표준화 위원회와의 활동과 함께 중요하게 인식하고 있다.

ECAMScript의 표준화에는 계속 참가하지만 ES3.1의 레벨까지 AS3의 기능을 되돌리는 것은 생각하지 않는 것으로 보인다. 눈에 보이는 제품의 성능에 대해서는 어느 것이 좋다 나쁘다로 판단할 근거가 명확하지만 이러한 프로그래밍 언어적 문법에 대한 표준화에는 상당한 이해관계가 얽혀 있는 듯하다.

처음 언어를 배우는 사람에게는 영어이건, 독일어이건 처음 배우는 과정에서 생산되는 엔트로피는 비슷하겠지만 이미 영어를 배우고 익숙한 학생이 독일어를 접하면 적지 않게 혼란스러운 것이 사실이다. 물론 자연어와 다르게 컴퓨터로 명령을 내리는 프로그래밍 언어의 경우는 그 안의 알고리즘 측면에서 본다면 크게 다르지 않겠으나 나와 같이 천천히 흘러가는 뇌의 전류로는 감당하기 버거울 것이다.

AS2에서 AS3로 넘어오면서 가장 나를 혼란스럽게 했던 것은 Void와 void, _alpha와 alpha, _alpha = 100과 alpha=1이었다. 지금도 그 추억에 사로잡혀 멤버변수로 _alpha와 같이 쓰고 있다. 쿠쿠

    

설정

트랙백

댓글

  • 검쉰 2008.09.04 10:50 ADDR 수정/삭제 답글

    앞으로 어떻게 진행될지 흥미진진하네요 ^^;

    • jasu 2008.09.07 23:28 신고 수정/삭제

      좀더 바람직한 방향으로 진행하고 있으니 큰 변화가 있더라도 직접적인 반응 보다는 추구하는 행보에 관심을 두는 것이 좋을 것 같기도 합니다. ^^

  • rhinoa 2008.09.04 23:04 ADDR 수정/삭제 답글

    헤롱헤롱~ 요즘들어 자주 void {} 를 void; {} 이렇게 쓰는 습관이...

    • jasu 2008.09.07 23:32 신고 수정/삭제

      쿠쿠 컴파일 에러의 고마움...

  • 우야꼬  2008.09.05 14:16 신고 ADDR 수정/삭제 답글

    volume = 100 의 귀아픈 기억이... 덜덜;;

    • jasu 2008.09.07 23:34 신고 수정/삭제

      volume은 예전에 클라이언트가 기본 볼륨값으로 적용했음에도 불구하고 소리 크기를 적당하게 해주세요 너무 작아요~ 라는 요구에 원격으로 해결해준 기억이 나네요

      스피커의 볼륨을 키우세요~

  • superSC 2008.09.10 00:04 ADDR 수정/삭제 답글

    저는 .. 반대로..
    as3.0하다가
    as2.0을 부탁 받으면

    뭐시기.x = 100

    이 왜 에러가 나는지 한참 처다본 기억이 있네요.ㅋ

    • jasu 2008.09.11 09:52 신고 수정/삭제

      그렇겠네요 ^^ 변화는 분명 발전하는 것이겠죠

[CS4] Adobe Creative Suite 4 (CS4) 의 발표일 공개

Programming/ActionScript 3.0 2008. 9. 3. 23:11
Adobe 사이트에서 CS4의 발표 일정이 공개되었다. 한국판이 나오기 까지는 한두달 소요될 것으로 예상되지만  영문판이 9월 23일 예정이므로 실질적으로 사용자 컴퓨터에 FlashPlayer10 업데이트가 되는 것은 올해 안으로 50%가 넘지 않을까 싶다.

    

설정

트랙백

댓글

  • ahnsw 2008.09.03 23:20 ADDR 수정/삭제 답글

    드디어 올것이 오는 군요~~ 이번에 회사에서 CS3 라이센스를 추가 구입하는데 조금 기다렸다가 CS4로 요청 해 봐야겠습니다.ㅎㅎㅎ

    • jasu 2008.09.03 23:59 신고 수정/삭제

      만질 수 있는 제품과 만질 수 없는 소프트웨어의 공통점은 새로운 버전이 나오면 현재 가지고 있는 것은 헌것이 되고 새로운 제품은 최첨단이 되는 것이고, 다른 점은 둘다 새로운 것은 갖고 싶지만 쉽게 친해지기 어려운 것은 소프트웨어 인 것 같습니다. ^^ 그래도 설레는 것은 비슷하네요

  • ssen 2008.09.04 08:46 ADDR 수정/삭제 답글

    이번엔 오픈베타 없이 바로 가나보네요. ㅎㅎ 간만에 시끌벅적 해지겠네요.

    • jasu 2008.09.07 23:22 신고 수정/삭제

      기존에 사용하던 클래스들도 속도향상을 위한 방법을 모색해 볼 필요가 있을 것 같네요 환상적인 기능 강화보다는 작게 변화하는 움직임이 더욱 흥분되는 것 같기도...^^

  • lovedev 2008.09.04 10:27 ADDR 수정/삭제 답글

    FLEX4와 함께 Player10이 나오지 않을까하는 생각도 드네요.. :)

    • jasu 2008.09.07 23:24 신고 수정/삭제

      이번에 추가된 새로운 기능이나 텍스트엔진에 따른 변화로 플래시플레이어 버전업도 있을 것으로 보이네요 저도 확실한 정보는 아직 없네요 ^^

  • 검쉰 2008.09.04 10:50 ADDR 수정/삭제 답글

    CS4 가... ㅎㄷㄷ 재미있겠습니다 ㅎ

    • jasu 2008.09.07 23:27 신고 수정/삭제

      툴을 이용한 표현이 어느정도 최적화에 영향을 줄지에 관심이 가네요 개인적으로는 플래시가 화려한 비쥬얼의 장점이 가능 큰 툴이기는 하지만 최적화가 되지 않은 버벅거림은 실용적 가치가 떨어지기에 민감하게 반응하기도 합니다.

[AS3] DigiMix

Programming/ActionScript 3.0 2008. 7. 23. 13:27
http://www.digimix.com/blog/

http://www.digimix.com/alpha/















사용자 삽입 이미지

    

설정

트랙백

댓글

  • Han Sanghun 2008.07.24 09:09 ADDR 수정/삭제 답글

    와우, 이거 장난이 아닌걸.
    대충 뚝딱뚝딱 해서 그럴싸한 노래하나 만들어 버리네.

  • 검쉰 2008.07.25 11:03 신고 ADDR 수정/삭제 답글

    와~ 엄청 신기하네요

  • lovedev 2008.08.07 11:28 신고 ADDR 수정/삭제 답글

    AIR 출시할 때 AIR Developer Derby에서 수상한 Appllication중에 하나에요 ^^;

    정말 대단한거 같아요 :)

[FlashPlayer10] Flash Player 10에서 보완된 기능 리스트

Programming/ActionScript 3.0 2008. 7. 21. 14:55
< 사용자 필터&효과 >

After Effects CS3에서도 사용되고 있는 Adobe Pixel Bender를 사용하여 사용자 필터, 브랜드 모드 등을 작성할 수 있습니다. Pixel Bender는 하이 퍼포먼스 화상 처리 언어입니다. Pixel Bender를 사용하여 Flash Player의 업데이트를 통해서 주어진 효과를 사용하는 것이 아닌 개발자의 독자적인 효과나 필터를 추가할 수 있습니다. 독자적인 효과나 필터는 기존의 Flash Player에 탑재되고 있는 필터와 함께 사용할 수 있습니다. 또 벡터, 비트맵, 비디오 등 모든 오브젝트에 적용할 수 있으며 오브젝트가 가지고 있는 인터랙티브적인 성질은 그대로 유지합니다. 사용자 효과는 런타임으로 적용할 수 있습니다. 또한 사용자 필터의 사이즈는 보통 1KB정도의 파일 사이즈를 갖기 때문에 플래시 콘텐츠의 용량 증가의 문제가 발생하지 않습니다.

 

< 3 차원 3D효과 >

모든 2차원 오브젝트를 3차원 형태로 변형할 수 있습니다. 사용자 필터와 같이 2차원 오브젝트가 가지고 있던 인터랙티브 성질은 그대로 유지됩니다. 기존의 Papervision3D나 Sandy, Away3D를 사용하여 3차원 처리를 고속으로 처리할 수 있습니다. 플래시툴에 기본적으로 제공하는 3차원 변형을 통해서 복잡한 3차원 처리를 간단한 코드로 기술할 수 있습니다.

 

< 새로운 텍스트 엔진 >

새로운 텍스트 엔진은 매우 유연한 텍스트 레이아웃을 제공합니다. 기존에 텍스트, 컨트롤을 통해 새로운 텍스트를 만드는 기술 보완했으며, 사용하기 쉬운 API를 제공합니다. 이로서 다양한 환경에서의 텍스트를 사용할 수 있게 되었습니다. Right-to-Left 식의 세로 형태의 레이아웃 타이포그래피도 지원됩니다.

 

<  텍스트 레이아웃 컴퍼넌트 >

레이아웃과 스타일 텍스트, 테이블, 인라인 이미지, 그리고 열 정렬을 지원합니다. 이로써 신문과 같이 복잡한 테이블 형태를 지원하게 되어 텍스트필드를 다양하게 사용할 수 있게 되었습니다.(기존에는 이러한 텍스트 필드 자체에서 지원되는 기능적 제약이 있어서 디스플레이 오브젝트에서 처리 프로세스를 따로 만들어야 하는 번거로움이 있었다.)

 

< 랜더링 API의 개선 >

기존에 화면처리에서는 특정 shape를 화면에 표시하고자 할 때 기존에 화면상에서 존재하던 그래픽 객체를 지우고 다시 그려야 하는 문제로 인하여 메모리나 성능 면에서 불필요한 시스템 자원을 낭비했었습니다. 이번 버전에서는 그러한 문제점을 보완하기 위해서 특정 shape의 일부분만을 교체할 수 있는 것이 가능하게 되어 메모리와 성능 면에서 효율적으로 처리할 수 있게 되었습니다.

 

< 컬러 관리 >

Flash Player 10은 비교적 정확한 색을 재현할 수 있게 되었다. 컬러 관리에서 swf를 sRGB 색공간(color space)으로 변경가능하며, 컬러 관리는 모니터의 ICC 칼라 프로파일과 동조하여 SWF의 색을 정확하게 재현합니다. 이는 런타임에서 실시간 컬러를 swf에 적용할 수 있습니다.

 

< 시각적인 퍼포먼스 개선 >

기존의 랜더링은 CPU가 모두 처리하였던 것을 GPU를 통해서 처리할 수 있게 되었습니다. 이로써 기존에 CPU처리 만으로 한계가 있던 화면처리 포퍼먼스를 향상시킬 수 있는 길이 열렸습니다. 결과적으로 그래픽 카드(하드웨어가속)을 이용하여 어플리케이션이 보다 매끄러운  반응 속도를 낼 수 있도록 향상되었습니다. (길이 열렸다는 의미는 아직은 GPU를 사용한 최적화에 따른 개발적인 이슈와 그에 대한 개발 가이드가 아직 나와 있지 않은 상태이기 때문이다. 앞으로 개발에 따른 문제점은 보완될 것이라 기대해 본다.)

 

< GPU로의 화상 처리 >

화상을 합성·필터의 적용·비디오의 재생이 보다 빠르게 실시할 수 있게 되었습니다. 모든 래스터 오브젝트는 비디오 카드를 사용해 처리됩니다. 하드웨어로 비트맵, 필터, 비디오를 처리하는 것은 기존의 소프트웨어로 랜더링하던 것보다도 빠르게 재생할 수 있습니다. GPU로 화상 처리하는 것은 HTML 파라미터로 사용 여부를 설정할 수 있으며 하드웨어를 사용할 수 있는 사용자 시스템에서만 적용됩니다. 사용자 하드웨어가 GPU를 사용할 수 없는 경우에는 기존대로 소프트웨어로 처리 합니다. Open GL 2.0으로 GLSL를 지원하고 있는 비디오 카드가 있는 경우에만 이 기능을 사용할 수 있습니다. Flash Player의 베타판에서는  GPU 가속으로 처리되고 있을 때는 좌측 상단에 녹색의 사각이 표시됩니다.

 

< GPU로의 비트맵 전송 >

새로운 HTML 파라미터의 설정을 통해서 SWF를 브라우저에 표시 할 때에 비디오 카드를 사용하도록 할 수 있습니다. 이 기능은 SWF를 새롭게 컴파일 할 필요 없이 사용할 수 있습니다. 이 기능은 Flash Player 9 Update 3으로 도입된 풀 스크린으로의 비디오 표시에 하드웨어 가속화 기능을 확장한 것으로, 랜더링 포퍼먼스가 개선되어 CPU 사용도 효율적으로 관리할 수 있습니다. 결과적으로 비디오나 화상을 사용하는 어플리케이션의 포퍼먼스가 개선됩니다.

 

< Anti-Aliasing 제거 엔진(Saffron 3.1) >

Saffron를 개량하여 특히 아시아권의 언어를 렌더링 할 때의 Anti-Aliasing 제거의 포퍼먼스나 품질이 개선되었습니다. 또 stroke 폰트를 지원하여 필요한 메모리를 경감시켰습니다.

 

< Vector 데이터형 >

Flash Player 10의 ActionScript 3.0에서는 ECMAScript 4를 통해서 제안되고 있는 Vector 데이터형을 지원합니다 .Vector 데이터형은 배열과 비슷하지만 요소가 모두 같은 형태가 아니면 안 되는 제약이 있습니다. 요소의 형태에 제약을 두는 것으로 배열 조작보다 포퍼먼스가 획기적으로 개선되었습니다. (일반 배열을 사용할 때 보다 10배 이상의 속도향상이 기대됨)

 

< 리치 미디어 >

Flash Player 10에서는 다음의 Adobe Flash Media Server나 다른 Adobe 제품으로 제공될 예정인 새로운 오디오·비디오 기능을 탑재했습니다.

 

< 다이나믹스 트리밍 >

네트워크의 상황에 따라 항상 최적인 비디오 품질을 유지하는 것이 가능하게 되었습니다. bit rate를 변화시키는 것을 통해서 비디오가 재생 중에 끊김이 없도록 할 수 있습니다. 이는 비디오 시청자의 대역에 맞는 비디오 전달이 가능하다는 것을 의미합니다. 앞으로 Flash Media Server에서는 네트워크의 상황에 따라 RTMP로의 비디오 전달로 bit rate를 변화시킬 수 있습니다. 리얼타임에 네트워크 상황과 CPU의 상황을 ActionScript로 확인할 수 있으므로 개발자는 그러한 정보를 바탕으로 비디오 전달을 컨트롤 할 수 있습니다. ( 동영상 플레이어로 동영상을 보다가 플레이되는 속도보다 다운로드되는 속도가 느릴 경우 중간에 버퍼링 시간으로 딜레이 되는 것을 개선할 수 있다는 의미)

 

< RTMFP (Real Time Media Flow Protocol) >

RTMFP는, 기존의 RTMP over TCP로 가고 있던 시큐어인 데이터 전달을 UDP로 실시하는 것입니다.이 기능을 이용하기 위해서는 앞으로 릴리스 되는 Flash Media Server나, 다른 Adobe 제품을 사용할 필요가 있습니다. UDP는 영상 전달을 위한 효율적인 프로토콜입니다. RTMFP로의 통신은 암호화를 위해서 영상을 보호할 수 있습니다. 이 기술은 2006년에 매수한 Amicima, Inc.에 의하는 것입니다 .

 

< File Reference runtime access >

Flash Player 9에서도 FileReference를 사용해서 로컬 파일에 액세스 하는 것은 가능합니다만 이 기능은 파일의 업 로드/다운로드를 수행하기 위한 것으로 Flash 어플리케이션에서는 일단 서버를 경유하지 않으면 로컬 파일의 데이터를 사용할 수가 없었습니다. 하지만 Flash Player 10에서는 파일의 읽고 쓰기를 위해서 서버를 사용할 필요가 없이 플래시 어플리케이션에서 읽어 들인 데이터를 바로 사용할 수 있게 되었습니다.

 

Flash Player 10의 flash.net.FileReference 클래스에 추가된 API

public function get data():ByteArray // 읽힌 데이터 (독해 전용의 프롭퍼티)

public function load():void          // 지정된 파일의 읽기 개시

public function save(data:*, name:String = null):void  // 저장처를 선택하는 다이얼로그를 표시, 그 후 데이터 저장

 

 

< 다이나믹 사운드 제너레이션 >

사운드 클래스는 사운드 오브젝트에 등록된 이벤트 리스너를 통하여 동적으로 생성된 오디오를 재생 가능하게 되었습니다.

 

< Large Bitmap Support >

Flash Player 10에서는 기존에 2880 x 2880픽셀로 제한했던 비트맵 최대 사이즈를16,777,216 픽셀(4096×4096 픽셀)까지 비트맵을 취급할 수 있게 되었습니다. (AIR를 통해서 듀얼 모니터에서 스트린캡쳐한 비트맵 데이터를 가공할 때 2880 사이즈를 벗어나 생겼던 에러로 고민한 적이 있는데 이를 통해서 쉽게 해결되었다.)

 

< context menu >

context menu용 ActionScript API를 사용하여 context menu를 좀더 자유롭게 제어가 가능하게 되었습니다. 표준 텍스트와 리치 텍스트의 양쪽 모두를 지원하고 있습니다. 클립보드 메뉴를 통해서 안전하게 제어된 방법으로 클립보드에 액세스 할 수 있으므로 텍스트의 페이스트용 핸들러를 쓸 수도 있습니다.

 

http://labs.adobe.com/technologies/flashplayer10/releasenotes.html


 

 

    

설정

트랙백

댓글

  • rhinoa 2008.07.22 02:44 ADDR 수정/삭제 답글

    좋은 기능들이 많이 늘어났네요.

    GPU 와 텍스트 레이아웃, 파일레퍼런스쪽 등..

    써보면 알겠죠 ㅎㅎ

    글좀 퍼갈께요

    • jasu 2008.07.23 13:31 신고 수정/삭제

      ㅇㅇ AS3 버전업이 안되고 추가 기능으로 제공이 되는터라 약간 혼돈이 기존 결과물들과 약간 혼돈이 올수도...

  • victim4@gmail.com 2008.07.23 18:01 ADDR 수정/삭제 답글

    와 너무 이쁘게 정리 잘해주셨네용~
    감사감사

  • 인민군 2008.08.06 14:30 ADDR 수정/삭제 답글

    잘 봤습니다.
    글좀 퍼가도 되나요? ^^

  • 블루메탈 2008.08.21 01:58 ADDR 수정/삭제 답글

    잘 정리해 주셨네요 퍼갑니다^^

[AS3] Andre Michelle의 AudioTool

Programming/ActionScript 3.0 2008. 7. 8. 23:03
요즘 Andre Michelle이 음향 관련 놀이를 자주 한다는 생각을 했는데 결국 이런 멋진 결과물을 만들어 냈다. 오디오나 음향 관련 지식이 부족한 나에게 이걸 가지고 놀아보라고 하면 아마도 헬리콥터 장난감을 물 속에서 가지고 놀지 싶다. 플래시와 자바를 가지고 개발 했다고 하는데 앙드레의 고집스런 뚝심을 따라가려면 아직도 멀었다는 생각이 든다.










사용자 삽입 이미지

http://www.hobnox.com/index.1056.en.html
    

설정

트랙백

댓글

  • Han Sanghun 2008.07.15 08:42 ADDR 수정/삭제 답글

    앙드레, 넌 어느 별에서왔니???

    • jasu 2008.07.19 22:05 신고 수정/삭제

      b612호 머나먼 이국 땅에서 살고 있다지요 ^^ 시작이 반이라고 하는데 목표는 시작의 반일거라는 생각이 드네요 일단 목표를 정하면 시작은 이미 반을 했으니 나머지 반만 채우면 시작의 반은 이미 달성하지 않을까 싶어요... 저도 주섬주섬 찾아봐야겠네요 ^^

[Flash Player10] 의 GPU 서포트 기능에 관하여...

Programming/ActionScript 3.0 2008. 5. 24. 12:27
Flash Player10 의 GPU 서포트에 대해 Flash Player 팀의 스페셜리스트 Tinic이 blog에서 설명하고 있다.(What does GPU acceleration mean?)

Flash Player10에서는 direct 와 gpu 모드가 새롭게 추가된다.

•    direct 모드 : 화면에 최단 패스로 표시 하고 싶을 때에 사용한다.이 모드에서는 브라우저가 표시하는 영역과 Flash Player의 표시 영역이 겹쳐도 대체로 브라우저 측이 무시된다고 한다. 주로 비디오 재생에서 사용될 것으로 보인다.
•    gpu 모드 : 그래픽 카드의 기능을 이용해 오브젝트의 합성을 실시한다. 대부분의 무비 클립의 랜더링은 기존의 방식대로 소프트웨어가 처리한다.
이러한 GPU 서포트 모드를 이용하기 전에 우선 아래와 같은 사항을 주의해야 한다고 한다.
그래픽 카드의 기능을 사용했다고 반드시 랜더링이 빨리 되는 것은 아니다. 오히려 늦어지는 경우가 더 많을 가능성도 있다고 한다. GPU의 효과를 끌어 내려면 컨텐츠를 디자인할 때 GPU의 동작을 이해해 거기에 맞추어 설계할 필요가 있다고 한다. 그것을 위한 정보나 전용의 가이드는 가능한 한 빠른 시기에 제공할 수 있도록 할 것이라고 이야기 한다.

flashPlayer10에서는 아직은 시작 단계인 기능들이 새롭게 추가되고 있다. GPU기능은 아직은 시기상조이지만 앞으로 플래시의 성능을 높이는데 큰 역할을 할 것이라 본다. FileReference 또한 플래시가 서버와의 통신에 제한적이었던 부분을 좀더 자유로운 개발이 가능하도록 하고 있다.

New Text Engine이나 Text Layout Components 들은 html상의 레이아웃을 플래시 안에서 TextField로 구현이 가능할 것으로 본다. 다만 한글의 경우도 제대로 표현되기를 바란다.

이러한 성능의 발전 방향을 볼때 앞으로 플래시가 온라인과 오프라인의 경계를 무너뜨리는 크로스어플리케이션을 만드는 프로그래밍 언어의 중심이 될 수 있을 것으로 본다.
    

설정

트랙백

댓글

  • 우야꼬  2008.05.26 11:59 신고 ADDR 수정/삭제 답글

    Vector 클래스가 저에겐 가뭄의 단비 같은 존재 같아용.
    배열 객체 가져다 쓸때 타입 캐스팅도 은근히 CPU 먹던데 넘 좋아용^^

    제가 GPU 랑 DIRECT 써봤는데
    DIRECT 는 약간 느려지긴 했는데
    GPU 는 겁나 느려지더라구요;; 약 30% 정도 느려지는듯 했어요;;
    대부분의 무비클립이 해당하지 않는다면
    도대체 어떤 부분이 해택을 받을지 궁금해지네요.

    • jasu 2008.05.26 12:32 신고 수정/삭제

      속도 면에서 Vector이 큰 역할을 할 것 같기는 한데 사용 방법이 약간 ActionScript와 어울리지 않는 형식인 듯 싶어요 아무튼 짜도짜도 더이상 줄일 수 없던 속도를 높일 수 있다는 것은 참 반가운 일인 듯 싶네요 GPU는 어느정도 개발 가이드가 나와야 하지 않을까 싶네요 대부분의 무비클립이라는 의미가 dynamic 형들을 의미하는 것이 아닐까 싶기도 하네요 일단 시작 단계인듯 하니 어느정도 방향성은 잡은 듯 싶어서 반갑네요 ^^

  • 좋네요 2008.06.20 15:54 ADDR 수정/삭제 답글

    좋네요...

[AS3] TweenMax Bezier Tweening Released by Jack

Programming/ActionScript 3.0 2008. 4. 6. 21:33
TweenLite와 TweenFilterLite를 만들었던 jack이 이번에 TweenMax를 릴리즈하였다. 이번 TweenMax에서는 bezier 곡선을 지원한다.

http://blog.greensock.com/tweenmaxas3/


Tweener와 속도 비교해보면 많은 오브젝트를 tween 시킬 때의 속도 차이를 느낄 수 있다.

http://blog.greensock.com/bezier-speed-test/
    

설정

트랙백

댓글

[AS3] FlashPlayer UPDATE3의 System.gc()

Programming/ActionScript 3.0 2008. 2. 9. 22:52
예전에 System.gc 내장 함수가 없었던 것으로 알고 있는데 업데이트 버전에서 생겨난 듯 하다. 기존에는 개발자가 강제로 CG를 실행시킬 수 없어서 완전한 메모리 테스트는 사실상 불가능 했다. 물론 강제로 많은 오브젝트를 생성하는 과정에서 일정한 메모리(FlashPlayer가 예상하는 적정 사용영역)을 벗어날 경우를 임의로 만들어서 확인할 수는 있었으나 이것 또한 어느 정도의 메모리 영역을 CG가 동작하는 시작점으로 보는가를 알 수 없기 때문에 어려움이 있었다.

System 클래스에서 지원하는 메소드에 gc가 있다. 이는 자바에서의 System.gc와 같이 이 함수를 실행하는 시점에서 강제로 CG가 동작하게 된다. 문제는 자바와 같이 플래시도 full gc를 할 경우 시스템 리소스 낭비가 예상된다는 것이다. System.gc 실행은 개발 테스트 과정에서 사용하되 작업물에서의 동적인 강제 실행은 피하는 것이 좋을 듯 싶으나 이는 이미 웹상에서는 System.gc가 작동하지 않는 듯 싶다. 경험상 flashPlayer9버전의 가비지콜렉터는 상당히 안정적이고 신뢰 할만 하다.

아래 예제로 만든 것을 보면 replay 버튼을 누름과 동시에 Event.ENTER_FRAME 이벤트가 등록된 sprite를 통해서 이벤트가 발생할 때마다 임의로 TextField를 생성과 소멸을 반복한다. 50개의 TextField가 생성되는 시점에서 Event.ENTER_FRAME가 등록된 sprite를 메모리해서 해제시킨다.

여기서 많은 개발자들이 Event.ENTER_FRAME 이벤트가 적용된 상태에서 removeEventListener로 이벤트를 해제하지 않고 sprite를 메모리 해제 시도를 했기 때문에 메모리에서 지워지지 않는다고 생각하는 듯 하다. 나도 예전에는 이 부분이 상당히 모호했다.  addEventListener로 강참조를 할 경우라도 역참조가 아닌 이상은 이벤트가 적용된 오브젝트가 메모리에서 해제하고 GC를 통해서 free memory가 되면 자동으로 등록되어 있는 이벤트도 발생하지 않는다.

여기서 혼돈했던 이유는 개발자가 강제로 가비지콜렉션을 실행하지 못하는 상황에서 sprite가 메모리에서 해제되지 않아서 이벤트가 계속 발생하는 것인지, gc가 동작하지 않아서 해제되지 않는 것인지 모호했기 때문이다.

아래의 예제에서 gc 동작버튼을 누르지 않더라도 일정한 시간이 지나면 flashplayer가 적당한 시점에서 gc를 가동하여 Event.ENTER_FRAME 이벤트가 등록된 sprite를 메모리에서 해제하면서 Event.ENTER_FRAME 이벤트도 발생하지 않게 된다. System.gc를 이러한 gc의 동작을 강제로 실행하므로써 개발자에게 즉시 free memory가 되었다는 것을 알려주므로 개발과정에서 요긴하게 사용될 듯싶다.

아래 swf상에서는 System.gc 함수가 실행되지 않는다. fla를 다운로드하여 로컬상에서 테스트 해보길 바란다.




    

설정

트랙백

댓글

  • 우야꼬  2008.03.03 21:28 신고 ADDR 수정/삭제 답글

    저도 테스트를 한번 해봤는데
    메모리가 줄어들더군요.

    한번 같이 봐주셨음 좋겠어요.

    코드는

    var txt: TextField = new TextField();
    addChild( txt );

    var loop: int = 50000;

    txt.text += System.totalMemory.toString() + "\n";

    while( loop-- )
    new Sprite();


    txt.text += System.totalMemory.toString() + "\n";

    System.gc();

    txt.text += System.totalMemory.toString() + "\n";

    링크는 http://www.as3.kr/gc2/ 입니다.

    • 우야꼬  2008.03.04 22:37 신고 수정/삭제

      디버거용 FPlayer 에서만 되는걸로 확인 됐네요.
      앞으로는 테스트할때 주의해야겠어요.
      당연한 건데 말이죠^^

  • 미나토 2008.03.04 11:35 ADDR 수정/삭제 답글

    웹에서는 안되고 로컬에서는 된다라.... 그렇다면 로컬에서 실행하게 될 air 에서는 사용가능하다는 얘기???

    좋은 정보 감사합니다 :)

  • 임대찬 2008.03.04 11:51 ADDR 수정/삭제 답글

    웹에서도 제대로 되는거 같은데요.

[AS3] Tween Engine (TweenLite)

Programming/ActionScript 3.0 2008. 2. 5. 19:28
TweenBencher 을 이용해서 AS3용 Tween 엔진을 테스트 해 봤다. 1등은 단연 Simple AS3 Tween으로 나왔는데 이것은 따로 클래스화 되어 있는 것이 아니고 fl.motion.easing.Exponential 의 easeInOut 함수만을 따로 빼서 직접 width을 적용한 형태라서 빠를 수 밖에 없다. 테스트를 하지 않은 fl 기본 트윈 클래스나 기타 다른 것들은 비교할만한 속도를 내지 못하여 제외 하였다.

비교 대상이 되는 것들은 Tweener TweenLite이다. Tweener은 그 사용법과 Bezier 곡선 처리 기능을 제공하기 때문에 사용성면에서 좋은 엔진이지만 많은 기능들이 포함되어 있는 만큼 속도는 약간 떨어진다.








Benchmark results: Simple AS3 Tween
------------------
125 Sprites    ::    Start Lag: 0 seconds    ::    FPS: 57
250 Sprites    ::    Start Lag: 0 seconds    ::    FPS: 57
500 Sprites    ::    Start Lag: 0 seconds    ::    FPS: 55
1000 Sprites    ::    Start Lag: 0 seconds    ::    FPS: 47
2000 Sprites    ::    Start Lag: 0.01 seconds    ::    FPS: 38
4000 Sprites    ::    Start Lag: 0.06 seconds    ::    FPS: 26

Benchmark results: TweenLite
------------------
125 Sprites    ::    Start Lag: 0 seconds    ::    FPS: 61
250 Sprites    ::    Start Lag: 0 seconds    ::    FPS: 55
500 Sprites    ::    Start Lag: 0.01 seconds    ::    FPS: 40
1000 Sprites    ::    Start Lag: 0.01 seconds    ::    FPS: 31
2000 Sprites    ::    Start Lag: 0.02 seconds    ::    FPS: 23
4000 Sprites    ::    Start Lag: 0.18 seconds    ::    FPS: 19

Benchmark results: Tweener
------------------
125 Sprites    ::    Start Lag: 0.11 seconds    ::    FPS: 56
250 Sprites    ::    Start Lag: 0.02 seconds    ::    FPS: 61
500 Sprites    ::    Start Lag: 0.06 seconds    ::    FPS: 46
1000 Sprites    ::    Start Lag: 0.2 seconds    ::    FPS: 33
2000 Sprites    ::    Start Lag: 0.45 seconds    ::    FPS: 25
4000 Sprites    ::    Start Lag: 1.4 seconds    ::    FPS: 17

TweenLite는 filter에 관련된 기능들은 TweenFilterLite로 따로 빠져있다. 특별한 기능이 아닌 오브젝트의 모션 처리는 x,y,scaleX, scaleY, width, height, alpha 등과 추가하면 color 적용일 것이다. TweenLite는 tint 속성으로 그것을 대신하고 있다. 기본적인 사용법은 아래와 같다.

import gs.TweenLite;
TweenLite.to(mc, 1, {x:46, y:43, scaleX:1, scaleY:1, rotation:0, alpha:1, tint:0x3399ff});

사용법이 Tweener와 많은 부분 흡사하다. mc는 타겟이되는 Object, 1은 모션 time이고 {} 오브젝트 형태로 적용 속성들과 모션 함수를 적용할 수가 있다. ease 속성으로 모션 함수를 적용할 수가 있는데 함수는 fl.motion.easing 패키지 안에 있는 함수를 적용하게 되므로 fl.motion.easing 패키지를 import 시켜서 사용하면 된다. 그리고 Tweener에서와 같이 onStart, onUpdate, onComplete 를 지원한다. 아래 예,

        import gs.TweenLite;
        import fl.motion.easing.Back;
        TweenLite.to(mc, 5, {alpha:0.5, x:120, ease:Back.easeOut, delay:2,
                                        onComplete:onFinishTween, onCompleteParams:[5, clip_mc]});
        function onFinishTween(argument1:Number, argument2:MovieClip):void {
                trace("The tween has finished! argument1 = " + argument1 + ",
                and argument2 = " + argument2);
        }



USAGE

TweenLite.to(target:Object, duration:Number, variables:Object);

  • Description: Tweens the target's properties from whatever they are at the time you call the method to whatever you define in the variables parameter.
  • Parameters:
    1. target: Target MovieClip (or any object) whose properties we're tweening
    2. duration: Duration (in seconds) of the tween
    3. variables: An object containing the end values of all the properties you'd like to have tweened (or if you're using the TweenLite.from() method, these variables would define the BEGINNING values). Putting quotes around values will make the tween relative to the current value. For example, x:"-20" will tween x to whatever it currently is minus 20 whereas x:-20 will tween x to exactly -20. Here are some examples of properties you might include:
      • alpha: The alpha (opacity level) that the target object should finish at (or begin at if you're using TweenLite.from()). For example, if the target.alpha is 1 when this script is called, and you specify this parameter to be 0.5, it'll transition from 1 to 0.5.
      • x: To change a MovieClip's x position, just set this to the value you'd like the MovieClip to end up at (or begin at if you're using TweenLite.from()).

      Special Properties (**Optional**):

      • delay: The number of seconds you'd like to delay before the tween begins. This is very useful when sequencing tweens
      • ease: You can specify a function to use for the easing with this variable. For example, fl.motion.easing.Elastic.easeOut. The Default is Regular.easeOut.
      • easeParams: An array of extra parameter values to feed the easing equation. This can be useful when you use an equation like Elastic and want to control extra parameters like the amplitude and period. Most easing equations, however, don't require extra parameters so you won't need to pass in any easeParams.
      • autoAlpha: Same as changing the "alpha" property but with the additional feature of toggling the "visible" property to false if the alpha ends at 0. It will also toggle visible to true before the tween starts if the value of autoAlpha is greater than zero.
      • volume: To change a MovieClip's volume, just set this to the value you'd like the MovieClip to end up at (or begin at if you're using TweenLite.from()).
      • tint: To change a MovieClip's color, set this to the hex value of the color you'd like the MovieClip to end up at(or begin at if you're using TweenLite.from()). An example hex value would be 0xFF0000. If you'd like to remove the color from a MovieClip, just pass null as the value of tint. Before version 5.8, tint was called mcColor (which is now deprecated and will likely be removed at a later date although it still works)
      • onStart: If you'd like to call a function as soon as the tween begins, pass in a reference to it here. This can be useful when there's a delay and you want something to happen just as the tween begins.
      • onStartParams: An array of parameters to pass the onStart function.
      • onUpdate: If you'd like to call a function every time the property values are updated (on every frame during the time the tween is active), pass a reference to it here.
      • onUpdateParams: An array of parameters to pass the onUpdate function (this is optional)
      • onComplete: If you'd like to call a function when the tween has finished, use this.
      • onCompleteParams: An array of parameters to pass the onComplete function (this is optional)
      • overwrite: If you do NOT want the tween to automatically overwrite any other tweens that are affecting the same target, make sure this value is false.




TweenLite.from(target:Object, duration:Number, variables:Object);

  • Description: Exactly the same as TweenLite.to(), but instead of tweening the properties from where they're at currently to whatever you define, this tweens them the opposite way - from where you define TO where ever they are now (when the method is called). This is handy for when things are set up on the stage where the should end up and you just want to animate them into place.
  • Parameters: Same as TweenLite.to(). (see above)




TweenLite.delayedCall(delay:Number, onComplete:Function, onCompleteParams:Array);

  • Description: Provides an easy way to call any function after a specified number of seconds. Any number of parameters can be passed to that function when it's called too.
  • Parameters:
    1. delay: Number of seconds before the function should be called.
    2. onComplete: The function to call
    3. onCompleteParams [optional] An array of parameters to pass the onComplete function when it's called.




TweenLite.killTweensOf(target:Object, complete:Boolean);

  • Description: Provides an easy way to kill all tweens of a particular Object/MovieClip. You can optionally force it to immediately complete (which will also call the onComplete function if you defined one)
  • Parameters:
    1. target: Any/All tweens of this Object/MovieClip will be killed.
    2. complete: If true, the tweens for this object will immediately complete (go to the ending values and call the onComplete function if you defined one).




TweenLite.killDelayedCallsTo(function:Function);

  • Description: Provides an easy way to kill all delayed calls to a particular function (ones that were instantiated using the TweenLite.delayedCall() method).
  • Parameters:
    1. function: Any/All delayed calls to this function will be killed.


EXAMPLES


As a simple example, you could tween the alpha to 50% (0.5) and move the x position of a MovieClip named "clip_mc" to 120 and fade the volume to 0 over the course of 1.5 seconds like so:
  1. import gs.TweenLite;
  2. TweenLite.to(clip_mc, 1.5, {alpha:0.5, x:120, volume:0});



If you want to get more advanced and tween the clip_mc MovieClip over 5 seconds, changing the alpha to 50% (0.5), the x coordinate to 120 using the Back.easeOut easing function, delay starting the whole tween by 2 seconds, and then call a function named "onFinishTween" when it has completed and pass in a few parameters to that function (a value of 5 and a reference to the clip_mc), you'd do so like:
  1. import gs.TweenLite;
  2. import fl.motion.easing.Back;
  3. TweenLite.to(clip_mc, 5, {alpha:0.5, x:120, ease:Back.easeOut, delay:2, onComplete:onFinishTween, onCompleteParams:[5, clip_mc]});
  4. function onFinishTween(parameter1_num:Number, parameter2_mc:MovieClip):void {
  5.     trace("The tween has finished! parameters: " + parameter1_num + ", and " + parameter2_mc);
  6. }


If you have a MovieClip on the stage that is already in its end position and you just want to animate it into place over 5 seconds (drop it into place by changing its y property to 100 pixels higher on the screen and dropping it from there), you could:
  1. import gs.TweenLite;
  2. import fl.motion.easing.Elastic;
  3. TweenLite.from(clip_mc, 5, {y:"-100", ease:Elastic.easeOut});

FAQ

  1. Can I set up a sequence of tweens so that they occur one after the other?
    Of course! Just use the delay property and make sure you set the overwrite property to false (otherwise tweens of the same object will always overwrite each other to avoid conflicts). Here's an example where we colorize a MovieClip red over the course of 2 seconds, and then move it to a _y coordinate of 300 over the course of 1 second:
    1. import gs.TweenLite;
    2. TweenLite.to(clip_mc, 2, {tint:0xFF0000});
    3. TweenLite.to(clip_mc, 1, {y:300, delay:2, overwrite:false});

  2. Do the properties have to be in a specific order?
    Nope. The only thing that matters is that the first parameter is the object you're tweening, the second parameter is the time (in seconds), and the third parameter contains all the properties you want to tween (in any order). So TweenLite.to(clip_mc, 1, {scaleX:120, y:200, x:1}) is the same as TweenLite.to(clip_mc, 1, {x:1, y:200, scaleX:120});

  3. Why are TweenLite and TweenFilterLite split into 2 classes instead of building all the functionality into one class?
    1. File size. Only a portion of projects out there require tweening of filters. Almost every project I work on uses TweenLite, but only a few require tweening filters (TweenFilterLite). TweenLite is 2k whereas TweenFilterLite is 5k. Again, one of the stated purposes of TweenLite is to minimize file size & code bloat. If someone only wants to use TweenFilterLite, fine. But I think many people appreciate being able to use the most lightweight option for their needs and shave off the 3k when possible.
    2. Speed. Tweening filters is a more complex task. There are additional if/else statements and calculations in the rendering loop inside TweenFilterLite which could potentially slow things down a bit, even for non-filter tweens (I doubt anyone would notice a difference unless they’re running hundreds or thousands of simultaneous tweens, but I’m a big fan of keeping things as efficient & fast as possible)

  4. Do I have to pay for a license to use this code? Can I use it for commercial purposes?
    Feel free to take the code and use it as you wish, even for commercial purposes. Some people have requested the ability to donate money to reward the work I put into the class(es), so i put a PayPal "donate now" button at the top and bottom of the page, but you certainly don't need to donate anything. I'm just glad to help the Flash community.

  5. Are TweenLite and TweenFilterLite better than Tweener, Fuse, MC Tween, and all the other tweening engines out there?
    Maybe, maybe not. It all depends on your objectives, coding style, etc. I certainly don't claim that TweenLite & TweenFilterLite are superior to all other tweening engines, but in terms of the power-to-file-size ratio, I certainly haven't seen anything that comes close. Feedback has been overwhelmingly positive. I've used TweenLite for many years and it hasn't let me down. I never found myself needing features that are available in another tweening engine. But hey, to each his own.


OBJECTIVES

  • Minimize file size
  • Maximize flexibility and efficiency by extending the TweenLite class. That way, if you don't need to tween filters, you can just use TweenLite (about 2k); otherwise, this class will only add another 3k (5k total)
  • Minimize the amount of code required to initiate a tween
  • Maximize performance
  • Allow for very flexible callbacks (onComplete, onUpdate, onStart, all with the ability to pass any number of parameters)

FITLERS & PROPERTIES:

  • type:"Blur" -
    blurX, blurY, quality
  • type:"Glow" -
    alpha, blurX, blurY, color, strength, quality
  • type:"Color" -
    colorize, amount, contrast, brightness, saturation, hue, threshold, relative
  • type:"DropShadow" -
    alpha, angle, blurX, blurY, color, distance, strength, quality
  • type:"Bevel" -
    angle, blurX, blurY, distance, highlightAlpha, highlightColor, shadowAlpha, shadowColor, strength, quality

USAGE

TweenFilterLite.to(target:DisplayObject, duration:Number, variables:Object);

  • Description: Tweens the target's properties from whatever they are at the time you call the method to whatever you define in the variables parameter.
  • Parameters:
    1. target: Target DisplayObject whose properties we're tweening
    2. duration: Duration (in seconds) of the tween
    3. variables: An object containing the end values of all the properties you'd like to have tweened (or if you're using the TweenFilterLite.from() method, these variables would define the BEGINNING values). Putting quotes around values will make the tween relative to the current value. For example, x:"-20" will tween x to whatever it currently is minus 20 whereas x:-20 will tween x to exactly -20. Here are some examples of properties you might include:
      • blurX
      • blurY
      • color: An example for red would be 0xFF0000. Several filters use this property, like DropShadow and Glow
      • colorize: Only used with a type:"Color" tween to colorize an entire MovieClip.
      • amount: Only used to control the amount of colorization.

      Special Properties:

      • type: REQUIRED. A string that indicates what type of filter you're tweening. Possible values are: "Color" (for all image effects like colorize, brightness, contrast, saturation, and threshold), "Blur", "Glow", "DropShadow", or "Bevel"
      • delay: Number of seconds to delay before the tween begins. This can be very useful when sequencing tweens.
      • ease: You can specify a function to use for the easing with this variable. For example, fl.motion.easing.Elastic.easeOut. The Default is Regular.easeOut.
      • easeParams: An array of extra parameter values to feed the easing equation. This can be useful when you use an equation like Elastic and want to control extra parameters like the amplitude and period. Most easing equations, however, don't require extra parameters so you won't need to pass in any easeParams.
      • autoAlpha: Same as changing the "alpha" property but with the additional feature of toggling the "visible" property to false if the alpha ends at 0. It will also toggle visible to true before the tween starts if the value of autoAlpha is greater than zero.
      • volume: To change a MovieClip's volume, just set this to the value you'd like the MovieClip to end up at (or begin at if you're using TweenFilterLite.from()).
      • tint:To change a MovieClip's color, set this to the hex value of the color you'd like the MovieClip to end up at(or begin at if you're using TweenLite.from()). An example hex value would be 0xFF0000. If you'd like to remove the color from a MovieClip, just pass null as the value of tint. Before version 5.8, tint was called mcColor (which is now deprecated and will likely be removed at a later date although it still works)
      • onStart: If you'd like to call a function as soon as the tween begins, pass in a reference to it here. This can be useful when there's a delay and you want something to happen just as the tween begins.
      • onStartParams: An array of parameters to pass the onStart function.
      • onUpdate: If you'd like to call a function every time the property values are updated (on every frame during the time the tween is active), pass a reference to it here.
      • onUpdateParams: An array of parameters to pass the onUpdate function (this is optional)
      • onComplete: If you'd like to call a function when the tween has finished, use this.
      • onCompleteParams: An array of parameters to pass the onComplete function (this is optional)
      • overwrite: If you do NOT want the tween to automatically overwrite any other tweens that are affecting the same target, make sure this value is false.



TweenFilterLite.from(target:DisplayObject, duration:Number, variables:Object);

  • Description: Exactly the same as TweenFilterLite.to(), but instead of tweening the properties from where they're at currently to whatever you define, this tweens them the opposite way - from where you define TO where ever they are now (when the method is called). This is handy for when things are set up on the stage the way the should end up and you just want to tween them to where they are.
  • Parameters: Same as TweenFilterLite.to(). (see above)



TweenLite.delayedCall(delay:Number, onComplete:Function, onCompleteParams:Array);

  • Description: Provides an easy way to call any function after a specified number of seconds. Any number of parameters can be passed to that function when it's called too.
  • Parameters:
    1. delay: Number of seconds before the function should be called.
    2. onComplete: The function to call
    3. onCompleteParams [optional] An array of parameters to pass the onComplete function when it's called.




TweenFilterLite.killTweensOf(target:Object, complete:Boolean);

  • Description: Provides an easy way to kill all tweens of a particular Object/MovieClip. You can optionally force it to immediately complete (which will also call the onComplete function if you defined one)
  • Parameters:
    1. target: Any/All tweens of this Object/MovieClip will be killed.
    2. complete: If true, the tweens for this object will immediately complete (go to the ending values and call the onComplete function if you defined one).




TweenFilterLite.killDelayedCallsTo(function:Function);

  • Description: Provides an easy way to kill all delayed calls to a particular function (ones that were instantiated using the TweenFilterLite.delayedCall() method).
  • Parameters:
    1. function: Any/All delayed calls to this function will be killed.


EXAMPLES

As a simple example, you could tween the blur of clip_mc from where it's at now to 20 over the course of 1.5 seconds by:
  1. import gs.TweenFilterLite;
  2. TweenFilterLite.to(clip_mc, 1.5, {type:"Blur", blurX:20, blurY:20});

If you want to get more advanced and tween the clip_mc MovieClip over 5 seconds, changing the saturation to 0, delay starting the whole tween by 2 seconds, and then call a function named "onFinishTween" when it has completed and pass in a few arguments to that function (a value of 5 and a reference to the clip_mc), you'd do so like:
  1. import gs.TweenFilterLite;
  2. import fl.motion.easing.Back;
  3. TweenFilterLite.to(clip_mc, 5, {type:"Color", saturation:0, delay:2, onComplete:onFinishTween, onCompleteParams:[5, clip_mc]});
  4. function onFinishTween(argument1_num:Number, argument2_mc:MovieClip):void {
  5.     trace("The tween has finished! argument1_num = " + argument1_num + ", and argument2_mc = " + argument2_mc);
  6. }
If you have a MovieClip on the stage that already has the properties you'd like to end at, and you'd like to start with a colorized version (red: 0xFF0000) and tween to the current properties, you could:
  1. import gs.TweenFilterLite;
  2. TweenFilterLite.from(clip_mc, 5, {type:"color", colorize:0xFF0000});

FAQ

  1. Can I set up a sequence of tweens so that they occur one after the other?
    Of course! Just use the delay property and make sure you set the overwrite property to false (otherwise tweens of the same object will always overwrite each other to avoid conflicts). Here's an example where we colorize a MovieClip red over the course of 2 seconds, and then blur it over the course of 1 second:
    1. import gs.TweenFilterLite;
    2. TweenFilterLite.to(clip_mc, 2, {type:"color", colorize:0xFF0000, amount:1});
    3. TweenFilterLite.to(clip_mc, 1, {type:"blur", blurX:20, blurY:20, delay:2, overwrite:false});

  2. Do the properties have to be in a specific order?
    Nope. The only thing that matters is that the first parameter is the object you're tweening, the second parameter is the time (in seconds), and the third parameter contains all the properties you want to tween (in any order). So TweenFilterLite.to(clip_mc, 1, {type:"color", colorize:0xFF0000, amount:1}) is the same as TweenFilterLite.to(clip_mc, 1, {amount:1, colorize:0xFF0000, type:"color"});

  3. Can I use TweenFilterLite to tween things other than filters?
    Sure. It extends TweenLite, so you can tween any property you want. TweenFilterLite.to(my_mc, 1, {x:200}) gives you the same result as TweenLite.to(my_mc, 1, {x:200}). However, I'd recommend using TweenLite to tween properties other than filters for two reasons:
    1. In order to accommodate the specialized nature of filters, TweenFilterLite's code is a bit lengthier which translates into more work for the processor. It's doubtful that anyone would notice a performance hit unless you're tweening hundreds or thousands of instances simultaneously, but I'm a bit of an efficiency freak.
    2. TweenLite can tween any property of ANY object whereas TweenFilterLite tweens properties of DisplayObjects (like MovieClips, Sprites, etc.)

  4. Why are TweenLite and TweenFilterLite split into 2 classes instead of building all the functionality into one class?
    1. File size. Only a portion of projects out there require tweening of filters. Almost every project I work on uses TweenLite, but only a few require tweening filters (TweenFilterLite). TweenLite is 2k whereas TweenFilterLite is 5k. Again, one of the stated purposes of TweenLite is to minimize file size & code bloat. If someone only wants to use TweenFilterLite, fine. But I think many people appreciate being able to use the most lightweight option for their needs and shave off the 3k when possible.
    2. Speed. Tweening filters is a more complex task. There are additional if/else statements and calculations in the rendering loop inside TweenFilterLite which could potentially slow things down a bit, even for non-filter tweens (I doubt anyone would notice a difference unless they’re running hundreds or thousands of simultaneous tweens, but I’m a big fan of keeping things as efficient & fast as possible)

  5. Do I have to pay for a license to use this code? Can I use it for commercial purposes?
    Feel free to take the code and use it as you wish, even for commercial purposes. Some people have requested the ability to donate money to reward the work I put into the class(es), so i put a PayPal "donate now" button at the top and bottom of the page, but you certainly don't need to donate anything. I'm just glad to help the Flash community.

  6. Are TweenLite and TweenFilterLite better than Tweener, Fuse, MC Tween, and all the other tweening engines out there?
    Maybe, maybe not. It all depends on your objectives, coding style, etc. I certainly don't claim that TweenLite & TweenFilterLite are superior to all other tweening engines, but in terms of the power-to-file-size ratio, I certainly haven't seen anything that comes close. Feedback has been overwhelmingly positive. I've used TweenLite for many years and it has never let me down. I've never found myself needing features that are available in another tweening engine. But hey, to each his own.
    

설정

트랙백

댓글

  • 문군 2008.02.07 11:24 ADDR 수정/삭제 답글

    저도 저번에 요 내용 지인께서 알려주셔서 적용해봤는데 외국에서도 주로 사용하는 방법이라고 하시더라구여^^ 형님이 정리해주시니 이해가 훨씬 잘데네여^^ㅋ 잘봤습니다.~

    • jasu 2008.02.08 20:37 신고 수정/삭제

      플래시의 초창기에도 그렇고 지금도 그렇듯이 플래시에서 모션을 빼면 다분히 매력 없는 툴이 되지 않을까 싶네 포퍼먼스를 생각한다면 타켓이 되는 기능만을 따로 만들어 사용해야 겠지만 과도한 CPU낭비가 아니라면 사용하기 편한 것을 사용하고 그 남는 시간에 다른 부분에 대한 투자를 하는 것이 궁극적인 효율성이 아닐까… ^^

  • 문군 2008.02.09 22:27 ADDR 수정/삭제 답글

    저 역시 플래시 모션의 그 무한한 가능성에 굉장히 꿈을 많이 심고 있고 그러리라 확신한답니다 ^^
    빨리 형님께 먼가 알려드릴수 있는 날이 와야하는데--;;; 가능할런진 잘 모르겠어여^^;

    • jasu 2008.02.09 23:16 신고 수정/삭제

      나 또한 모르는 부분이 많으니 부지런해져야겠지... 부지런함이란 일찍 자고 일찍 일어나는 것이 아니라 정보습득의 부지런함이라는... ^^

[AS3] Linkage 클래스를 필요할때 참조

Programming/ActionScript 3.0 2008. 1. 29. 18:09

















public function getDefinitionByName(name:String):Object

플래시에서의 Public 함수 중에서 getDefinitionByName() 함수는 name 매개 변수로 지정된 클래스의 클래스 객체에 대한 참조를 반환해 준다.

var c:Class = getDefinitionByName("m"+2) as Class;  // 라이브러리에 있는 Linkage 클래스명 "m2"의 참조를 반환한다.

package {
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.utils.getDefinitionByName;

public class GetDefinitionByNameExample extends Sprite {
private var bgColor:uint = 0xFFCC00;
private var size:uint = 80;

public function GetDefinitionByNameExample() {
var ClassReference:Class = getDefinitionByName("
flash.display.Sprite") as Class;
var instance:Object = new ClassReference();
instance.graphics.beginFill(bgColor);
instance.graphics.drawRect(0, 0, size, size);
instance.graphics.endFill();
addChild(DisplayObject(instance));
}
}
}

    

설정

트랙백

댓글

  • Han Sanghun 2008.01.30 00:21 ADDR 수정/삭제 답글

    오~~ 매우 유용한 정보군... 생유

    • jasu 2008.01.30 00:58 신고 수정/삭제

      2.0에서의 attachMovie와 흡사한 기능을 구현하기에 좋을 것 같기는 하지만 동적으로 클래스 참조 객체를 반환하는 과정의 속도 문제는 고민해 볼 필요가 있을 듯 싶어요 속도를 감안한다면 그냥 array에 각각을 넣어두고 참조하는 것이 좋을 것 같기도하고... 회사에서 물어보길래 찾아보니 지원하는 함수가 있더군요...^^

[AS3] getTileColor 메소드를 이용한 이미지

Programming/ActionScript 3.0 2008. 1. 28. 19:11
BitmapData의 일정한 간격의 pixel 컬러를 추축하는 메소드를 작성하고 이미지를 뽑아 보았다. 땡굴이 형님도 비슷한 작업을 진행중인 듯 싶다. 원본 이미지의 사이즈와 상관없이 16x16픽셀 아이콘도 이러한 확대한 결과물을 만들 수 있어서 여러가지로 사용할 수 있을 듯 싶다.

랜덤한 형태에서 좀더 관련이 있는 부분들을 조합하면 불규칙적이지만 규칙이 있는 재질을 만들어 낼 수 있을 듯 싶다.









사용자 삽입 이미지

    

설정

트랙백

댓글

  • 땡굴이 2008.01.29 01:31 ADDR 수정/삭제 답글

    이효. 좋은데구려~ 흐흐. 갑작스런 회사일 스나미 때문에 작업 못하고 있는데..
    암튼 잘 뽑았는걸.. ^^; 은근히 잼있는 걸 만들 수 있을 것 같다는 생각이야..

    • jasu 2008.01.29 02:06 신고 수정/삭제

      ㅎㅎ 구려요? 쿠쿠... 이미지는 나무 가지를 잡고 있는 한 마리 쥐가 위에서 다른 한 마리 다리를 잡고 있고 다리 잡힌 쥐가 꽃을 아래에 있는 쥐에게 주는 장면이랍니다...쿠쿠 믿거나 말거나... 다음 작품 기대할께요~

  • nellun 2008.01.29 12:36 ADDR 수정/삭제 답글

    이말밖에 할말이 없네요

    You are sooooooooooooooooo good!!

    잘보고 갑니다.

    • jasu 2008.01.30 00:51 신고 수정/삭제

      특별한 기능은 없습니다. 이미지 pixel 컬러 축출+랜덤한 오브젝트 생성이에요 단순한기능이지만 생각에 따라서 재미있는 비주얼을 컴퓨터가 만들어 주기도 할 것 같네요 ^^

  • i-coo 2008.02.01 00:35 ADDR 수정/삭제 답글

    멋있어요~

Flickr API UML - as3flickrlib

Programming/ActionScript 3.0 2008. 1. 28. 14:57

Project Page: http://code.google.com/p/as3flickrlib/
Project Group: http://groups.google.com/group/as3flickrlib

위 구글 코드에서 오픈되어 있는 flickr API adobe 소스를 UML로 변환해 보았다. 필요하신 분들은 참고하시면 좋을 듯 싶다. 기본적인 상속과 합성관계만 형성해 놓은 상태, 대부분 합성으로 페키지가 구성되어 있다.

참고. 새벽에 작성한 관계로 틀린 부분이 있을 수 있음.










사용자 삽입 이미지

    

설정

트랙백

댓글

  • namoo 2008.01.30 09:53 ADDR 수정/삭제 답글

    이렇게 방대한 데이터를 일목요연하게 UML 로 정리하시다니.. 정말 대단합니다 ^^;;
    자수님 블로그 오면 배울게 많네요~ 혹시 어떤 UML tool 을 쓰시는지도 알수 있을까요?

    • jasu 2008.01.30 13:42 신고 수정/삭제

      api 패키지를 테스트하면서 머리 속에 정리가 되지 않아서 만든 자료입니다. 정리만 몇 시간 걸린 것 같네요 제가 사용한 툴은 starUML입니다. http://staruml.sourceforge.net/ko/index.php
      여기서 다운로드 하실 수 있고 오픈소스입니다. 오픈소스 UML툴이지만 기본적인 기능들이 충실하고 가벼워서 유료프로그램 못지않은 것 같다는 생각이 드네요 원 뿌리는 예전 플라스틱 UML로 판매를 하다가 오픈 소스로 전환된 것으로 알고 있습니다. 클래스 다이어그램을 생성하면 프로젝트 참여자들의 이름이 디폴트로 나옵니다. 이것 말고도 argouml이라는 툴도 있는데 이 툴에서는 ActionScript 3.0을 지원하기 위해 프로젝트가 진행중인 것으로 알고 있습니다. ActionScript를 지원해주는 uml툴이 마땅치 않아서 수작업으로 만들고 있는데 머지 않아서 패키지 소스를 그대로 uml로 변환해 주거나 uml 다이어그램을 그대로 ActionScript로 generate 해 준다면 편리해 질 것 같네요 ^^
      이 자료는 클래스 구조를 편하게 보기 위해서 만든 자료이니만큼 참고만 하시면 좋을 듯 싶습니다.

  • namoo 2008.01.30 16:17 ADDR 수정/삭제 답글

    친절하고 상세한 답변 감사합니다 ^^; starUML 은 저도 들어본것 같네요. Air 기반의 Saffron UML이 개발되고 있다는 얘기는 들었는데, ActionScript 전용 UML 이 나온다면 플래시나 air 개발자들에게 큰 도움이 될것 같네요~ 그럼 즐거운 하루되시길..

Wise를 확장한 SimpleFanwise, SimpleArchwise 클래스 응용

Programming/ActionScript 3.0 2008. 1. 23. 13:53
예전에 만들었던 호 그리는 클래스를 응용하여 부채꼴, 활꼴 모양을 그리는 Shape를 만들고 응용해보았다.
아래 CREATE 버튼을 클릭하면 왼쪽은 SimpleFanwise를 이용한 것이고 오른쪽은 SimpleArchwise를 이용하여 20개 오브젝트 생성후 사라지는 모션을 적용해 봤다.














    

설정

트랙백

댓글

[AS3] private, protected, internal, public을 어떻게 결정하면 좋은가

Programming/ActionScript 3.0 2007. 12. 31. 03:07
AS3의 private, protected, internal, public을 어떻게 결정하면 좋은가

일본의 ASer의 포스트을 보고 나를 포함한 많은 플래시 작업자들이 개념적으로는 이해 하고 있지만 실전에서 흐지부지 하게되는 것을 지양하기 위해서 그 분의 포스트을 토대로 접근자들을  정리해 본다.

각 접근자의 개념은 아래와 같다.

내부 이용자(자기 자신)               -> private
계승이용자(서브 클래스)             -> protected
외부 이용자(동일 패키지의 제삼자) -> internal
외부 이용자(다른 패키지의 제삼자) -> public
 




이하에 패키지 A_package의 클래스 A_class를 예로 들어 아래와 같을 경우, A_package 패키지 내에서는 모두 접근이 가능하다.
package A_package {
public class A_class {

private var p1:uint;
protected var p2:uint;
internal var p3:uint;
public var p4:uint;

public function A_class() {

p1 = 1; // OK
p2 = 2; // OK
p3 = 3; // OK
p4 = 4; // OK

}
}
}
동일 패키지의 상속 클래스는 private를 제외한 속성들에 접근이 가능하다.
package A_package {
public class B_class extends A_class {

public function B_class() {

v1 = 1; // error
v2 = 2; // OK
v3 = 3; // OK
v4 = 4; // OK

}
}
}
동일 패키지의 다른 클래스는 protected 속성에 액세스할 수 없지만 internal에는 액세스할 수 있다.
package A_package {
public class C_class {

public function C_class() {

var a:A_class = new A_class();

a.v1 = 1; // error
a.v2 = 2; // error
a.v3 = 3; // OK
a.v4 = 4; // OK

}
}
}
다른 패키지의 상속 클래스에서는 protected에는 액세스할 수 있지만 internal에는 액세스할 수 없다.
package B_package {

import A_package.A_class;

public class D_class extends A_class {

public function D_class() {

v1 = 1; // error
v2 = 2; // OK
v3 = 3; // error
v4 = 4; // OK

}
}
}
다른 패키지의 다른 클래스에서는 public밖에 액세스할 수 없다.
package B_package {

import A_package.A_class;

public class E_class {

public function E_class() {

var a:A_class = new A_class();

a.v1 = 1; // error
a.v2 = 2; // error
a.v3 = 3; // error
a.v4 = 4; // OK

}
}
}
예전에는 이런 구분 자체가 내 머리속을 어지럽게 하여 private와 public만을 사용했었다. AS3로 넘어오면서 상속, 합성, 오버라이드를 이용한 작업이 늘어나면서 유기적인 클래스들과의 관계 중심으로 구조를 설계하다보니 클래스 간에 접근 규정을 코멘트로 달아놓지 않는 한 스스로 혼란스럽게 되었다. 보통 private로 해두고 protected→internal→public 방향으로 작업을 하면 되겠으나 이것 또한 중간중간 에러체크를 감당해야 하는 부담을 지울 수가 없다.

확실히 private, protected, internal, public을 구분해서 작업 하는 것이 현재 작업자에게도 큰 도움이 된다. 가장 바람직한 방법으로는 작은 프로젝트라도 작업에 들어가기 전에 구조를 설계하고 노트에 UML 비스무리한 낙서를 하고 시작하는 것이 좋을 것 같다.

 

    

설정

트랙백

댓글

  • 땡굴이 2008.01.03 23:49 ADDR 수정/삭제 답글

    나도 아직 무개념이라 이해력이 부족한데 네 글을 보니.. 좋은걸.. 푸합..
    네 말처럼 낙서라도 해 가믄서 일해야 하는데 쩝~ 후후.. 낙서 할 시간도 없는 건가 ㅠㅠ;

    • jasu 2008.01.04 01:18 신고 수정/삭제

      쿠쿠 저도
      var result = 나의무개념 as 개념
      trace(result); // null
      하면 항상 null이 반환되고 있어요. 습관을 들이기가 힘든 것 같네요 ^^

  • Han Sanghun 2008.01.09 12:51 ADDR 수정/삭제 답글

    아직 UML이 뭔지 모르는 무개념 1인 추가...

    • jasu 2008.01.09 17:02 신고 수정/삭제

      하면 도움이 될것도 같은데 하자니 귀찮고... 시간적 여유가 있을 때 정말 나에게 맞는 언어인지 따져봐야겠어요 ^^

  • 성주 2010.01.07 11:54 신고 ADDR 수정/삭제 답글

    2007년에 올리신 포스트를 2010년에 보고 큰 도움 얻고 갑니다.
    시간이 지나도 좋은 자료네요

    • jasu 2010.01.12 13:01 신고 수정/삭제

      말씀 감사합니다. 개념적으로 이해하고 있는 내용도 실전에서 자주 활용되지 않으면 무시하는 경우가 많이 발생하는 것 같네요 ^^

[AS3] TextField.htmlText 속성 문제

Programming/ActionScript 3.0 2007. 11. 12. 22:33
작업한 파일을 주말 동안 브라우저에 올려 놓고 몇 시간을 놔두었더니 CPU 점유율이 서서히 올라간다. 어디서 문제가 있는지 고민해 보았는데 이상하게도 메모리에는 이상이 없는 것 같은데 유독 CPU 점유율만 서서히 상승하는 것이다. 그래서 몇 개의 클래스를 두고 하나 하나 테스트를 해봤는데 결국 예전에 만들었던 DZeroNumber.as 클래스에서 문제가 있는 것으로 나타났다.

그런데 그 클래스 내에서도 특별히 문제가 될만한 곳을 발견하지 못하였는데 결국 생각지도 못한 곳에서 문제가 발생하고 있었다. DZeroNumber 클래스에서는 지정한 텍스트 필드에 00000 부터 지정한 숫자만큼 다이나믹하게 넘버링 하는 기능을 하고 있는데 그 클래스에서 000에 해당하는 부분과 실제 숫자에 해당하는 부분의 색을 달리하기 위해 TextField.htmlText 속성에 html 태그를 포함한 String을 넣고 있었다. 그런데 이 htmlText 속성이 문제가 있다.

TextField.text = "String" 을 넣을 때에는 CPU 점유율이 고정이지만 하나의 TextField에 htmlText속성을 통해서 html 태그를 포함한 String을 주기적으로 넣었을 때는 html 태그를 렌더링하는 과정에서 CPU 점유율이 점차적으로 상승한다. 그리고 이 상승하는 CPU 점유율은 swf파일이 종료되지 않는 이상 떨어지지 않는다.

TextField.htmlText = "<b> text </b>"

위와 같은 형태로 html 태그를 계속해서 TextField.htmlText에 넣게 되면 점차적으로 CPU 점유율이 100%를 향해 달려가니 주의가 필요하다.
    

설정

트랙백

댓글

  • cmr 2007.11.13 15:30 ADDR 수정/삭제 답글

    헙 ㅠㅠ 요즘 아주 이런 이슈들이 많죠......그노메 GC는 알다가도 모를녀석인데다가...
    이런 문제까지.. ㅠㅠ

    • jasu 2007.11.14 09:33 신고 수정/삭제

      htmlText 속성의 문제 같은 경우는 경험하지 않으면 다른 곳에서 헤매기 쉬울 듯 싶네요^^ 그래도 믿어야지요..

  • chadol 2008.06.05 15:05 ADDR 수정/삭제 답글

    진짜 만 하루 돌려놨더니 CPU 가 1% 에서 30% 까지 올라 갔네요. 그렇다고 htmlText 을 안 쓸수도 없는 상황이고 참 답답하네요~^^

    • jasu 2008.06.11 21:40 신고 수정/삭제

      안에서 어떻게 렌더링 되는지 모르겠지만 다음 플래시플레이어 버전에서는 텍스트필드 기능이 좋아지니 해결되지 않을까요? ^^

Variable Notation for ActionScript

Programming/ActionScript 3.0 2007. 11. 7. 21:55

 플래시 액션스크립트 언어가 3.0으로 접어들면서 변수명 지정에 있어서 스스로 한계를 느껴서 변수명 표기법을 만들어 보았다. 기본적인 규칙은 헝가리안 표기법에 따랐으며 플래시의 특성에 맞는 타입들은 플래시 액션스크립트에서 권장하는 접미어를 사용 하였다.

 

사실 아래 이미지와 같이 표기법을 만들어 놓았지만 지금은 이와 같이 변수명을 지정하지 않고 있다. 이 테이블에서는 Scope 형태를 표기하기 위해서 g_, m_, l_, p_ 접두어를 사용하였는데, ActionScript 3.0으로 접어들면서 글로벌 변수의 개념이 불명확해 졌으며 접두어를 사용할 경우 변수명을 볼 때 한번 더 생각을 하게 만들기 때문에 읽기 어려운 점도 있는 듯하다. 그래서 이 테이블을 만들어 놓고도 사용하는 방법은 다음과 같다.

 

g_를 사용하는 글로벌 변수 표기는 제거 하고 클래스 속성변수(멤버변수)의 경우에는 _를 사용하며, 로컬 변수의 경우는 _를 없앴다. 그리고 파라미터로 넘겨받은 변수의 경우는 로컬변수에 포함하여 _가 없는 변수명을 하도록 했다. 따라서 이러한 표기법을 사용하면 아래와 같은 형태를 취한다.


package{
        public class VariableNotation extends Sprite{
                // ----------------- properties ---------------//
private var _strMsg:String; private const COUNT:int = 12;    // 상수는 대문자 표기
   // ----------------- Methods ----------------// public function VariableNotation():void{ _strMsg = “멤버변수 표기법”; initStart(); // 메소드는 대문자로 단어를 구분 } private function initStart ():void{ var strMsg:String = “로컬변수 표기법”; trace(“_strMsg : ”+_strMsg, “strMsg : ”+strMsg); } } }

표기법은 개인의 취향에 따라 다양한 형태를 나타낼 수 있지만 그때 그때 다른 표기법은 자신은 물론 다른 사람이 코드를 분석할 때도 어려움을 줄 수 있을 것 같다. 딱히 표기법이 없는 분들에게 권유해 본다.

사용자 삽입 이미지


    

설정

트랙백

댓글

  • Han Sanghun 2007.11.08 12:02 ADDR 수정/삭제 답글

    갠적으로, 역시 플래시의 특성상 접두어보다는 접미어를 사용하는 게 편한듯...

    • jasu 2007.11.09 09:35 신고 수정/삭제

      습관들이기 나름인 것 같아요 저도 플래시툴에서 인스턴스 네임을 지정할 때 접미어를 사용하고 있는데 그 습관이 바뀌기가 어려운 것 같아요...^^

  • JINE 2008.01.01 18:01 ADDR 수정/삭제 답글

    형님 이글좀 담아 갈께요
    // 새해부터 이런거(밥먹고 사는데 도움되는ㅋㅋ) 완전 좋은데요!? ^^
    참 무자년 새해. 계획하신일 모두 이루시게 한해 또 열심히 앞에서 달려주세요
    저 같이 뒤에 있는 후배들이 쫓아갈수/ 바라볼수 있는 사람이 되실수 있게요 ^^

    • jasu 2008.01.03 13:41 신고 수정/삭제

      그래요 말씀 고맙습니다. ^^

「Flash Performance Tips Part 1」의 한국어 번역

Programming/ActionScript 3.0 2007. 11. 4. 20:15
「BIG SPACESHIP LABS / Flash Performance Tips Part I」 에서 Flash의 최적화에 대한 이야기를 하고 있어서 포스팅한다. 내용은 번역 과정에서 잘 못된 부분이 있을 수 있으므로 이해가 필요하다. Flash사이트를 최적화를 위해 부드럽게 재생시키려면 93%의 노력과6%의 지식과4%의 땀과2%정도의 butterscotch(버터를 넣은 캔디)가 필요합니다.(영화 「Charlie & the Chocolate Factory」의 대사로부터의 인용 했다고 합니다)
농담은 접어두고, 많은 사람들이Flash Player의 퍼포먼스에 고민을 하고 있지만 사이트를 부드럽게 재생시키기 위해서 당신이 할 수 있는 것이 있습니다. 부드러운 재생을 위해서 우리(BIG SPACESHIP스탭)이 매일 사용하고 있는 수법을 몇 개 소개하겠습니다.

마스크는 안된다
모든 마스크를 사용해서는 안된다는 것은 아닙니다. 마스크가 매우 도움이 되는 것은 이미 아시는 바지요. 그렇지만, 마스크는 재생 퍼포먼스를 떨어뜨리는 원인의 주범입니다. 어떤 대상을 마스크 했을 때 Flash player는 매 프레임 마다 무엇을 표시 하고 무엇을 숨기는지를 계산하고 있습니다. 마스크와 능숙하게 친해지려면 어떻게 하면 좋을까요? 거기에는 조금의 인내와 트릭인 층 구조(예를 들면 표시시키고 싶은 영역 사이즈로 구멍을 뚫은 상위 층을 올려놓고 그것을 아래의 층에 씌운다든가)를 사용하면 퍼포먼스 저하를 막으면서 같은 표시 결과를 얻을 수 있겠지요.

알파 채널 첨부PNG와 비디오에 대해
마스크와 같이 이것도 사용하지 않을 수 없을 때도 있지만 이 때도Flash Player는 알파 아래 부분의 표시 계산 처리를 강요당하고 있습니다. 경우에 따라서 우리는 절반 사이즈의 알파 비디오를 Flash위에서 확대해 사용하기도 합니다.
그리고 알파 첨부의 동영상에 대해입니다만 알파 비디오 대신에 연속된 번호의PNG를 사용하는 방법도 시험하는 가치가 있을 거라고 생각합니다. 대부분의 경우는 비디오 형식이 약간 퍼포먼스가 좋은 듯 하지만 그 때 마다 실험해 볼 가치는 있습니다.

frame rate
여러 가지 논의가 있습니다만 세상에 말하는 「매직 frame rate」같은 것은 없습니다. 우리는25, 30fps로 만들고 있습니다.(내가 알기로는) 그것이 베스트라고 생각하고 있습니다. 우리는 그 때마다 어느 쪽이 보다 좋은가를 테스트해서 결정을 하고 있습니다. 그렇지만 일반적으로 말하면 frame rate가 사이트의 재생 스피드가 저하하는 주된 원인은 되지 않을 것입니다. 아무튼 통상의 사용에서는30fps이상은 별로 추천하지 않습니다. 그렇게 아주 대단한 스피드로 렌더링 시켜도…

cacheAsBitmap 과 BitmapData
cacheAsBitmap을 이용한 벡터의 아이템의 rasterize화는 상황을 선택해 사용하도록 해야 한다. 분명히Flash는 심볼을draw하는 것은 한 번으로  끝납니다. 하지만 심볼을 확대 축소나 회전시킬 때는 결코cacheAsBitmap하지 말아야 한다. 이 때 Flash는 매프레임 마다 렌더링과 캡쳐를 반복하므로 처리가 빨라야할 어딘가가 늦어져 버립니다.
Da Vinci CodeNike Air 의 사이트에서 우리는 보이는 부분의 screen shot를 찍어 그것을 하나의 무비 클립에draw시켜서 screen shot을 애니메이션 시키는 처리를 하고 있습니다. 이것은 많은 엘리먼트를 개별적으로 움직이거나 하는 것보다도 상당히 빠릅니다.이 수법은 꽤 추천합니다.

alpha보다 visible로 하는 편이 좋아

alpha = 0과 visible = false는 실은 전혀 별개입니다. alpha는 대상이 되는 클립의 투명도를 결정하는 것입니다. Visible는 FlashPlayer위에서 실제로 그 클립을 표시 할까, 하지 않을까를 결정하는 것입니다. 만약, 무언가를 비 표시로 설정하고 싶으면 visible프롭퍼티를 사용하도록 합시다.

onEnterFrame 과 setInterval
이러한 처리를 사용했을 때는 각각 onEnterFrame = null;이나 clearInterval(myInterval); 하고, 메모리로부터 클리어 해 두도록 합시다.그것을 하지 않는 채 방치하는 것은 전화의 통화 후에 수화기를 올린 채로 떠나는 것입니다.

수학 연산은 사전에 미리 해둡시다.
표시 직전의 단계에서 싸인 웨이브(※ -1~1를 취하는 파형)을 연산하고 있지 않습니까? 그것은 매회 같은 싸인 커브는 아닙니까? 그럴 때는 수치를 배열 안에 하드 코드 해 둡시다. 사전에 수학 연산을 해 두는 것으로, 직전에 복잡한 처리를 하지 않는 것이 좋습니다. 나는 트윈 시키고 싶을 때에 사전에 배열에 모든 트윈치를 배열에 넣어두고 nextFrame()으로 매 프레임 마다 이동시킨 적도 있습니다.

무음 사운드
우리도 마지막 수단으로서 사용하고 있습니다만 기억해 두는 가치가 있는 수법이라고 생각합니다. 타임 라인상의 독립된 층에 무음의 사운드 파일을 「스트리밍 재생•루프」로 설정해 놓아두면 FlashPlayer는 사운드에 동기 시키려고 하고 자동적으로 프레임을 솎아내 조정해 줍니다.

//////////////////////////////////////////////////////////////////////////////////

위 내용은 「BIG SPACESHIP LABS / Flash Performance Tips Part I」의 내용이다. 이 밖에서 작업자 입장에서 FlashPlayer를 웃을 수 있게 해주는 방법은 여러 가지가 있을 듯 싶다. 현재 생각나는 몇 가지만 추가하고 그 이후 자신이 알고 있는 방법이 있으면 코멘트로 소통했으면 좋겠다.

1.    위에서 visible = false; 로 하는 것은 화면상의 표시 오브젝트에서 제외 되지만 그 안에서 연산하고 있는 처리는 그래도 FlashPlayer의 몫이다. 따라서 visible = false를 적용한 오브젝트 안에서 이루어지는 연산도 멈춰 주는 것이 바람직하다.

2.    for(var i:int=0;i<m_arr.length;i++) 와 같이 for문의 비교연산에서 직접 m_arr.length 값을 취득하는 것 보다 상위에 var l_intLen:int = m_arr.length; 변수를 미리 정의하여 사용하는 것 이 좋다. 이는 for문이 비교연산을 처리할 때 매번 m_arr 배열의 개수를 취득하기 위해서 연산처리를 시도하기 때문이다.

3.    _mcParent._mcChild1._mcChild2; 와 같은 참조를 여러 번 사용할 때는 상위에 var _mcChild2:MovieClip = _mcParent._mcChild1._mcChild2; 변수를 미리 선언하여 _mcChild2를 사용하는 것이 좋다. 이는 .연산자를 통해서 매번 depth 탐색이 이루어 지기 때문이다.

4.    _mcParent[“_mcChild1”]와 같은 참조 보다는 _mcParent._mcChild1과 같은 참조가 빠르다. _mcParent[“_mcChild1”]와 같은 형태로 참조할 경우에는 해시테이블 탐색을 통해서 string의 값을 비교 연산을 하기 때문이다.

5.    onEnterFrame or Timer and Interval과 같은 빠른 속도로 처리되는 function 안에서는 특정 기능을 하기 위한 코드들을 외부 function을 호출하는 형태로 분리 하는 것 보다는 직접 function 안에 쓰는 것이 좋다.(이는 유지 보수와 재 사용상의 문제가 있을 수 있음)

6.    for문을 사용하여 연속된 연산처리를 수행하는 것 보다는 절차지향으로 라인으로 풀어 쓰는 것이 빠르다.(onEnterFrame이나 interval과 같은 function 안에서 for문을 사용하는 것은 치명적이다. 이럴 때는 라인에 풀어 쓰는 것이 좋다)

이 밖에도 많은 테스트들이 있었을 것으로 생각한다. 각자 가지고 있는 노하우가 있으면 댓글을 달아 주길 바란다.

    

설정

트랙백

댓글

  • 소다수 2007.11.05 08:41 ADDR 수정/삭제 답글

    늘 좋은글 잘 읽고 갑니다. ^^

  • cmr 2007.11.07 13:28 ADDR 수정/삭제 답글

    3.0 에 와서는 가비지 컬랙션에 대한 올바른 지식이 가장 필요한 것 같아요 ㅠㅠ

    • jasu 2007.11.07 21:52 신고 수정/삭제

      가끔 코드를 짜다보면 나는 말을 하는데 쓰레기통이 대답을 안해서 문제라는...

  • 이니셜Z 2007.11.08 00:35 ADDR 수정/삭제 답글

    (Cross Referencing)교차참조와 이벤트 핸들러의 정확한 참조 위임등
    순간적인 편리함을 위한 코딩보다 조금더 손이 가는 코딩을 지향한다면
    3.0의 GC는 정말 필요할때 작동을 하는거 같더군요.
    작업관리자 창의 메모리 그래프를 실시간으로 검사하여 확인 하는 것 보다는
    현제 브라우저나 플래시플레이어창에서 다른 응용프로그램 창으로 작업 활성화를
    변경했을때 주로 메모리를 반환 하더군요.
    플래시플레이어는 OS에서 수행되는 가비지 수집 프로세스에 의해 메모리를
    반환 하는 것 같내요.

    • jasu 2007.11.09 09:34 신고 수정/삭제

      작업 전환이 이루어 지지 않는 화면상에서 메모리가 언제 반환될지를 개발자 입장에서 결정할 수 있는 권한이 없다는 것이 아리송하게 만드는것 같네요 ^^

  • 동강 2007.11.10 04:50 ADDR 수정/삭제 답글

    와 ~ 좋은 참고가 되네요 . 잘 읽고 가요.ㅋ

    • jasu 2007.11.12 02:45 신고 수정/삭제

      네... 감사합니다. 추가할 사항이 있으면 남겨주세요...^^

  • 이드 2007.11.29 19:18 ADDR 수정/삭제 답글

    좋은글 감사합니다..좀 담아갈께요.

  • 지돌스타 2009.03.05 10:06 ADDR 수정/삭제 답글

    좋은 글 너무 잘봤습니다. ^^

  • 두리미 2009.04.29 11:38 신고 ADDR 수정/삭제 답글

    좋은 글 감사합니다. ^-^

  • 지돌스타 2010.03.03 12:33 ADDR 수정/삭제 답글

    cacheAsBitmap의 경우 move를 제외한 alpha,resize,rotation등 move외에 각종 transform에는 사용하지 말아야 한다는 군요. http://www.bytearray.org/?p=290
    alpha는 괜찮을 줄 알았는데... alpha가 변경될때마다 다시 캡쳐하는 방식이라 어쩔 수 없이 cpu연산이 들어가나 봅니다.

[AS3] 스테이지에 올려놓은 TextField의 autoSize 설정

Programming/ActionScript 3.0 2007. 11. 3. 18:49
회사 작업으로 만들었던 클래스를 이리저리 가지고 놀다가 플래시 툴에서 stage에 만들어 놓은 TextField의 autoSize 설정이 제대로 먹히지 않는 경우가 발생하여 한참을 고생했다. new TextField()로 생성한 TextField의 경우에는 제대로 먹히는데 stage에 직업 올려놓은 TextField의 설정이 처음에는 되었다가 어느 순간부터 먹히지 않거나 중간에 사이즈가 늘어나다 끊기는 현상이 발생했다.

문제의 이유는 확인하지 못하였는데 여러가지 테스트를 해보다가 결국은 기존에 있던 텍스트 필드를 삭제하고 다시 텍스트 필드를 만들어서 같은 속성으로 적용을 해보니 이번에는 제대로 먹는다...

stage에 있는 TextField의 폰트를 임베드 시키고 폰트를 다른 폰트로 바꾸게 되면 그때부터 autoSize 속성이 적용이 되지 않는다. 텍스트필드에 filter를 적용해도 autoSize 속성이 먹통이 되버린다...

저 처럼 stage에 올려놓은 텍스트필드의 autoSize가 먹히지 않을 때에는 주저하지 말고 기존에 있던 텍스트 필드를 지우고 새롭게 텍스트 필드를 만들어서 테스트 해보길 바란다.



    

설정

트랙백

댓글

  • 깡생이 2008.01.24 18:54 ADDR 수정/삭제 답글

    아...역시나..안되는 거였군요...
    오토사이즈가 안되길래..
    혹시나 해서 자수님 블로그에서 검색하니..지우고 다시 만들어야 하는거네요.ㅎ

    • jasu 2008.01.28 19:12 신고 수정/삭제

      ^^ 저도 이때 한참 고민했었던 기억이 있네요

  • 디마인드 2008.02.20 16:53 ADDR 수정/삭제 답글

    autoSize를 적용하려면 wordWrap속성이 false가 되어야 하더군요 ^^

[AS3] 호(arc)를 그리는 클래스

Programming/ActionScript 3.0 2007. 9. 15. 03:08
호를 그리는 클래스를 만들어 봤다. 여러가지 자료들을 급조하여 기본적인 호를 그리는 형태를 제작한 관계로 -값이나 예상치 않은 입력 값에 따른 예외는 처리하지 않은 상태다. 사용하실 분들은 개인적으로 자료 정리를 위해서 패키지 설정을 해 놓은 상태이니 원하는 폴더 구조 및 패키지를 설정하여 사용하거나 패키지(jasu.display)를 제거하고 fla와 같은 폴더에 복사 후 사용 하면 된다.









    

설정

트랙백

댓글

  • moonkoon 2007.09.15 14:05 ADDR 수정/삭제 답글

    가끔 와서 보는데여 정말 대단하세요;;; 3.0을 벌써 이정도로 구현하시다 놀랍습니다 -_-;

    • jasu 2007.09.15 22:41 신고 수정/삭제

      저도 처음에는 많이 변한 모습에 2.0에서 3.0 넘어가는 것이 힘들 것 같다는 생각도 들었는데 두 버전의 차이를 어느정도 익히시면 버전업하는데는 크게 문제될 것은 없을 것 같아요... 좀더 불편한 점도 있고 편한 점도 있는데 구조적인 개념에서는 3.0이 좀더 편해졌다는 생각이 드네요...^^;

  • 소주 2007.09.15 21:24 ADDR 수정/삭제 답글

    우와~ 바로 만들어내시다니 대단하시네요~!

    사용 방법 좀 알 수 있을까요??
    C 계열이나 Python, Lua 같은 언어만 사용해봐서 AS3.0으로
    이 클래스를 이용해서 어떻게 그려줘야 할지 확실히 모르겠네요..


    실행 결과가 어떤식으로 나오는지 확인 해 보려고
    생성자에서 간단하게 함수를 이용해 보려고 하는데 오류가 나네요..

    package jasu.display{ // 패키지 매칭 에러 확인
    import flash.display.Sprite;
    import flash.display.Graphics;

    public class Draw extends Sprite{
    private var bgColor:uint = 0xFFCC00;

    public function Draw(){
    var child:Sprite = new Sprite();
    var da:DrawArc;

    da = new DrawArc();
    child.graphics.beginFill(bgColor);
    //da.arcTo(child.graphics, 350, 200, 50, 0, 90, false);
    addChild(child);
    }
    }

    public class DrawArc{
    public function DrawArc():void{
    trace ("Draw is a static class and should not be instantiated.");
    }
    public static function arcTo(g:Graphics, cx:Number, cy:Number, radius:Number,
    sAngle:Number, eAngle:Number, cw:Boolean=false):void {
    var arc:Number = 0;
    !cw ? arc = eAngle - sAngle : arc = 360-(eAngle - sAngle);
    arc = Math.abs(arc)>360 ? 360 : arc;

    var segs:Number = Math.ceil(Math.abs(arc)/45);
    var segAngle:Number = arc/segs;

    var ta:Number = 0;
    var angle:Number = 0;

    !cw ? ta = -(segAngle/180)*Math.PI : ta = (segAngle/180)*Math.PI;
    angle = (sAngle/180)*Math.PI;

    var sx:Number = cx+Math.cos(angle)*radius;
    var sy:Number = cy+Math.sin(angle)*radius;

    g.moveTo(sx,sy);

    var am:Number = 0;
    var bx:Number = 0;
    var by:Number = 0;
    var controlX:Number = 0;
    var controlY:Number = 0;
    var i:int = 0;
    while(i<segs){
    angle += ta;
    am = angle-(ta/2);
    bx = cx+Math.cos(angle)*radius;
    by = cy+Math.sin(angle)*radius;
    controlX = cx+Math.cos(am)*(radius/Math.cos(ta/2));
    controlY = cy+Math.sin(am)*(radius/Math.cos(ta/2));
    g.curveTo(controlX, controlY, bx, by);
    i++;
    }
    }
    }
    }

    AS3.0에서 어떤식으로 이런 클래스를 사용하는지 알려주실 수 있을까요??

    <아.. 여긴 탭이 화면에 재대로 표현이 안 되는군요..>

    • jasu 2007.09.15 22:37 신고 수정/삭제

      아... 위 클래스를 복사해서 코드편집 툴이나 메모장 복사를 하시고 package jasu.display{ 이 부분을 package{으로 수정해서 Draw.as 파일로 저장을 하세요...

      그런 다음에 FlashCS3 툴을 열어서
      첫번째 프레임에 아래와 같이

      graphics.lineStyle(1, 0xff0000);
      Draw.arcTo(graphics, 350, 200, 50, 0, 90, false);

      작성하시고 퍼블리시를 하시면 되는데 이때 Draw.as 파일과 FlashCS3에서 생성한 fla파일이 같은 폴더에 있으면 제대로 실행이 될거에요 파라미터 값들을 변경해 보시면 호 그리기는 제대로 실행 될거에요...^^

  • 소주 2007.09.16 18:01 ADDR 수정/삭제 답글

    아하! 이렇게 하니까 되는군요~~
    소스를 완전히 파일들로 분리 시키려고 했는데.. 프레임에 넣어야 되는군요;;

    이래 저래 시험해 보다가 결과가 계속 이상하게 나와서 보니
    기준 축이 y축이더군요.. x 축이 기준 축인줄 알고 제가 넣는 각도하고 계속 안 맞게 결과가 나와서 놀랐어요;;

    정말 감사합니다! 앞으로 자주 와서 물어 보면 힘드실테고;;
    자주 와서 강좌 보고, 가끔 질문도 던지겠습니다~~

    • jasu 2007.09.17 09:11 신고 수정/삭제

      네..제가 아는 범위 안에서는 알려드릴께요...감사합니다.

  • moonkoon 2007.09.16 21:55 ADDR 수정/삭제 답글

    아... 전 이제 3.0 걸음마 수준이에여^^ 어떻게 이해해 나가는것이 좋으며, 공부방향에 대한 제시 하나만 해주시면 안될까요^^

    • jasu 2007.09.17 09:15 신고 수정/삭제

      2.0을 하셨다고 하시면 http://livedocs.adobe.com/flash/9.0_kr/ActionScriptLangRefV3/ 이 자료를 참고하셔서 기존 2.0에서 사용하던 내장 언어가 어떻게 바뀌었는지 확인해 보시면 도움이 될거 같네요 2.0을 클래스로 제작해 오셨다면 3.0에서 바뀐 개념 부분들을 약간 수정하시면 충분히 사용하실 수 있을 거에요... 1.0을 주로 사용하셨다면 2.0 후 3.0을 하는 것 보다는 바로 3.0을 공부하시는 것도 좋을 것 같습니다. 물론 클래스 개념들이 어렵게 다가오겠지만 2.0을 하더라도 느낄 수 있는 부분들이니 클래스라는 것이 3.0이라 더욱 어려운 것은 아니라는 것만 말씀드리고 싶네요...

    • Han Sanghun 2007.09.17 22:51 수정/삭제

      AS3.0 쿡북을 보셔도 도움이 될듯 하네요.
      드로잉, 비트맵, 텍스트, 사운드, XML 등 기능별로 기본적인 사용법과 샘플 코드들을 제시하니까요.

    • jasu 2007.09.18 17:25 신고 수정/삭제

      이렇게 오셔서 답변까지 해 주시니 저에게는 큰 힘이 됩니다. ^^ 고맙습니다...

  • moonkoon 2007.09.19 00:41 ADDR 수정/삭제 답글

    앗! 상훈님이시네여^^ 땡굴형님 홈피에서 자주뵈었던 크큭;
    요새 한참 쿡북으로 공부하고 잇는데 도움이 정말 많이 되는거 같아여^^

    도움말씀 진심으로 감사드립니다^^

[AS3] Pen 클래스 테스트

Programming/ActionScript 3.0 2007. 9. 14. 12:52
Pen 클래스를 이용해서 드로잉 테스트겸 만들어 봤다. Graphics 객체는 드로잉을 하면 할수록 CPU를 많이 잡아먹는디 Graphics 객체 안에서 어떤 일이 벌어지길에 이런 현상이 발생하는지 모르겠다... 그리는 과정에서 비트맵데이타로 처리해버리면 될거 같은디 귀찮스러워서 그냥 올려 놓는다. 테스트 하시는 분들은 너무 많이 그리지 마셔용...쿠쿠











 
 
    

설정

트랙백

댓글

  • moonkoon 2007.09.17 02:38 ADDR 수정/삭제 답글

    질문 드려도 될지 모르지만^^; 제가 이 문제를 풀어보려 매우 고생을 했는데; 솔직히 풀지 못했습니다 ㅠ_ㅠ;;; 아직 부족해서 그런건 알겠지만 너무 하고 싶은데 답답해서 아주 난리를 치고 있네여 ㅋ

    힌트좀 주세요 -_-;

    • jasu 2007.09.17 09:17 신고 수정/삭제

      어떤 문제인지...위 코드를 말씀 하시는 것이라면 위 코드는 Pen 클래스를 테스트 하기 위한 Container 역할을 하는 클래스입니다. Pen 클래스가 올라가 있지 않아서 위 클래스 만으로는 위와 같은 결과물을 만들 수는 없어요... Pen 클래스는 완전한 것이 아니라서 추후에 손을 대볼 생각입니다.

[AS3] UIScrollBar 동적으로 스킨 적용하기

Programming/ActionScript 3.0 2007. 9. 12. 06:43
UIComponent에 해당하는 컴포넌트들의 스킨을 적용하는 방법에 대해서 FlashCS3의 레퍼런스에서는 컴포넌트를 라이브러리에 등록하고 등록된 컴포넌트를 스테이지에 끌어다 놓고 무비클립을 직접 수정하는 방법 이외에는 이렇다 할 설명을 하지 않고 있는 듯 하다.

개인적으로 웹상에 올려지는 스크립트들을 이쁘게(?!) 보이도록 만들어 보려고 AScodeViewer를 작업하고 있는데, 외부에 있는 Style xml 데이터를 로드하여 사용자가 작성한 xml에 따라서 UIScrollBar와 기타 화면상의 DisplayObject들의 스타일을 적용하는 과정에서 컴포넌트의 스킨을 동적으로 적용을 해야 했다. 웹상에서 찾아보았지만 그와 관련된 자료를 찾지 못하여 임의로 적용해 보게 되었다.

일단은 컴포넌트의 스킨을 동적으로 적용하기 위해서는 기존의 컴포넌트들이 어떠한 형태로 스킨을 적용하고 있는지, 구조를 파악할 필요가 있다. 컴포넌트를 스테이지에 올려놓고 안으로 들어가보면 해당 컴포넌트에서 사용되는 기능별 무비클립들을 볼 수 있는데 이러한 무비클립들은 2 프레임에 위치하고 있기 때문에 외부에서 직접 해당 무비클립에 접근 할 수는 없다.

라이브러리에 있는 Component Assets -> ScrollBarSkins 폴더에 보면 사용되는 무비클립들을 볼 수 있는데 이들 무비클립들에는 각각 내부 클래스가 지정되어 있다. 이 클래스들이 각각의 무비클립을 대변한다고 볼 수 있다.

그럼 각각의 무비클립의 색을 변경하기 위해서는 어떻게 해야 할까… 여러가지로 실험도 해보고 고민을 해보았는데 일단은 아래 방법은 개인적으로 작업하는 과정에서 만들어 낸 결과이기 때문에 옳은 방법이 아닐 수 있음을 밝혀둔다.

UIScrollBar 컴포넌트의 상속 관계에서 setStyle 메소드를 발견할 수 있는데 이 메소드는 스타일 적용에 필요한 default 클래스를 custom 클래스로 대체할 수 있도록 해준다. 따라서 setStyle 메소드를 통해서 기존에 등록되어 있는 각 무비클립의 클래스를 자신이 원하는 기능을 하는 클래스로 대체할 수 있다는 이야기다. 아래는 디폴트로 지정되어 있는 클래스들이다.

ScrollArrowDown_disabledSkin
ScrollArrowDown_downSkin
ScrollArrowDown_overSkin
ScrollArrowDown_upSkin
ScrollThumb_downSkin
ScrollBar_thumbIcon
ScrollThumb_overSkin
ScrollThumb_upSkin
ScrollTrack_Skin
ScrollArrowUp_disabledSkin
ScrollArrowUp_downSkin
ScrollArrowUp_overSkin
ScrollArrowUp_upSkin

그리고 아래는 디폴트 클래스와 매칭되는 문자열들이다.

downArrowDisabledSkin
downArrowDownSkin
downArrowOverSkin
downArrowUpSkin
thumbDownSkin
thumbIcon
thumbOverSkin
thumbUpSkin
trackSkin
upArrowDisabledSkin
upArrowDownSkin
upArrowOverSkin
upArrowUpSkin

일단 적용한 형태를 보면 아래와 같다.
private function setScrollBarStyle(s:UIScrollBar):void{
s.setStyle("downArrowDisabledSkin", DScrollArrowDown_disabledSkin);
s.setStyle("downArrowDownSkin", DScrollArrowDown_downSkin);
s.setStyle("downArrowOverSkin", DScrollArrowDown_overSkin);
s.setStyle("downArrowUpSkin", DScrollArrowDown_upSkin);

s.setStyle("upArrowDisabledSkin", DScrollArrowUp_disabledSkin);
s.setStyle("upArrowDownSkin", DScrollArrowUp_downSkin);
s.setStyle("upArrowOverSkin", DScrollArrowUp_overSkin);
s.setStyle("upArrowUpSkin", DScrollArrowUp_upSkin);

s.setStyle("thumbDownSkin", DScrollThumb_downSkin);
s.setStyle("thumbIcon", DScrollBar_thumbIcon);
s.setStyle("thumbOverSkin", DScrollThumb_overSkin);
s.setStyle("thumbUpSkin", DScrollThumb_upSkin);
s.setStyle("trackSkin", DScrollTrack_Skin);
}

위 코드에서는 적용할 UIScrollBar를 전달 받아서 setStyle 메소드를 통해서 각 무비클립의 클래스들을 새로운 클래스(D로 시작하는 클래스들)들로 대체했다. 새로 대체한 클래스에서는 각각 디폴트로 지정되어 있는 클래스들을 extends 시켰다. 이렇게 한 이유는 라이브러리에 있는 컴포넌트 무비클립들을 그대로 사용하기 위함이다.

이렇게 작성하게 되면 컴포넌트에서 사용하는 각각의 무비클립에서 원하는 기능을 수행할 수 있는 새로운 클래스들로 대체했기 때문에 새로 등록된 클래스 안에서 무슨 짓을 하더라도 플래시가 용서해 준다…쿠쿠

각 클래스 안에서는 자신의 무비클립의 색을 변경하는 클래스를 통해서 색과 알파값등을 세팅하도록 하였고 셋팅하는 방법으로는 중앙에 Singleton 클래스를 만들어 놓고 xml에서 전달받은 스타일을 각 무비클립에 입히는 방법으로 사용했다. 참고로 색 변경에 사용한 간단한 클래스도 올려 놓는다.
package viewer.skins{
import flash.display.DisplayObject;
import flash.geom.Transform;
import flash.geom.ColorTransform;

public class TintColor{
public function TintColor():void{}
public static function setTintColor(d:DisplayObject, c:uint, a:Number):void{
var resultColorTransform:ColorTransform = new ColorTransform();
resultColorTransform.alphaMultiplier = a;
resultColorTransform.color = c;

var transformation:Transform = d.transform;
transformation.colorTransform = resultColorTransform;
}
}
}

이 과정중에서 버그를 발견하게 되었는데 다른 것들은 위에서 언급한 문자열을 통해서 클래스를 대체할 수 있었으나 유독 trackSkin(스크롤바의 기본 바탕이 되는 배경)의 경우 클래스를 대체하지 못하는 문제가 있다. 이 문제로 검색을 해 보니 adobe에 버그로 등록되어 있는 것 같은데 그 해결책은 찾지 못하였다.. 그렇다고 그냥 지나칠 수 있낭…자존심이 허락하는 범위 안에서 꼼수를 부렸다.

적용한 방법은 쿠쿠 웃기는 이야기이긴 하지만 컴포넌트 스킨에서 스크롤바의 배경이 되는 무비클립을 투명으로 처리하고 스크롤바 아래에 무비클립을 두어 스테이지가 변경될 때 스크롤바의 크기와 위치에 따라 이동하는 배경 무비클립을 따로 만들어 놓고 그 무비클립의 색을 변경하는 방법으로 적용했다…쿠쿠 약간 찜찜하지만 trackSkin 버그 문제가 해결되기 전까지 임시방편으로 적용해 두기로 했다.

스테이지 상에서 무비클립들을 직접 수정하여 사용할 경우 일단 사용된 최초 컴포넌트만을 사용하기 때문에 서로 다른 스킨을 적용하기가 어렵지만 이러한 방법을 사용하면 컴포넌트 각 인스턴스에 개별적인 스킨을 적용할 수 있다.

AScodeViewer는 거의 85% 정도 완성된 것 같다. FlashDevelop의 as 코드 스킨과 스크립트 창의 배경까지 직접 xml을 편집하여 사용할 수 있도록 하였기 때문에 자신의 FlashDevelop 환경과 거의 비슷한 화면을 웹상에 올려놓을 수 있을 듯 싶다. FlashDevelop에서 사용하는 xml데이터를 그대로 사용하다보니 AS 코드 뿐만이 아니라 Java나 기타 언어에서도 사용 할 수 있을 듯 싶다. 중요 포인트는 풀스크린 모드 기능을 지원한다는 것이 아닐까 싶다....
    

설정

트랙백

댓글

  • 조기 2011.10.12 16:19 ADDR 수정/삭제 답글

    안녕하세요~ 글 잘읽었습니다. uiscrollbar가 아닌 그냥 scrollbar에서는 이 방법이 안 먹히더군요;;
    해결 방안이 있을 까요??

[FlashCS3] Auto Format 기능 주의...

Programming/ActionScript 3.0 2007. 9. 6. 03:16
코드 100줄 이상 넘어가는 것들은 대부분 FlashDevelop에서 작업을 하지만 그보다 적은 코딩 테스트를 할 경우에는 따로 열기 귀찮아서 FlashCS3에 내장된 스크립트 창을 사용하는데, Flash CS3의 Auto format 기능이 여러 가지로 문제가 좀 있다. CS3에서 ActionScript 3.0으로 버전업 하면서 스크립트 자체 기능은 강화되었다지만 FlashCS3 툴은 완성도는 다소 떨어지는 느낌이다. Sepy나 FlashDevelop 처럼 안되더라도 그에 부합하는 기능 보강은 필요할 듯싶다.

아래 코드의 경우 예상되는 결과값은 9가 되어야 하지만 스크립트 창에 있는 Auto Format 기능을 실행해서 코드를 정렬하고 퍼블리시를 해보면 결과는 엉뚱하게 7이 나온다.



trace(getResult());
function getResult(a:int=1, b:int=2, c:int=3):Number {
return (a + b) * c;
}

Auto Format 기능을 실행하게 되면 return 이후에 나타나는 ()는 리턴값으로 간주하여 ()를 제거해 버린다. 이 때문에 결과로 내보낼 사칙연산 순서가 b*c + a로 되어버린다. 실제로 Auto Format 기능을 실행하면 아래처럼 코드상에서 ()가 제거된 것을 확인 할 수 있다.
trace(getResult());
function getResult(a:int=1, b:int=2, c:int=3):Number {
return a + b * c;
}

간단한 코드의 경우에는 문제가 되는 부분을 찾을 수 있겠지만 덩치가 큰 코드의 경우에는 Auto Format 기능 한방으로 예상치 못한 에러 아닌 에러를 내는 곳을 찾기란 쉽지 않다. 그나저나 FlashDevelop은 왜 Auto Format 기능 안 넣는겨….


    

설정

트랙백

댓글

  • Han Sanghun 2007.09.07 15:30 ADDR 수정/삭제 답글

    전 오토포맷 한번도 사용해보지 않았다는...
    자동으로 처리하는 것은 그닥 신뢰할 수 없기 때문에 ㅋ

    • jasu 2007.09.08 04:19 신고 수정/삭제

      플래시8 버전에서는 불필요한 라인 제거용으로 가끔 사용했었는데 CS3는 라인도 그렇고 전혀 오토스럽지가 못하네요..쿠쿠

  • 티오엠 2007.09.11 21:40 ADDR 수정/삭제 답글

    플래시8은 잘 되는데, 이상하게 CS3만..

    • jasu 2007.09.12 02:46 신고 수정/삭제

      그렇더라구요...다음 버전에서는 어도비에서 툭닥툭닥 고쳐서 나오겠죠...^^

[AS3] BitmapData.lock and unlock 기능

Programming/ActionScript 3.0 2007. 9. 3. 09:45
BitmapData에 있는 lock/unlock 메소드는 레퍼런스에 기능이 명시 되어 있지만 짧게 설명되어 있어서 지나치기 쉬운 것 같다. 아래는 레퍼런스에 나와 있는 내용이다.

public function lock():void
언어 버전 :     ActionScript 3.0
Player 버전 :     Flash Player 9
이 BitmapData 객체를 변경할 때 BitmapData 객체를 참조하는 어떤 객체(예: Bitmap 객체)도 업데이트되지 않도록 이미지를 잠급니다. 성능을 높이려면 setPixel() 또는 setPixel32() 메서드를 여러 차례 호출하기 전후에 이 메서드를 unlock() 메서드와 함께 사용합니다.

레퍼런스의 내용만으로는 정확히 어떠한 역할을 하는지 알기 쉽지 않다. lock 메소드는 BitmapData의 정보를 화면에 draw하는 처리과정을 일시적으로 사용하지 않도록 하여 불필요한 처리과정을 제거함으로써 퍼포먼스를 향상시킬 수 있다. 예를 들면

보통 BitmapData를 처리하기 위해 addChild(new Bitmap(bitmap))와 같이 addChild한 이후에 setPixel() 또는 setPixel32() 메소드를 사용하는 경우가 많은데, 이때 setPixel() 또는 setPixel32()와 같은 메소드는 그 메소드 자체 처리만으로도 addChild 되어 있는 경우 화면에 draw하는 기능을 함께 처리해 버린다. 따라서 addChild되어 있는 BitmapData에 setPixel() 또는 setPixel32() 메소드를 여러 번 사용하여 복잡한 처리를 할 경우에 setPixel() 또는 setPixel32() 메소드를 호출될 때마다 화면에 draw 하기 때문에 불필요한 CPU 처리를 하게 되는 것이다.

물론 setPixel() 또는 setPixel32()메소드의 처리 과정을 화면에 표시해야 하는 경우라면 별로 효력이 없겠으나 setPixel() 또는 setPixel32() 메소드를 여러 번 처리한 이후 결과만을 화면에 표시할 경우는 lock 메소드를 통해서 화면에 표시하는 기능을 잠그고 일련의 처리를 완료한 이후에 unlock 메소드를 통해서 잠근 기능을 풀어주면 불필요한 처리를 하지 않으면서 화면에 처리한 결과를 표시할 수 있다.

아래 예제를 돌려보면 lock/unlock를 사용하지 않았을 때와 사용했을 때의 차이를 확인 할 수 있다.

lockTest(700, 700);

function lockTest(w:uint, h:uint) {
var bm:BitmapData = new BitmapData(w,h);
addChild(new Bitmap(bm));

trace("lock/Unlock 사용 안함 : "+drawBitmap(bm) + "ms");

bm.lock();
trace("lock/Unlock 사용 : "+drawBitmap(bm) + "ms");
bm.unlock();
}
function drawBitmap(bm:BitmapData):uint {
var start:uint = getTimer();
var w:uint=bm.width;
var h:uint=bm.height;

for (var x:uint=0; x < w; x++) {
for (var y:uint=0; y < h; y++) {
bm.setPixel(x,y,Math.random()*0xFFFFFF);
}
}
return getTimer() - start;
}

// output
lock/Unlock 사용 안함 : 214ms
lock/Unlock 사용 : 157ms

output 결과는 시스템에 따라 다소 차이가 있을 수 있는데 테스트한 컴퓨터 스펙은 아래와 같다.

소니 바이오 노트북 VGN-SZ18LP
Genuine Intel® CPU T2400 @ 1.83GHz
메모리 1.50GB RAM

    

설정

트랙백

댓글

  • Han Sanghun 2007.09.03 23:03 ADDR 수정/삭제 답글

    setPixel 할 때 등, 비트맵을 변경하는 작업을 하려면 lock 해주는게 좋죠...

    • jasu 2007.09.04 06:16 신고 수정/삭제

      네... 기능적인 부분에서 필요성을 느끼지 못하면 지나치기 쉬운 기능들이 여럿 있네요^^

  • lazyartist 2007.09.07 11:01 ADDR 수정/삭제 답글

    님의 블로그 잘 보고 있습니다.~ ^^
    한가지 궁금한게 있는데요~
    소스코드 올릴때 생상은 어떻게 변환 해서 넣는지요?
    저도 아는 사이트가 있기는한데 변환이 잘 안되서요... ^^;
    저는 여기를 이용합니다... http://qbnz.com/highlighter/

    • jasu 2007.09.07 14:54 신고 수정/삭제

      안녕하세요...감사합니다.
      저는 blog.pluszone.net에서 제공하고 있는 beautifierPlus 를 사용하고 있습니다. 간단하고 편해서 사용중이죠 제 블로그 위에 보시면 beautifierPlus 링크를 걸어두었습니다.

[AS3] Head First - OOAD AS3로 변환 두번째

Programming/ActionScript 3.0 2007. 8. 26. 12:11
이전에 포스팅한 기타 검색 프로그램의 두 번째로 객체지향 원리를 살린 cohesive버전을 AS3로 변환하였다. 변환 과정에서 Java에서 제공하고 있는 HashMap의 경우는 AS3로 기본적인 기능만을 하는 HashMap class를 만들었다.

메인 document class에서 inventory. addInstrument() 메소드를 실행할 때, 마지막 파라미터 값으로 new InstrumentSpec(HashMap)을 전달하게 되는데, 이때 HashMap 클래스의 경우 Array을 이용하여 데이터를 테이블 형태로 저장하고 있기 때문에 put과 remove과정에서 하나의 Array를 참조하므로 마지막 데이터만을 저장하게 되어 검색이 제대로 되지 않는다.

이는 addInstrument 메소드를 실행하는 시점에서 참조 형태로 HashMap 데이터 Array를 전달하기 때문에 발생하는 문제다. 이를 해결하기 위해 HashMap에 있는 Array를 복제(clone)할 필요가 생겼다. 그래서 HashMap 클래스 내에 clone() 메소드를 만들어 사용되고 있는 Array를 byteArray로 변환하여 복제하였다.

이 프로그램을 변환하면서 다시 한번 느끼는 건 단순해 보이지만 단순하지 않은, 간결하고 함축적인, 사용자가 사용하기 편리한 것과 개발자의 정신분열 증상은 항상 반비례한다는 것이다. 
Java의 버전업을 통해 지원하고 있는 클래스들을 분석하는 것은 충분히 가치가 있는 일이다. 이미 입증된 알고리즘으로 제작되었기 때문에 AS3로 변환하면 충분히 사용성에서 좀더 나을 방법을 찾을 수 있을 듯싶다.

사용자 삽입 이미지

// FindInstrumentTester.as
package{
import flash.display.Sprite;
public class FindInstrumentTester extends Sprite{

public function FindInstrumentTester():void{
var inventory:Inventory = new Inventory();
initializeInventory(inventory);

var properties:HashMap = new HashMap();
properties.put("builder", Builder.GIBSON);
properties.put("backWood", Wood.MAPLE);
var whatBryanLikes:InstrumentSpec = new InstrumentSpec(properties);

var matchingInstruments:Array = inventory.search(whatBryanLikes);
if(matchingInstruments.length != 0){
trace("Bryan, you might like these instruments:");
var ilen:int = matchingInstruments.length;
for(var i:int=0;i<ilen;i++){
var instrument:Instrument = matchingInstruments[i];
var spec:InstrumentSpec = instrument.getSpec();

trace("We have a " + spec.getProperty("instrumentType") +
" with the following properties:");

var hashMap:HashMap = spec.getProperties();
var jlen:int = hashMap.length;
for(var j:int=0;j<jlen;j++){
var propertyName:String =
String(hashMap.getHashTable()[j].key);
trace(" " + propertyName + ": "
+spec.getProperty(propertyName));
}
trace(" You can have this " +
spec.getProperty("instrumentType") +
" for $" + instrument.getPrice() + "\n---");
}
}else{
trace("Sorry, Bryan, we have nothing for you.");
}
}
private function initializeInventory(inventory:Inventory):void {
var properties:HashMap = new HashMap();
properties.put("instrumentType", InstrumentType.GUITAR);
properties.put("builder", Builder.COLLINGS);
properties.put("model", "CJ");
properties.put("type", Type.ACOUSTIC);
properties.put("numStrings", 6);
properties.put("topWood", Wood.INDIAN_ROSEWOOD);
properties.put("backWood", Wood.SITKA);
inventory.addInstrument("11277", 3999.95,
new InstrumentSpec(properties.clone()));

properties.put("builder", Builder.MARTIN);
properties.put("model", "D-18");
properties.put("topWood", Wood.MAHOGANY);
properties.put("backWood", Wood.ADIRONDACK);
inventory.addInstrument("122784", 5495.95,
new InstrumentSpec(properties.clone()));

properties.put("builder", Builder.FENDER);
properties.put("model", "Stratocastor");
properties.put("type", Type.ELECTRIC);
properties.put("topWood", Wood.ALDER);
properties.put("backWood", Wood.ALDER);
inventory.addInstrument("V95693", 1499.95,
new InstrumentSpec(properties.clone()));
inventory.addInstrument("V9512", 1549.95,
new InstrumentSpec(properties.clone()));

properties.put("builder", Builder.GIBSON);
properties.put("model", "Les Paul");
properties.put("topWood", Wood.MAPLE);
properties.put("backWood", Wood.MAPLE);
inventory.addInstrument("70108276", 2295.95,
new InstrumentSpec(properties.clone()));

properties.put("model", "SG '61 Reissue");
properties.put("topWood", Wood.MAHOGANY);
properties.put("backWood", Wood.MAHOGANY);
inventory.addInstrument("82765501", 1890.95,
new InstrumentSpec(properties.clone()));

properties.put("instrumentType", InstrumentType.MANDOLIN);
properties.put("type", Type.ACOUSTIC);
properties.put("model", "F-5G");
properties.put("backWood", Wood.MAPLE);
properties.put("topWood", Wood.MAPLE);
properties.remove("numStrings");
inventory.addInstrument("9019920", 5495.99,
new InstrumentSpec(properties.clone()));

properties.put("instrumentType", InstrumentType.BANJO);
properties.put("model", "RB-3 Wreath");
properties.remove("topWood");
properties.put("numStrings", 5);
inventory.addInstrument("8900231", 2945.95,
new InstrumentSpec(properties.clone()));
}
}
}
//  Inventory.as
package{
        public class Inventory{
                private var inventory:Array;
                public function Inventory():void{
                        inventory = new Array();
                }
                public function addInstrument(serialNumber:String,
                price:Number,
                spec:InstrumentSpec):void{
                        var instrument:Instrument = new Instrument(serialNumber,
                        price,
                        spec);
                        inventory.push(instrument);
                }
                public function get(serialNumber:String):Instrument{
                        var len:int = inventory.length;
                        for(var i:int=0;i<len;i++){
                                if(inventory[i].getSerialNumber() == serialNumber){
                                        return inventory[i];
                                }
                        }
                        return null;
                }
                public function search(searchSpec:InstrumentSpec):Array{
                        var matchingInstruments = new Array();
                        var len:int = inventory.length;
                        for(var i:int=0;i<len;i++){
                                if(inventory[i].getSpec().matches(searchSpec)){
                                        matchingInstruments.push(inventory[i]);
                                }
                        }
                        return matchingInstruments;
                }
        }

}
// Instrument.as
package{
        public class Instrument{
                private var serialNumber:String;
                private var price:Number;
                private var spec:InstrumentSpec;
                public function Instrument(serialNumber:String,
                price:Number,
                spec:InstrumentSpec) {
                        this.serialNumber = serialNumber;
                        this.price = price;
                        this.spec = spec;
                }
                public function getSerialNumber():String {
                        return serialNumber;
                }
                public function getPrice():Number{
                        return price;
                }
                public function setPrice(newPrice:Number):void{
                        price = newPrice;
                }
                public function getSpec():InstrumentSpec{
                        return spec;
                }
        }
}
// InstrumentSpec.as
package{
        public class InstrumentSpec{
                private var properties:HashMap;
                public function InstrumentSpec(properties:HashMap=null):void{
                        if (properties == null) {
                                this.properties = new HashMap();
                        } else {
                                this.properties = new HashMap(properties);
                        }
                }
                public function getProperty(propertyName:String):*{
                        return properties.getValue(propertyName);
                }
                public function getProperties():HashMap{
                        return properties;
                }
                public function matches(otherSpec:InstrumentSpec):Boolean{
                        var otherHashMap:HashMap = otherSpec.getProperties();
                        var len:int = otherHashMap.length;

                        var hashTable:Array = otherHashMap.getHashTable();

                        for (var i:int=0; i<len; i++ ) {
                                var propertyName:String = String(hashTable[i].key);

                                if (String(properties.getValue(propertyName)) !=
                                String(otherHashMap.getValue(propertyName))) {
                                        return false;
                                }
                        }
                        return true;
                }
        }
}
// HashMap.as
package{
        import flash.utils.ByteArray;
        public class HashMap{
                private var hashTable:Array;
                public function HashMap(hm:HashMap=null):void{
                        if (hm == null) {
                                hashTable = new Array();
                        } else {
                                hashTable = hm.getHashTable();
                        }
                }
                public function put(k:*, v:*):*{
                        var len:int = length;
                        for(var i:int=0;i<len;i++){
                                if(hashTable[i].key == k){
                                        hashTable[i].key = k;
                                        hashTable[i].value = v;
                                        return v;
                                }
                        }
                        hashTable.push({key:k, value:v});
                        return v;
                }
                public function remove(k:*):Boolean{
                        var len:int = length;
                        for(var i:int=0;i<len;i++){
                                if(hashTable[i].key == k){
                                        hashTable.splice(i,1);
                                        return true;
                                }
                        }
                        return false;
                }
                public function getValue(k:*):*{
                        var len:int = length;
                        for(var i:int=0;i<len;i++){
                                if(hashTable[i].key == k){
                                        return hashTable[i].value;
                                }
                        }
                        return null;
                }
                // this function for test
                public function allTrace():void{
                        var len:int = length;
                        for(var i:int=0;i<len;i++){
                                trace(String(hashTable[i].key)+" : "+String(hashTable[i].value));
                        }
                }
                public function getHashTable():Array{
                        return hashTable;
                }
                public function setHashTable(hashTable:Array):void{
                        this.hashTable = hashTable;
                }
                public function get length():int{
                        return hashTable.length;
                }
                public function clone():HashMap{
                        var hm:HashMap = new HashMap();
                        var hashTableBA:ByteArray = new ByteArray();
                        hashTableBA.writeObject(hashTable);
                        hashTableBA.position = 0;
                        var ary:Array = hashTableBA.readObject() as Array;
                        hm.setHashTable(ary);
                        return hm;
                }
        }
}
// Builder.as
package{
        public class Builder{
                public static const FENDER = "Fender";
                public static const MARTIN = "Martin";
                public static const GIBSON = "Gibson";
                public static const COLLINGS = "Collings";
                public static const OLSON = "Olson";
                public static const RYAN = "Ryan";
                public static const PRS = "PRS";
        }
}

// InstrumentType.as

package{
        public class InstrumentType{
                public static const GUITAR = "Guitar";
                public static const BANJO = "Banjo";
                public static const DOBRO = "Dobro";
                public static const FIDDLE = "Fiddle";
                public static const BASS = "Bass";
                public static const MANDOLIN = "Mandolin";
        }
}

// Type.as

package{
        public class Type{
                public static const ACOUSTIC = "acoustic";
                public static const ELECTRIC = "Belectric";
        }
}

// Wood.as

package{
        public class Wood{
                public static const INDIAN_ROSEWOOD = "Indian Rosewood";
                public static const BRAZILIAN_ROSEWOOD = "Brazilian Rosewood";
                public static const MAHOGANY = "Mahogany";
                public static const MAPLE = "Maple";
                public static const COCOBOLO = "Cocobolo";
                public static const CEDAR = "Cedar";
                public static const ADIRONDACK = "Adirondack";
                public static const ALDER = "Alder";
                public static const SITKA = "Sitka";
        }
}



 

    

설정

트랙백

댓글

[FlashCS3] AIR for FlashCS3 업데이트

Programming/ActionScript 3.0 2007. 8. 25. 23:44
AIR이 공식적으로 FlashCS3에 서포트 되었다. 예전 포스트 grant skinner의 Flash CS3용 Adobe AIR extension 에서 개인이 만든 AIR extension 소개한 적이 있는데 adobe에서 공식적으로 AIR을 FlashCS3에서 생성할 수 있도록 지원하는 update 파일을 배포했다. 버전은 현재 AIR 1.0이다.  업데이트 파일은 아래 링크에서 다운로드 할 수 있다.

http://labs.adobe.com/wiki/index.php/AIR:Flash_CS3_Professional_Update

air파일 정보 세팅과 air파일 생성은 Commands 메뉴에 추가된 AIR-Application and Package Settings 와 AIR-Pacakge AIR File 명령을 통해서 세팅 및 생성할 수 있다.





사용자 삽입 이미지






    

설정

트랙백

댓글