남 캘리포니아대에서 개발한 360도 입체영상 디스플레이를 개발

User Interface/Etc 2007. 9. 2. 09:53
남 캘리포니아 대학의 연구자들이 360도 입체영상 디스플레이를 개발했다.이 디스플레이는 "holographic diffuser"라고 하는 특수 필름을 붙인 회전거울과 고속 프로젝터 DVI의 특수한 디코더를 통해 구성되어 있다고 한다. 아래 동영상에서 보면 흑백의 와이어 프레임 모형이나 다각형 모델, 실사 입체 모형도 표시할 수 있어서 컬러 표시도 가능하다고 한다.

이 holographic diffuser의 기술은 .세로 방향에는 난반사하지만 횡 방향에는 거의 난반사가 일어나지 않는다고 하는 특성을 이용하였다고 한다. 이를 통해서 입체영상을 표현 할 수 있고 본체에 대해서 앵글이 높거나 낮아도 상을 볼 수 있게 되어 있다.






논문 : http://gl.ict.usc.edu/Research/3DDisplay/3Ddisplay_preprint.pdf

    

설정

트랙백

댓글

[AS3] SelectArea, DrawShape and Sewing

Project/Programming 2007. 8. 31. 18:30
예전에 http://www.tileui.com/ 사이트를 보면 스테이지 상에 있는 복수의 오브젝트를 선택할 때 직사각형으로 선택하는 것이 아닌 draw 형태를 이용하여 필요한 요소만 선택할 수 있다. 이 것을 보고 그려진 Shape를 통해서 선택할 수 있도록 하면 되겠다 싶어서 구현해 봤다.

일단은 클래스의 구조는 아래와 같이 작성했다.

DrawShape.as
이 클래스는 Point 요소를 가지고 있는 Array를 전달하고 그것을 통해 그려진 Shape를 돌려주는 클래스

Sewing.as
이 클래스는 Point 요소를 가지고 있는 Array를 전달하고 그것을 통해 외각선을 그려주는 클래스

SelectArea.as
이 클래스는 DrawShape와 Sewing클래스를 통해 그려진 Shape에 걸쳐진 오브젝트들을 Array로 반환하는 메소드를 가지고 있다. 여기에는 마우스를 UP을 했을 때 Event를 dispatch하게 되는데 이벤트를 받는 메소드에서 기존의 array 요소 중에서 선택된 오브젝트 요소를 가지고 있는 새로운 배열을 참조할 수 있게 하였다.

아래 예제에서는 랜덤한 위치에 생성한 오브젝트들을 마우스 down and drag, up을 통해서 선택을 하면 대각선 방향으로 정렬하게 해놨는데 대각선으로 정렬되는 것은 일정한 규칙이 있는 것은 아니고 디테일하게 하기 귀찮아서 그냥 되는대로 정렬해놨다…쿠쿠 목적이 없는 예제는 슬슬 힘이 빠진다는..;;

    

설정

트랙백

댓글

[OOP] 디자인 원리 - Head First-OOAD

Programming/Design Patterns 2007. 8. 28. 07:35
『Head First Object-Oriented Analysis&Design』 책의 내용 중에 8장에서 다루고 있는 디자인 원리에 관한 좋은 내용이 있어서 소개한다.

여담 : 여러분들 마우스 옆에 핸드폰 놓지 맙시다. 자꾸 헷갈리네…쿠쿠

일단 와 닫는 짧은 문장 하나, “모방은 바보 같은 짓을 하지 않기 위한 가장 진지한 방안입니다.” 이 이야기는 새롭고 독창적인 방법이 좋을 수 있으나 그 방법은 기존에 같은 문제를 해결한 것이 없거나 자신의 독창적인 방법이 나은 결과를 가져왔을 때만 유효한 해결책이라는 설명이다. 이런 비슷한 내용은 디자인 패턴 관련 책에서 주로 다루고 있는데 이미 입증된 것이 항상 옳은 방법일 수는 없으나 가장 안전한 방법일 듯 싶다.

디자인 원리 : 디자인 원리는 코드를 좀 더 유지보수하기 쉽고, 유연하고, 확장하기 쉽게 만들기 위해, 코드의 작성이나 디자인에 적용되는 기본 도구 또는 기법이다.

객체지향 원리
1.    변하는 것을 캡슐화하라.
2.    구현에 의존하기 보다는 인터페이스에 의존하도록 코딩하라.
3.    각 클래스는 변경 요인이 오직 하나이어야 한다.
4.    클래스는 행동과 기능에 관한 것이다.

위와 같은 디자인 원리에 대한 구체적인 내용을 살펴보면 아래와 같다.

원리 1)
개방-폐쇄의 원리 OCP(Open-Closed Principle)

클래스는 확장에는 열려 있고, 수정에는 닫혀 있어야 한다는 것으로 보통 추상클래스의 확장과 override 개념에서 찾을 수 있을 듯싶다. 추상 클래스(상위 클래스) 자체는 하나의 독립되고 완전한 기능을 수행하며 수정에 닫혀 있고 그 추상 클래스를 확장하는 클래스에서 개별적으로 필요한 기능은 오버라이드를 통해서 고유의 기능을 수행할 수 있도록 하는 개념을 의미한다.

Java에서는 파라미터의 형태, 파라미터의 개수, 메소드의 접근성이 다를 경우에는 전혀 다른 메소드로 인식할 수 있다. 이 때문에 private로 선언된 함수를 사용하되 그 함수와 다른 기능을 수행하는 같은 메소드명의 public 메소드를 새로 만들어 외부에서 접근할 수 있도록 하는 경우도 이 OCP원리에 부합되는 예라고 할 수 있다.

원리 2)
반복 금지의 원리 DRY(Don’t Repeat Yourself)

공통되는 부분을 추출하여 추상화하고 한 곳에 두어 중복 코드를 피하라는 내용이다. 책에서는 2장에서 설명한 강아지 문(외국의 전원주택을 보면 애완견이 스스로 출입할 수 있도록 현관문 아래에 작은 문을 달아놓은 것을 프로그래밍한 내용)에 대한 이야기로 개념을 설명하고 있는데 리모컨을 눌렀을 때 열려있던 문은 닫히고 닫혀있던 문은 여는 기능을 수행한다. 또한 문은 리모컨 뿐만이 아니라 강아지가 짖는 소리에도 열린다. 그리고 열려있던 문은 일정한 시간이 지나면 자동으로 닫게 설계되어 있는데 이때 일정한 시간이 흐르면 자동으로 닫히는 기능을 리모컨 기능에도 넣고 강아지가 짖는 것을 판별하는 기능에도 넣었을 때 코드가 중복되는 것을 강아지 문 하나에 넣어 문이 open 되었을 때 일정 시간이 지나면 닫히게 할 수 있다는 것이다. 강아지 문을 여는 행위를 지시하는 곳은 두 곳이지만 이 두 곳 모두 일정 시간이 지나면 자동으로 닫히는 기능을 넣는 중복을 피하고 그 행위를 하는 강아지 문에 기능을 넣는 것이 좋다는 것이다. 하나의 요구사항은 한 곳에 두어 코드 중복으로 인한 유지보수의 어려움을 없애야 한다는 내용이다.

원리 3)
단일 책임의 원리 SRP(Single Responsibility Principle)

시스템의 모든 객체는 하나의 책임만을 가지며, 객체가 제공하는 모든 서비스는 그 하나의 책임을 수행하는 데 집중되어 있어야 한다는 내용이다. 이는 얼핏 보면 반복 금지의 원리와 비슷하다고 볼 수 있는데, 반복금지의 원리는 SRP를 포괄하는 내용이라고 볼 수 있다. 반복금지의 원리는 하나의 기능을 한 곳에 두자는 내용으로 그 한 곳이 클래스가 될 수도 있고 코드가 될 수도 있다. 하지만 SRP는 클래스가 한 가지 일만 잘하게 하자는 내용이다.

책에서는 간단하면서도 재미있는 방법을 제한하고 있는데 아래와 같은 방법이다.

[*]이 자신을 [*]한다.를 한 줄에 하나씩 작성하고 첫 번째 빈칸에는 자신 클래스명을 기입하고 두 번째 빈칸에는 자신 클래스에서 사용하고 있는 메소드명을 기입하는 것이다. 이렇게 작성하여 한 줄씩 큰 소리로 읽어보면 ‘무엇이 자신을 무엇 한다’는 말이 맞지 않은 경우가 SRP를 위반할 가능성이 높다는 이야기다. 예를 들면 다음과 같다.

Automobile 이라는 클래스에 아래와 같은 메소드들이 있다고 가정하면
1.    start()
2.    stop()
3.    changeTires(Tire[*])
4.    drive()
5.    wash()
6.    checkOil()
7.    getOil():int

1.    [Automobile]이(가) 자신을 [start](출발한다).
2.    [Automobile]이(가) 자신을 [stop](멈춘다).
3.    [Automobile]이(가) 자신을 [changeTires](타이어를 간다).
4.    [Automobile]이(가) 자신을 [drive](운전한다).
5.    [Automobile]이(가) 자신을 [wash](닦는다).
6.    [Automobile]이(가) 자신을 [checkOil](오일을 점검한다).
7.    [Automobile]이(가) 자신을 [getOil](기름을 얻는다).

위와 같이 썼을 때 책에서는 3개의 메소드는 SRP를 따르고 있고 나머지 4개의 경우에는 SRP를 따르지 않고 있다고 이야기 하고 있다. 다시 말해서 3개의 메소드는 Automobile 클래스에 있어야 하지만 나머지 4개의 메소드는 따로 빼내어 다른 클래스로 만들어야 단일 책임의 원리를 따를 수 있다는 이야기다.

답은 며칠 후에 이 포스트에 추가로 올려놓도록 할 테니 여러분들도 한번 고민해 보고 어떤 것이 단일 책임의 원리를 위반하고 있다고 생각하는지 댓글을 남겨보면 좋겠다. 책에서는 SRP.는 단지 가이드라인일 뿐이지 꼭 이 방법을 따라야 한다는 것은 아니라고 설명하고 있다. 클래스의 기능과 프로젝트에 대한 상식, 그리고 경험을 통해서 디테일한 부분을 스스로 결정해야 한다고 설명하고 있으니 부담 없이 참여해 보시길…

원리 4)
리스코프 치환 원리 LSP(Liskov Substitution Principle)

자식 타입들은 부모 타입들이 사용되는 곳에 대체될 수 있어야 한다는 내용이다. 이는 잘 디자인된 상속에 관한 내용으로 부모 클래스를 상속할 때, 부모 클래스가 사용되는 곳은 아무 문제없이 자식 클래스도 사용할 수 있어야 한다는 것이다. 그렇지 않으면 상속을 잘못 사용하고 있다는 것.

예를 들어 Board라는 클래스는 대부분의 메소드에서 x와 y의 인자를 사용하지만 3DBoard 클래스의 경우는 x,y,z 인자를 사용한다. 이때 3DBoard 클래스가 Board 클래스를 상속하였을 때 3DBoard 클래스에서는 상속된 Board 클래스의 기능이 전혀 필요 없음에도 상속을 하는 경우이다.

이렇게 되었을 때는 상속을 통해서 얻는 것보다 잃는 것이 많아지는데 이는 불필요한 메소드와 구조상 가독성이 떨어지기 때문이다. 불필요한 상속을 피하고 LSP 따를 수 있는 방법으로는 아래와 같은 방법이 있을 수 있다고 설명한다.

1.    상속 보다는 연관을 사용한다
이것은 3DBoard에 Board 인스턴스를 가지고 있으며 Board를 사용하되 zpos 값을 통해서 3DBoard를 표현하는 방법이다.

2.    구성(Composition)을 사용하여 다른 클래스들의 행동을 조합한다.
이 방법은 하나의 인터페이스를 따르는 클래스들의 묶을 배열 형태로 저장하여 필요한 클래스를 동적으로 적용할 수 있는 방법이다. 구성의 경우 구성을 가지고 있는 클래스가 소멸했을 때는 그 클래스에 포함된 구성 요소들도 함께 소멸한다.

3.    집합(Aggregation)을 상용하여 구성에서 구성 요소들이 사라지지 않게 한다.
이 방법은 구성과 비슷하지만 구성 요소들이 외부에서도 사용할 수 있도록 하여 집합을 가지고 있는 인스턴스가 소멸했을 때에도 집합 요소들은 사라지지 않도록 하는 방법이다.

책에서는 LSP위한 방법으로 아래와 같이 정리하고 있다.

1.    위임(Delegation)
클래스의 행동을 변경하고 싶지 않고 그 행동을 스스로 구현하는 것이 그 클래스의 책임이 아닌 경우에는 그 행동을 다른 클래스에 위임(Delegation)한다.

2.    구성(Composition)
구성을 사용하여 하나 또는 여러 개의 클래스, 특히 비슷한 종류의 여러 클래스들로부터 행동을 재사용할 수 있다. 여러분의 객체가 다른 객체를 완전히 소유하고 있는 형태이며, 구성 관계로 연결된 객체는 여러분 객체의 외부에 독립적으로 존재할 수 없다.

3.    집합(Aggregation)
구성 관계의 이점을 바라지만 여러분 객체의 외부에서도 연결된 객체의 행동이 사용되는 경우, 집합을 사용한다.

덧붙여 책에서는 위임과 구성 그리고 집합을 상속보다 선호하면, 대개의 경우 소프트웨어는 더 유연하고, 유지보수성, 확장성, 그리고 재사용성이 좀더 좋아진다고 이야기 하고 있다. 꼭 그런 것은 아니겠지만 LSP를 따르지 않는 상속은 구조를 복잡하게 하고 재사용성이 떨어질 수 있기 때문이라고 할 수 있다. LSP를 따르는 상속의 경우에는 상속을 사용하는 것이 바람직할 것으로 생각된다.


    

설정

트랙백

댓글

우리나라 건설 문화?

Miscellaneous/Story 2007. 8. 27. 11:37
얼마 전부터 집 앞 건물에 살던 사람들이 이사 가는가 싶더니 어느 날 이틀 동안 그 큰 건물이 허물어졌다. 건물을 허물면서 날리는 먼지 때문에 이 더위에 창문도 못 열었었는데 건물 허무는데 이틀이 걸렸고 만 하루 동안 건물 잔해가 없어졌고 지금은 건물 기초 공사에 들어갔다.

비가 억수같이 쏟아지는 와중에도 골조 사이에 시멘트를 부어대고 있다. 상식적으로는 비가 올 때 시멘트 작업을 하게 되면 과다한 물기와 기포 때문에 기초공사가 부실해 질 수 있을 듯싶은데 작업 하시는 분들은 비가 와도 아랑곳 없이 작업에 열중이다.

이 속도라면 5층 이상 될 거 같은 건물은 한달 만에도 지어질 수 있을 듯싶다. 우리나라는 재건축에 대한 승인이 떨어지면 설계나 실질적인 공사 과정에서 모니터 하는 시스템이 갖춰져 있지 않은 것 같다. 있다고 한들 힘이 있겠냐만은…

앞 건물이 없어지면서 창문을 열면 시야가 시원했는데 빠른 속도로 건물이 다시금 올라오고 있어서 답답함이 밀려 온다… 내년에 이사를 가야겠다…

    

설정

트랙백

댓글

[FlashPlayer] Adobe Flash Player v9.0.60.184 beta - H.264/HE-AAC지원

Miscellaneous/Etc 2007. 8. 27. 06:37
Adobe Systems는 지난 8월 21일 압축 규격 H.264와 HE-AAC (Hi Efficiency AAC)를 Flash Player에서 지원한다고 발표했다. 현재는 베타판 공개이고 이번 가을에 정식판을 발표할 예정이라고 한다.

베타판은 Flash Player 9 Update Downloads@Labs에서 다운로드 하여 인스톨 할 수 있는데 주의할 것은 기존에 있던 FlashPlayer를 언인스톨하고 설치 해야 한다. H.264가 FlashPlayer에 추가되면 iPod를 재생할 수 있다. H.264/HE-AAC 비디오 재생도 플래시플레이어에서 가능하게 되어 MPEG-4 표준을 따르고 있는 MP4, MOV, 3GP등을 재생할 수 있다고 한다.

현재는 단지 지원한다는 의미로 flv만큼의 퍼포먼스를 기대하기는 어려울 듯싶지만 지원한다는 자체의 의미는 매우 크다고 볼 수 있다. Adobe의 다이나믹 미디어 담당 Mark Randall에 의하면 최신판에서는 그래픽 카드의 하드웨어 가속을 이용할 수 있도록 설계되고 있어 듀얼 코어 프로세스에서 최적화 된다고 한다.

Microsoft는 Silverlight를 통해서 웹비디오계의 흐름에서 Flash의 독점에 도전할 의향인 듯 하다. Microsoft는 이미 MLB.com 등 대기업과 Silverlight 채용을 계약했다고 한다. Microsoft는 현시점에서 H.264의 지원을 이야기하고 있지 않지만 고객의 피드백에 근거해서 지원할 가능성이 있으면 지원할 방침이라고 전하고 있다.

웹비디오 기술의 흐름은 앞으로 웹의 발전 방향의 초석이 될 듯싶다. 메크로미디어가 어도비에 인수되었던 시점은 메크로미디어로서는 절호의 찬스였다는 생각이다. 하지만 어도비가 아니라 구글 쪽에서 메크로미디어를 인수 했다면 어떤 변화가 발생했을까 궁금하다. 간간히 구글이 flash만을 인수하거나 어도비를 인수할 수 있는 가능성에 대해서 조심스럽게 이야기를 하고 있는 듯하다. 어도비가 메크로미디어를 인수할 때 20%이상의 프리미엄이 있었던 것을 감안한다면 인수금이 대단할 것으로 예상된다. 만약 그렇게 된다면 엄청난 이슈가 될 것이지만 그러한 이야기는 구글 쪽에서 서비스 하고 있는 대부분이 FlashPlayer를 통해서 배포되고 있기 때문에 나오는 루머가 아닐까 싶다.

    

설정

트랙백

댓글

플래시 게임 Budapest defenders

Programming/Etc 2007. 8. 26. 19:15
게임 장르를 잘모르지만 이런 장르를 전략시물레이션 게임이라고 하지 않나 싶다. 간단한 스토리지만 플래시 전략 보드게임으로서는 매력적이다.













http://alt.tnt.tv/tntoriginals/thecompany/budapestdefenders/index.htm

사용자 삽입 이미지





    

설정

트랙백

댓글

[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 명령을 통해서 세팅 및 생성할 수 있다.





사용자 삽입 이미지






    

설정

트랙백

댓글

[AS3] Head First - OOAD AS3로 변환

Programming/ActionScript 3.0 2007. 8. 24. 18:43
Head First 시리즈 중에 설계를 위한 객체지향 방법론에 관한 내용을 담고 있는 『Head First Object-Oriented Analysis&Design』 이라는 책이 있다. 책에서 사용한 언어는 Java언어인데 내용 중 기타 판매점의 기타검색 프로그램을 AS3로 수정하였다. 비교적 간단한 구조를 가지고 있지만 막상 하나의 문제를 해결하기 위해 필요한 기능을 구현하고 재사용성이 용이한 구조로 설계하려고 하면 어려움이 많이 발생하는 것 같다. AS3로 변환 과정에서 Java의 enum(열거형 타입 Builder, Type, Wood)는 각 클래스의 static const속성으로 변환하였다.

이 구조는 책의 2장까지 나와 있는 내용 중에서 final 버전이다. 책에서는 이 프로그램을 객체지향의 원리

(변하는 것을 캡슐화하라,
구현에 의존하기 보다는 인터페이스에 의존하도록 코딩하라,
각 클래스는 변경 요인이 오직 하나이어야 한다.)


에 입각해서 다시 5장에서 리펙토링하게 되는데 그 버전은 다음에 바꿔볼 생각이다. 어떤 문제를 풀 때 역행으로 분석해 보는 것도 상당히 도움이 된다.



사용자 삽입 이미지

// FindGuitarTester .as
package{
import flash.display.Sprite;
public class FindGuitarTester extends Sprite{
private var inventory:Inventory;
private var whatErinLikes:GuitarSpec;
private var matchingGuitars:Array;
public function FindGuitarTester():void{
inventory = new Inventory();
initialize();
}
private function initialize():void{
initializeInventory(inventory);
whatErinLikes = new GuitarSpec(Builder.FENDER, "Stratocastor", Type.ELECTRIC, 6, Wood.ALDER, Wood.ALDER);
matchingGuitars = inventory.search(whatErinLikes);
if (matchingGuitars != null) {
trace("Erin, you might like these guitars:");
var len:int = matchingGuitars.length;
for (var i:int=0;i<len;i++) {
var guitar:Guitar = matchingGuitars[i];
var spec:GuitarSpec = guitar.getSpec();
trace(" We have a " +
spec.getBuilder() + " " + spec.getModel() + " " +
spec.getType() + " guitar:\n " +
spec.getBackWood() + " back and sides,\n " +
spec.getTopWood() + " top.\n You can have it for only $" +
guitar.getPrice() + "!\n ----");
}
} else {
trace("Sorry, Erin, we have nothing for you.");
}
}
private function initializeInventory(inventory:Inventory):void {
inventory.addGuitar("11277", 3999.95, new GuitarSpec(Builder.COLLINGS, "CJ", Type.ACOUSTIC, 6, Wood.INDIAN_ROSEWOOD, Wood.SITKA));
inventory.addGuitar("V95693", 1499.95, new GuitarSpec(Builder.FENDER, "Stratocastor", Type.ELECTRIC, 6, Wood.ALDER, Wood.ALDER));
inventory.addGuitar("V9512", 1549.95, new GuitarSpec(Builder.FENDER, "Stratocastor", Type.ELECTRIC, 6, Wood.ALDER, Wood.ALDER));
inventory.addGuitar("122784", 5495.95, new GuitarSpec(Builder.MARTIN, "D-18", Type.ACOUSTIC, 6, Wood.MAHOGANY, Wood.ADIRONDACK));
inventory.addGuitar("76531", 6295.95, new GuitarSpec(Builder.MARTIN, "OM-28", Type.ACOUSTIC, 6, Wood.BRAZILIAN_ROSEWOOD, Wood.ADIRONDACK));
inventory.addGuitar("70108276", 2295.95, new GuitarSpec(Builder.GIBSON, "Les Paul", Type.ELECTRIC, 6, Wood.MAHOGANY, Wood.MAHOGANY));
inventory.addGuitar("82765501", 1890.95, new GuitarSpec(Builder.GIBSON, "SG '61 Reissue", Type.ELECTRIC, 6, Wood.MAHOGANY, Wood.MAHOGANY));
inventory.addGuitar("77023", 6275.95, new GuitarSpec(Builder.MARTIN, "D-28", Type.ACOUSTIC, 6, Wood.BRAZILIAN_ROSEWOOD, Wood.ADIRONDACK));
inventory.addGuitar("1092", 12995.95, new GuitarSpec(Builder.OLSON, "SJ", Type.ACOUSTIC, 12, Wood.INDIAN_ROSEWOOD, Wood.CEDAR));
inventory.addGuitar("566-62", 8999.95, new GuitarSpec(Builder.RYAN, "Cathedral", Type.ACOUSTIC, 12, Wood.COCOBOLO, Wood.CEDAR));
inventory.addGuitar("6 29584", 2100.95, new GuitarSpec(Builder.PRS, "Dave Navarro Signature", Type.ELECTRIC, 6, Wood.MAHOGANY, Wood.MAPLE));
}
}
}

// Inventory.as

package{
        public class Inventory{
                private var guitars:Array;
                public function Inventory():void{
                        guitars = new Array();
                }
                public function addGuitar(serialNumber:String, price:Number, spec:GuitarSpec):void{
                        var guitar:Guitar = new Guitar(serialNumber, price, spec);
                        guitars.push(guitar);
                }
                public function getGuitar(serialNumber:String):Guitar{
                        var len:int = guitars.length;
                        for(var i:int=0;i<len;i++){
                                if(guitars[i].getSerialNumber() == serialNumber){
                                        return guitars[i];
                                }
                        }
                        return null;
                }
                public function search(searchSpec:GuitarSpec):Array{
                        var matchingGuitars = new Array();
                        var len:int = guitars.length;
                        for(var i:int=0;i<len;i++){
                                if(guitars[i].getSpec().matches(searchSpec)){
                                        matchingGuitars.push(guitars[i]);
                                }
                        }
                        return matchingGuitars;
                }
        }

}


// GuitarSpec.as

package {
        public class GuitarSpec {
                private var builder:String;
                private var model:String;
                private var type:String;
                private var numStrings:int;
                private var backWood:String;
                private var topWood:String;

                public function GuitarSpec(builder:String, model:String, type:String, numStrings:int, backWood:String, topWood:String) {
                        this.builder = builder;
                        this.model = model;
                        this.type = type;
                        this.numStrings = numStrings;
                        this.backWood = backWood;
                        this.topWood = topWood;
                }

                public function getBuilder():String {
                        return builder;
                }

                public function getModel():String {
                        return model;
                }

                public function getType():String {
                        return type;
                }

                public function getNumStrings():int {
                        return numStrings;
                }

                public function getBackWood():String {
                        return backWood;
                }

                public function getTopWood():String {
                        return topWood;
                }

                public function matches(otherSpec:GuitarSpec):Boolean {
                        if (builder != otherSpec.getBuilder()) {
                                return false;
                        }
                        if ((model != null) && (model !="") && (model.toLowerCase() != (otherSpec.getModel().toLowerCase()))) {
                                return false;
                        }
                        if (type != otherSpec.getType()) {
                                return false;
                        }
                        if (numStrings != otherSpec.getNumStrings()) {
                                return false;
                        }
                        if (backWood != otherSpec.getBackWood()) {
                                return false;
                        }
                        if (topWood != otherSpec.getTopWood()) {
                                return false;
                        }
                        return true;
                }
        }
}

// Guitar.as
package{
        public class Guitar{
                private var serialNumber:String;
                private var price:Number;
                private var spec:GuitarSpec;
                public function Guitar(serialNumber:String, price:Number, spec:GuitarSpec):void{
                        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():GuitarSpec{
                        return spec;
                }
        }
}

// 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";
        }
}
// 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";
        }
}
// Type.as
package{
        public class Type{
                public static const ACOUSTIC = "acoustic";
                public static const ELECTRIC = "Belectric";
        }
}
    

설정

트랙백

댓글

[FlashCS3] AlignAssist Extension

Programming/ActionScript 3.0 2007. 8. 23. 09:17
AlignAssist Extension은 스테이지에 있는 복수의 심볼을 원형으로 배치해 주는 Extension이다. 일본 사람이 만든 것으로 익스텐션을 설치하면 익스텐션 설명이 일본어로 되어 있는데 내용은 다음과 같다.

 ■AlignAssist에 대해
 선택한 심볼을 지정한 수치 간격으로 정렬합니다.
 본확장 기능은 Macromedia Flash MX 2004에서 사용할 수 있습니다.  다만 환상 정렬 기능에 대해서는 Flash CS3에서만 되니 주의해 주십시오.

 ■사용 방법
 도구모음의[Window]의[Other Panels]의 [AlignAssist]를 선택하세요.




왼쪽과 같이 불특정 좌표로 배치되어 있는 심볼들을 선택하고 익스텐션을 실행하면 오른쪽과 같이 정렬이 가능하다.
 



    

설정

트랙백

댓글

APE : SpringConstraint의 이벤트는 왜...

Project/Programming 2007. 8. 23. 05:50

Collide 이벤트를 가지고 형광등을 표현해 봤다. 형광등의 진공 유리관에도 collide 이벤트를 적용하려고 했었는데 SpringConstraint에서 이벤트 반응을 하지 않는다. 구조상으로는 SpringConstraint -> AbstractConstraint -> AbstractItem -> EventDispatcher 와 같은 상속관계를 갖고 있음에도 이벤트에 반응하지 않는 것이 좀 이상하다.

일단은 진공관에 대한 이벤트 반응과 collidable을 false로 해 놓았다.


    

설정

트랙백

댓글

[AS3] APE : CollisionCircleParticle

Programming/Physics Engine 2007. 8. 18. 06:37
APE의 RectangleParticle 클래스를 이용해서 파티클을 생성하고 등록할 경우에는 자체 rotation (angle) 표현을 하지 못한다. 이는 CircleParticle의 경우도 같다. 하지만 CircleParticle을 상속하고 있는 WheelParticle의 경우에는 자체 angle값을 가지고 있어서 마찰과 각도에 따라서 자체 회전을 하게 된다. 아래 실험한 오브젝트의 경우도 WheelParticle을 통해서 생성한 오브젝트들이기 때문에 회전이 가능하다.

화면에서 마우스를 down한 상태에서 시간의 흐름에 따라 원형의 크기가 커지는데 Max 값은 반지름 80으로 한정하였다. 생성한 오브젝트를 MouseDown and Drag하면 힘의 방향을 바꿀 수 있으며 MouseUp을 하게 되면 마우스 포인트와의 SpringConstraint를 removeConstraint를 실행하여 연결을 끊어 주었다. 이러한 형태는 앙드레 미쉘이 만들고 있는 Revive의 엔진 자체에 있는 마우스 이벤트와 비슷하지만 구현 방법은 아마 다를 듯싶다.

오브젝트가 없는 화면에서 위에서 생성한 방법으로 생성할 수 있는 오브젝트의 개수는 10개로 한정하였다. 생성한 모든 오브젝트들은 서로 collision이 가능하다.(외벽 또한 그러함) 8개로 오브젝트를 한정한 이유는 오브젝트가 많으면 지누 컴이 뻑난다.(쿠쿠)

이러한 형태를 어디에 쓸 수 있을 지는 생각해 봐야겠다. 원래 이런 형태로 테스트 하려고 했던 것은 아니었는데 하다 보니…

원래 하려고 했던 것은 위에서 언급했던 것과 같이 RectangleParticle의 경우 자체 angle이 지원되지 않아서 중력에 의해서 외부의 충격을 받았을 때 WheelParticle처럼 회전을 하지 못한다는 것을 고민하다가 APE 제작자 alec cove와 APE를 사용하는 kiosk(키오스크 작업을 하는지 이름이 그러한지 모르겠다.) 와의 대화를 보고 알게 되었다. 방법은 아래와 같다.

4면에 대한 충돌과 각도에 따라 회전이 가능한 사각형의 오브젝트를 만들 때는 4점이 되는 모서리 부분에 CircleParticle을 생성하고 그 모서리의 외각선을 따라 각각 4개의 SpringConstraint로 연결해 준다. 이렇게만 하면 4점이 모두 연결 되었으나 외각선에 따라 연결되었기 때문에 충격을 받으면 쓰러지듯이 퍼져버린다. 이를 방지하기 위해서 모서리 4개 중에서 대각선으로 마주보는 CircleParticle들을 연결하는 2개의 SpringConstraint로 연결하되, 그 연결은 non-collidable springs 이어야 한다는 점이다.

위와 같은 방법으로 Group에 추가하면 사각형이 생기고 그 사각형 안에 X자 모양의 두 개의 선이 대각선으로 연결된 모양이 된다. 이렇게 만들어지면 외부의 충격이나 중력에 의해서 다른 그룹에 있는 particle들과의 충돌에 의해서 각도와 좌표가 바뀌는 CustomRectangleParticle을 생성할 수 있다. 이런 방법으로 사각형뿐만 아니라 다각형들도 연결을 통해서 생성할 수가 있다.

그러데 하다 보니 문제가 좀 있다. 4개의 모서리에 있는 CircleParticle의 크기를 작게 할 경우 SpringConstraint도 함께 무게가 실리지 않아서 다른 오브젝트와 충돌했을 때 그 안쪽으로 collision된 오브젝트들이 뚫고 들어온다는 점이다. 엔진의 계산 값이 벗어 났을 때는 오류가 발생한다. 이는 좀더 고민해 봐야겠다.



    

설정

트랙백

댓글

Google의 애드센스를 달다...

Miscellaneous/Story 2007. 8. 16. 22:09
재미 삼아 Google의 애드센스를 달아보았다. 블로그에 외부의 광고를 단다는 것이 디자인 적으로나 컨텐츠의 가독성 면에서도 좋지 않을 것이라는 생각에서 그 동안 달지 않았었는데 텍스트 색과 배경색 크기 등을 비교적 다양하게 지정할 수 있어서 적용해 보았다.

https://www.google.com/adsense/ 이곳을 방문하면 한글로 등록 및 안내를 해주고 있어서 초기 애드센스 등록할 때보다는 손쉽게 계정을 만들어 적용할 수 있다. 등록 요청을 하게 되면 일정기간, 보통 2일 정도 소요된다고 하는데 나 같은 경우는 오전에 신청하고 오후에 메일을 통해서 승인이 떨어졌다.

메일이 도착하면 안내하는 웹사이트에 접속하여 등록 과정을 거치게 되는데 개인 정보입력에서 영문 집주소를 입력하는 부분이 있다. 이는 수익이 일정금액(100달러)에 도달 했을 때 기준으로 수표를 우편으로 받을 곳이기에 정확하게 표기할 필요가 있다.

영문 주소 번역은 웹사이트에서도 간혹 지원하고 있는 듯 한데 아래 올려놓는 파일을 다운 받아서 사용하면 유용할 듯싶다.



개인정보까지 모두 마무리하면 자신이 노출하고자 하는 광고 형태를 선택할 수 있다. 종류는 콘텐츠용 애드센스, 검색용 애드센스, 추천 이렇게 3 종류로 구분되며 현 블로그의 경우는 콘텐츠용 애드센스에 해당한다.

콘텐츠용 애드센스로 들어가면 광고 단위와 광고색상 및 추가옵션을 선택할 수 있다. 설정을 끝내고 다음을 클릭하면 채널 등록이 있는데 채널 별로 광고를 관리하는 기능 같은데 자세한 것은 아직 모르겠다. 나 같은 경우는 블로그 주소를 가지고 타겟팅 기능 채널 하나를 추가했다.

그러고 다음으로 넘어가면 애드센스 코드를 볼 수 있는데 이 코드를 복사해서 적용하고자 하는 블로그나 웹사이트의 해당 페이지 <body> </body> 안에 적당히 적용하면 페이지 내에서 볼 수 있게 된다. 애드센스 코드를 임의로 변경할 경우 수익 지불을 거부당할 수 있다고 하니 설정한대로 적용하는 것이 바람직할 것 같다.

초기에는 광고가 나타나지 않고 추가옵션에서 설정한 대체 광고 또는 색상이 자주 노출된다고 하니 등록 과정을 마치고 하루 정도 지나봐야 할 듯싶다. 일단 애드센스를 다는 과정은 생성된 코드를 html에 적용하는 것 까지만 하면 모든 설정은 끝난 것이니 지켜보면 될 듯싶다.

간혹 부정클릭으로 인해서 Google로부터 수익 지급을 거부당하는 사람들이 있는 듯 하다. 부정 클릭은 대부분 본의 아니게 외부의 부정클릭을 유도하는 공격을 받았을 경우에 많이 발생하는 듯 싶다. 이 또한 대책을 세워야 하지 않을까 싶다… 검색페이지에서 애드센스에 관련된 정보를 검색해 보면 많은 자료들을 얻을 수 있다.

    

설정

트랙백

댓글

APE(Actionscript Physics Engine) Class Diagram

Project/Programming 2007. 8. 16. 10:05

기존에 만들었던 APE의 UML에서 Association 표기가 없었던 것을 추가하고 기존에 잘못 되었던 부분을 수정했다. 클래스 소스를 기준으로 작성된 class diagram이므로 정확하지 않을 수 있지만 대체적으로 package를 분석하는데 도움이 될 것 같다.

아래 풀사이즈 jpg이미지와 플래시로 만들어 놓은 파일을 올려놓는다.  






사용자 삽입 이미지





    

설정

트랙백

댓글

[AS3] TextField 길이를 벗어나는 글자는 ...으로

Programming/ActionScript 3.0 2007. 8. 16. 03:13
이 클래스는 인수로 지정한 TextField의 width길이보다 text 내용이 길어질 경우에 뒤에 임의로 "..."을 append 하는 클래스다. static 메소드 형태로 만들려다가 동적으로 TextField의 width 값을 변경할 경우에도 편하게 사용할 수 있도록 만들었다. 실제적으로 동적으로 사이즈를 변경해야 하는 경우가 많지는 않겠지만 브라우저의 사이즈에 따라 유동적으로 TextField의 길이를 변경해야 할 경우에는 유용하게 사용할 수 있을 듯싶다.

아래는 위 클래스를 이용하여 동적으로 TextField의 사이즈를 변경하는 예이다.









아래는 클래스 소스 원본
package jasu.display{
        import flash.text.TextField;
        public class CutTextField {
                private var _tf:TextField;
                private var _t:String;
                public function CutTextField(tf:TextField):void {
                        _tf = tf;
                        _t = tf.text;
                        cutText();
                }
                public function cutText():void {
                        if (_tf.maxScrollH > 0) {
                                _tf.appendText("...");
                                while (_tf.maxScrollH > 0) {
                                        var str:Array=_tf.text.split("");
                                        var len:int = str.length;
                                        str.splice(len - 4,1);
                                        _tf.text=str.join("");
                                }
                        }
                }
                public function setTextField(tf:TextField):void {
                        _tf = tf;
                        _t = tf.text;
                }
                public function getTextField():TextField {
                        return _tf;
                }
                public function set width(w:int):void {
                        _tf.width = w;
                        _tf.text = _t;
                }
                public function get width():int {
                        return _tf.width;
                }
                public function set text(t:String):void {
                        _tf.text = _t = t;

                }
                public function get text():String {
                        return _t;
                }
        }
}
    

설정

트랙백

댓글

[AS3] 지원하는 신기능 Best 10

Programming/ActionScript 3.0 2007. 8. 14. 13:03
1. 복수의 변수의 출력이 편하게:trace
인수에 변수를 복수 건네주면 자동적으로 공백으로 구분하여 출력한다. 3.0 이전에도 굳이 필요하다면 trace([a,b])와 같은 방법으로 사용하였었는데 뭐 자체 지원이니…
var a:int = 0;
var b:String = 'hgoe';
trace(a, b); // Output: 0 hoge




2. 요소의 순회가 간단히:for each
이전에는 배열의 요소를 순회하는 것은 다음과 같이 하는 것이 정석이었다.
var len:Number = list.length;
for (var i:Number = 0; i < len; ++i) {
trace(list[i]);
}

하지만 3.0에서는 다음과 같이 사용하면 이런 귀찮은 일이 많이 줄어든다. list 안의 요소가 하나씩 element에 대입되어 loop된다.
for each (var element:Object in list) {
trace(element);
}

3. 솔직하게 쓸 수 있게 되었다:default 인수
다음과 같이 인수를 생략 했을 경우의 default값을 간단하게 지정할 수 있다.
function f(arg1:int, arg2:int = 2):void
{
trace(arg1, arg2);
}
f(3, 4); // Output: 3 4
f(3); // Output: 3 2

4. arguments는 필요없다:가변 인수
trace와 같이 얼마든지 인수를 잡는 함수에서는 다음과 같이 쓸 수 있다. 지정한 인수(여기에서는rest )에 나머지의 인수를 배열로서 받을 수가 있다.
function output(separator:String, ...rest:Array):void
{
trace(rest.join(separator));
}
output(':', 1, 2, 3, 4); // Output: 1:2:3:4
output('.', 'a', 'b', 'c'); // Output: a.b.c

5. 모든 형태를 나타낸다:*
어떤 형태가 대입되는지 모르지만 형태를 지정하고 싶을 경우 기존에는 Object가 이용되고 있었지만 AS3에서는 보다 그 의미를 명확하게 하기 위해서, 「* 」(asterisk)라고 하는 형태 지정을 할 수 있다.
var element:* = list[0];

6. 변경되지 않는 상수:const
한 번 값을 설정하면 실행 중에는 변경할 수 없는 이른바 「상수」를 정의할 수 있다.
public class SelectedEvent extends Event
{
public static const SELECTED:String = 'selected';
}

7. 복수의 루프를 단번에 빠진다:label
다중 루프를 단번에 break 하거나 continue 하거나 할 수가 있게 되었다. switch case 에서 친숙한 라벨을 쓰고 break나 continue를 할 때에 그것을 지정하면 그 라벨에 대해서 동작을 한다.
loop: for (var i:int = 0; i < 2; i++) {
for (var j:int = 0; j < 3; j++) {
if ((i == 1) && (j == 0)) {
break loop;
}
trace(i, j);
}
}
/* Output:
0 0
0 1
0 2
*/
설명:「loop 」라는 라벨을 지정하고 그 안에 상자가 된 루프가 있다. 루프는 최초로 i=0 으로부터 1씩 증가하며 한번 증가할 때마다 j루프를 돌게 되는데 if문을 만나는 순간, break에 의해서loop 라벨로부터 탈출(?!)하여 두 루프를 빠져 버리므로 Output과 같은 결과가 된다. 보통 이러한 형태는 인터프리터언어(순차적 언어)에서 주로 사용되었던 방식이었는데 그 복잡한 흐름 때문에 순차적 언어에서도 꺼려하는 방법이었다. 하지만 간단한 내부 알고리즘에서 활용하면 편할 것 같기는 하다.


8. 프롭퍼티의 존재를 간단하게 확인:in

「a in b 」와 같이 쓰면 b의 안에 프롭퍼티 a가 들어가 있으면 true, 그렇지 않으면 false 반환한다.이것에 이용하면 프롭퍼티 존재를 간단하게 조사할 수가 있다.
var obj:Object = {abc: 1, def: 2};
trace('abc' in obj); // Output: true
trace('ghi' in obj); // Output: false

9. 오브젝트가 특정의 형태인가 간단하게 확인:is
「a is b 」와 같이 쓰면 a가 b와 형태가 같거나 b의 서브 클래스의 인스턴스이면 true, 그렇지 않으면 false를 반환한다. 이것에 이용하면 어느 형태인가를 간단하게 조사할 수가 있다.
var s:Sprite = new Sprite();
trace(s is Sprite); // Output: true
trace(s is DisplayObject); // Output: true
trace(s is String); // Output: false

*instanceof 는 직접적인 인스턴스가 아니면 true를 반환하지 않기 때문에 주의해야 한다.
var s:Sprite = new Sprite();
trace(s instanceof Sprite); // Output: true
trace(s instanceof DisplayObject); // Output: false

10. 예외 없이 캐스트:as

보통 다음과 같이 캐스트 하려고 했을 때 형태가 맞지 않으면 예외가 슬로우 된다.
var s:Sprite = Sprite(new Array());
그러나 as를 사용해 캐스트 하면 형태가 맞지 않는 경우, 예외는 슬로우 되지 않고 그 형태의 디폴트값을 돌려준다.
var s:Sprite = new Array() as Sprite;
trace(s); // Output: null ← 형태 지정으로 null을 반환한다.
var n:Number = new Array() as Number;
trace(n); // Output: 0 ← Number의 디폴트값은 0

    

설정

트랙백

댓글

[AS3] WheelParticle 상속

Project/Programming 2007. 8. 12. 22:40
WheelParticle 클래스를 상속하여 Square 클래스를 만들어 봤다. WheelParticle 클래스에서는 angle 메소드를 원하고 있어서 paint 메소드를 오버라이드 할때 그리게 되는 graphics의 rotation에 적용하였다.

화면에서 마우스를 클릭하고 있으면 Square 오브젝트 들이 생성하며 일정한 범위(y값 450) 이상으로 넘어가는 오브젝트는 엔진에서 제외(and sprite 삭제) 하였다.

엔 진에서 제외할 때 더이상 사용하지 않는 sprite인 경우에는 delete 시켜줄 필요가 있다. removeParticle을 실행할 때 cleanup 메소드를 통해서 해당 sprite에 있는 오브젝트들을 removeChildAt 시켜주지만 sprite 그 자체는 메모리에 남아있게 된다.

왼쪽, 오른쪽에는 경계영역을 만들어 분산되는 오브젝트들을 어느정도 밀집시켰다.


    

설정

트랙백

댓글

APE UML 다이어그램

Programming/Physics Engine 2007. 8. 12. 19:11
APE UML 자료를 찾아보려고 하였으나 공개된 UML자료가 없어서 클래스를 토대로 임의로 만들어 놓았다. 위 이미지는 APE의 클래스 명으로 표기한 기본적인 class diagram이다. 아직 APE의 클래스 관계가 제대로 파악되지 않아서 generalization과 realization  관계만을 표시해 놓았다. 위 이미지는  클래스명으로만 간략하게 표시해 놓았지만 아래 파일은  각 클래스에 있는 attribute와 operation도 포함해 놓았으니 ape를 분석하시는 분에게는 도움이 될 듯 싶다. exe파일로 퍼블리시 해 놓았는데 예전에 AS3 API 계층 구조도를 만들 때 사용했던 소스를 그대로 사용하였다.


사용자 삽입 이미지






    

설정

트랙백

댓글

Flash Player 9 실시간 인스톨 상황

Programming/ActionScript 3.0 2007. 8. 10. 10:52




[Flash] http://www.onflex.org/FP9Counter/FP9Counter.swf



현재 Flash Player 9버전 install 상황, 이 숫자의 개념이 머리 속에 들어오지 않는다.





    

설정

트랙백

댓글

왜 자수(jasu)는 닉네임이 자수(jasu)인가?

Miscellaneous/Story 2007. 8. 9. 23:34
가끔 닉네임이 왜 자수(jasu)인지 물어보시는 분들이 있다. 사전을 찾아보면 여러가지 뜻을 볼 수 있는데 사전에서의 자수라는 단어의 뜻은 상당히 상반된 뜻을 지니고 있다.

사실 자수라는 닉네임은 예전에 PC통신 시절 천리안의 모 클럽의 익명 게시판에서 활동을 할 당시에 처음 사용하게 되었는데 작명을 할 때는 다음과 같은 뜻을 생각해서 지은 것이 아니라 그냥 단어의 뉘앙스가 좋아서 사용하게 되었다.

사전에서 나쁜 뜻은 버리고 좋은 뜻으로만 모아보면 다음과 같다.

자수 [自手] : 자기 혼자의 노력이나 힘.
자수 [自守] : 행동이나 말을 스스로 조심하여 지킴.
자수 [自修] : 남의 가르침을 직접 받지 않고 자기의 힘으로 학문을 닦음.


    

설정

트랙백

댓글

2D 물리엔진을 이용한 벽돌깨기 게임

Programming/Physics Engine 2007. 8. 9. 18:29
물리엔진을 이용한 벽돌깨기 게임이 있어 소개한다. 쉐어웨어로 일정한 스테이지 까지는 게임이 가능하니 받아서 한번 해보길 바란다. 기본적인 벽돌깨기 게임과 비슷하지만 오브젝트들의 움직임이 예술이다.




사용자 삽입 이미지

    

설정

트랙백

댓글

인성,적성검사 어렵다 어려워...

Miscellaneous/Story 2007. 8. 9. 18:08
오늘 한국행동과학연구소라는 곳에서 인성, 적성 검사를 받았는데 생각 외로 문제의 난이도가 높다. 문제는 어렵고 시간은 부족하니 한 영역당 20문제에 5분 내지 6분의 시간이 주어져서 문제가 정말 문제로 다가왔다..아흐...

한 영역은 문제를 제대로 파악하지 못하고 헤매다가 몇 분 남겨두고 문제를 파악하는 바람에 몇 문제 풀었나...쿠쿠 수능 시험 이후에 가장 어려운 문제들로 시험 아닌 시험을 보게 된 것 같다.

적성검사의 마지막 문제 중에는 그림 세 개를 제시하고 특이 사항이나 질문에 대한 창의적인 답을 서술하는 문제가 있었는데 첫 번째 그림은 불규칙한 패턴 형태의 그림이었는데 문제는 그 그림을 보고 연상되는 것이 무엇이 있는지 서술하는 것이었다. 밝은 부분관 어두운 부분이 구분되어 물 위에 기름을 부은 것 같아서 그렇게 적었다. 카오스 이론과 결부시켜 이야기를 장황하게 쓰려다가 시간이 부족하여 그냥 대충 규칙이 있다고 이야기 해버렸다.

두 번째 그림은 몇 가지 채소 그림이 있고 그 것들을 음식 이외에 사용할 방법에 대해 서술하라는 문제였는데 가만히 보고 있자니 배도 고프고 해서 한동안은 침만 삼키고 있다가 으깨서 그림을 그린다는 이야기로 마무리 했다.

세 번째 그림은 어떤 여인이 바닷가에 있고 그 근처에는 어지럽게 널려 있는 쓰레기와 드럼통이 있고 그 여인이 서성거리는 그림이었는데 일단 배가 난파되어 배를 만들기 위한 재료를 찾는 모습이라고 적었는데 그림을 더 보고 있자니 근처에 배도 보이고 육지도 그리 멀지 않은 것 같아서 이 사람이 꿈을 꾸고 있다고 적었다..쿠쿠

주어진 시간이라는 것이 사람이 생각할 수 있는 시간을 안 준다. 아나… 생각 많은 놈인데 적성검사가 날 생각 없는 놈으로 만들어 버렸다.

    

설정

트랙백

댓글

SPE(Simple Physics Engine)

Programming/Physics Engine 2007. 8. 9. 00:30
SPE(Simple Physics Engine) 라는 물리엔진인데 전혀 심플하지 않은 것 같다. 언어가 생소한데 무슨 언어인지는 잘 모르겠다... 아무튼 데모로 제공하고 있는 자료가 있어서 다운 받아서 실행해 봤는데 퍼포먼스가 엄청나다 이런 퍼포먼스가 웹상에서 지원이 된다면 엄청난 변화가 일어나지 않을까 싶다.

그 변화의 주축이 플래시라면... 앞으로의 기술 발전에 따라 충분히 가능한 일이 되지 않을 까 싶다. 자료를 다운 받아서 실행하면 바로 데모를 볼 수 있는데 시간 있는 분들은 한번 받아서 즐겨 보시길....









사용자 삽입 이미지


사용자 삽입 이미지 사용자 삽입 이미지 사용자 삽입 이미지


    

설정

트랙백

댓글

[AS3] APE에 추가된 클래스

Programming/Physics Engine 2007. 8. 8. 18:25
APE의 code repository에 보니 다운로드로 제공하고 있는 소스 파일 이외에 3개의 클래스가 은근슬적 추가된 것을 알게 되었다. 3개의 클래스는 IForce, VectorForce, CollsionEvent 이 세개의 클래스다. Force관련 추가된 클래스는 장력에 관련된 클래스를 제공하기 위해 만들어 놓았는데 기존에는
APEngine.addMasslessForce(new Vector(0,3));
형태로 Vector 클래스를 사용하였으나 이와 구분되는 VectorForce를 통해서
APEngine.addForce(new VectorForce(false,0,3));
이러한 형태로 사용하게 되었다. 추가된 VectorForce는 APEngine 클래스의 internal static Array 변수 forces에 등록됨으로써 중력에 관련하여 복합적으로 적용이 가능하게 되었다.  

CollsionEvent 클래스는 충돌을 체크하기 위해 Event 클래스를 확장하여 만들어 놓았다. 이는 AbstractItem 클래스를 확장하고 있는 클래스에 대한 충돌을 이벤트처리하기 위해 만들어져 있다. 실제로 code repository에 있는 AbstractItem 클래스는 EventDispatcher를 상속하고 있다. CollsionEvent에는 아래와 같은 이벤트타입이 있다.
public static const COLLIDE:String = "collide";
public static const FIRST_COLLIDE:String = "firstCollide";
COLLIDE는 충돌이 발생할 때마다 매번 dispatch 하며 FIRST_COLLIDE는 처음 충돌이 발생한 시점에서 한번만 dispatch하게 된다.

이 이벤트 처리는 Flade에서 지원하던 충돌 관련 기능을 추가한 것이다. 이로서 Flade에서 지원하던 대부분의 기능은 APE에 포함된 것으로 보이며 앞으로 오브젝트에 관련된 클래스들이 추가 될 것으로 기대된다.

    

설정

트랙백

댓글

[AS3] Revive 테스트

Project/Programming 2007. 8. 8. 13:37
Circle 오브젝트를 클릭하여 드레그할 수 있다. 중앙 원은 ImmovableCircleInnerSegment(움직임이 없는 중력방향 Inner)이다.



 





 
 


 


    

설정

트랙백

댓글

[AS3] 3대(APE, Revive, Fisix) Physics Engine 정리

Programming/Physics Engine 2007. 8. 8. 11:15
며칠 동안 2D 물리엔진을 검토 테스트해 보고 가장 알려져 있는 3가지 물리엔진에 대한 개인적인 생각을 적어 볼까 한다. 깊이 있게 테스트해보지 않은 관계로 자세한 부분까지 이야기 할 수는 없을 것 같고 개인적으로 테스트해본 결과에 대한 짧은 생각을 정리해 본다. 좀더 깊이 있는 테스트는 각자 관련 사이트에서 소스를 다운 받아서 테스트 해 보길 바란다.











3대 Physics Engine 정리

타이틀

APE

Revive

Fisix

제작

MIT(Alec Cove)

Andre michelle

Fisix 회사

라이센스

LGPL

Free

Free(제한적)

규모

API 문서

Directory Listing Denied

다운로드 한 소스로부터

Adobe Flex2 Language Reference

특징

Simple

고속, 정확

다기능

표현 범위

정방형 파티클 등

베이지어곡석 표면 처리 등

로프, 프렉탈, 지형 등

테스트 예

APE

Revive

Fisix


 

APE

먼저 처음 접했던 것은 APE 물리엔진이었다. 이것은 AS2 버전으로 이미 알려졌던 Flade 엔진을 AS3로 고치면서 새롭게 APE라는 이름으로 나오게 되었다. 3개의 엔진 중에 가장 심플한 클래스 구조를 가지고 있다. 19개의 클래스 중에 public 클래스는 불과 12개 밖에 되지 않기 때문에 소스를 분석하는데도 그리 어렵지 않을 것 같다.

아직 AS2버전에 있던 기능들을 모두 APE에 적용한 상태는 아니기 때문에 앞으로 버전업을 통해서 추가될 것으로 기대된다. 기본적으로 정방형 형태와 파티클 형태인 원들을 만들 수가 있는데 wheel과 같이 자동차 바퀴와 같은 파티클을 통해서 역학운동 표현이 가능하다.

그러나 아직까지 많은 기능을 포함하고 있지 않기 때문에 표현의 범위가 적다. 다각형을 표현할 경우 파티클들의 조합으로 가능할 것으로 생각되지만 실질적인 클래스를 지원하고 있지 않기 때문에 파티클들을 extends 해서 사용할 필요가 있다.

하지만 비교적 간단한 방법으로 표현이 가능하기 때문에 사용상에 어려움은 없다. API 문서를 지원하지만 원본 소스를 직접 보고 테스트 해보는 것이 도움이 될 것 같다.

 
Revive

Revive는 두 번째로 접하게 된 물리 엔진이다. 2005, 2006 MAX conference에도 스피커로 참여했던 Andre michelle이 만든 엔진이다. Revive의 경우는 베이지어 곡선 처리가 가능하여 surface 표현할 때 곡선처리가 가능하다. 물리엔진의 계산 표현이 비교적 정교하여 움직임이 매끄럽고 속도가 빠르다. 마우스 이벤트에 대해 기본적으로 제공하고 있기 때문에 약간의 확장을 통해서 마우스를 통한 인터렉션이 자유롭다.

엔진의 API문서는 제공되고 있지 않으며 소스코드에 있는 몇 개의 샘플을 통해서 충분히 손쉽게 사용해 볼 수 있다. 다운 받은 엔진의 소스를 그대로 사용할 경우 몇 가지 error를 발견할 수 있는데 이는 단순한 package import를 하지 않은 것이기 때문에 필요한 package import하여 사용해야 한다. 이는 아무래도 앙드레미쉘이 class path default로 설정해 놓은 상태에서 클래스를 저장하여 에러를 발견하지 못한 듯 싶다.

Revive도 파티클의 조합으로 다각형을 표현해 볼 수 있는데 경계가 되는 파티클들이 범위를 벗어났을 때 약간을 오류가 발생하고 있어서 다각형의 경우는 새로운 기능이 확장되어야 할 듯 싶다. 이 문제로 Revive package 외에 physics package를 만들어 놓았는데 physics 패키지에서는 경계 부분의 오류를 바로잡은 다각형을 지원하고 있다. 하지만 클래스 자체가 사용하기 용이하게 제작되어 있지 않은 관계로 앞으로 업데이트에 기대를 가져봐야 할 것 같다.

 
클래스 구조

* de/
    o popforge/
        + revive/

                      # application/ - 어플리케이션
                            * SceneContainer.as – 뷰어
                            * Simulation.as - 물리 엔진

                      # display/ - 표시
                            * ExtDrawAPI.as – Graphics을 사용하고 호를 그리는 확장
                            * IDrawAble.as – 표시오브젝트 관련 Interface

                      # forces/ -
                            * FixedSpring.as - 고정 용수철
                            * IForce.as -
힘을 가지는 오브젝트를 위한 Interface
                            * Spring.as -
용수철

                      # geom/ - 지오메트리
                            * BezierCubic.as – 3 베이지어곡선
                            * BezierQuadric.as - 4
베이지어곡선
                            * BoundingBox.as - 바운딘
                            * ICurve.as - 곡선을 위한 Interface
                            * Vector.as - 2
차원 벡터

                      # member/ - 물체
                            * Immovable.as - 움직이지 않는 물체의 base class
                            * ImmovableBezierQuadric.as -
움직이지 않는 4 베이지어곡선
                            * ImmovableCircleInner.as - 움직이지 않는 원
                            * ImmovableCircleInnerSegment.as - 움직이지 않는 호
                            * ImmovableCircleOuter.as - 움직이지 않는 원
                            * ImmovableCircleOuterSegment.as - 움직이지 않는 호
                            * ImmovableGate.as
                            * ImmovableGroup.as -
움직이지 않는 그룹
                            * ImmovablePoint.as - 움직이지 않는 점
                            * Movable.as - 움직이는 물체의 base class
                            * MovableCircle.as -
움직이는 원
                            * MovableParticle.as - 움직이는 점
                            * MovableSegment.as - 움직이는 선

                      # resolve/
                            * DynamicIntersection.as -
동적 접점
                            * IDynamicIntersectionTestAble.as - 동적인 접점을 테스트하는Interface
                            * IResolvable.as

        + surface/ - 인터페이스

                      # display/ - 표시
                            * DefaultTextFormat.as - 이 라이브러리의 디폴트 텍스트 포맷
                            * FPSCounter.as - FPS 카운터

                      # io/ - IO
                            * PopKey.as –
키 코드 상태를 관리
                            * PopMouse.as - mouse button의 상태를 관리

                      # valuation/ -
                            * Potentiometer.as –
미터

Fisix

Fisix 엔진은 0.5 alpha버전으로 공개되어 있으나 위의 APE, Revive 보다 많은 기능을 포함하고 있다. 소스를 다운로드 하면 API문서, 라이브러리, 샘플 6개와 나머지 라이선스와 관련된 텍스트 파일을 볼 수 있다. Public 클래스는 47개 정도 되어 꽤 많은 기능을 제공하고 있다. as파일은 없으며 swc 파일만을 배포하고 있는 듯 하다.

제공하는 샘플
* Example1 … 타이머, 엔진 표현, 직선 표면 1 , 차 바퀴
* Example2 … ENTER_FRAME , 엔진 표현, 차 바퀴
* Example3 … ENTER_FRAME , 엔진 표현, 용수철, 마우스 interaction
* Example4 …
숫자 키1 ~4 ,5 ~6 모드 변환, 파티클의 자동 삭제
* Example5 … 로프, SWF 부품(타이어)
* Example6 …
유모차

Fisix 엔진의 경우는 직접적으로 많이 접해보지 않았기 때문에 다음 기회에 포스트해 보도록 하겠다.


3개 엔진을 접해본 결과 결과적으로 기능적인 면에서는 Fisix가 우위를 점하고 있다고 하겠다. 또한 커뮤니티 사이트도 비교적 활발하게 운영되고 있는 것을 높이 평가할 만 하다. 하지만 구체적은 클래스 구조를 탐구하기 어려운 부분이 있고 다기능으로 인한 클래스 구조의 복잡함은 응용에 있어서 까다로운 부분이 없지 않다.

APE의 경우는 Flade 엔진을 개선한 부분도 있으나 아직까지 많은 기능을 포함하고 있지 않기 때문에 응용 과정에서 기존의 클래스를 확장하여 가공할 필요가 있다. 하지만 기본적으로 원본 클래스를 가공하여 사용하는 것은 라이센스의 규약에 있어서 문제가 될만한 것이기 때문에 기존의 클래스를 가공하기 보다는 확장을 통해서 기능을 추가해 사용해야 할 것으로 보인다.

클래스 구조가 비교적 단조롭기 때문에 물리엔진 보다는 잘 짜여진 클래스 구조를 공부하는데 도움이 될만한 자료라고 생각된다.

Revive의 경우는 앙드레미쉘의 개인적인 성향이 강한 물리엔진이기 때문에 약간의 범용적이지 않은 부분도 보이지만 엔진으로서의 가치와 앞으로 문제점을 보완한다면 충분히 좋은 엔진이 될 것으로 기대된다. 개인적으로는 physics 패키지와 revive 패키지를 적절히 접목하여 좀더 구체적이고 단단한 물리엔진을 만들면 좋을 것 같다.

physics revive 패키지를 분석해 본 결과 세밀한 코드 자체에는 비슷한 부분이 있지만 전체적인 흐름(구조)에서는 다른 형태를 가지고 있어서 이 둘을 하나로 혼합하기에는 적지 않은 시간과 생각이 필요할 듯 싶다. 하지만 앙드레미쉘의 열정이라면 언젠가는 지금보다 바람직한 물리엔진을 만들어 내지 않을까 기대해 본다.

3개의 물리엔진에서 어떤 것이 좋고 어떤 것이 나쁘다는 결론은 내리기 어렵다. 3개의 물리엔진 모두 진화과정에 있기 때문에 앞으로의 업데이트 과정을 지켜봐야 할 듯 싶다. 물리엔진이라는 것이 기본적인 파티클을 통해서 재미적인 결과물을 보기 위한 목표가 될 수 없기 때문에 응용에 있어서 사용하기 편하고 안정성이 높은 것이 높은 점수를 받을 수 밖에 없다
    

설정

트랙백

댓글

연말에 등장하는 FlashPlayer9 update3에서 실현되는 기능 향상이란?

Programming/Etc 2007. 8. 7. 05:55
퍼포먼스 향상에 주력 한 업데이트

2006년 6월에 발표된 flashPlayer9는 flash CS3 시대를 예감 시키는 중요한 내용을 포함하고 있었다. FlashPlayer9는 올 연말에도 대폭적인 업데이트를 예정하고 있다고 한다. Flash나 ActionScript의 향후를 예측하는데 있어서 중요한 FlashPlayer9 update3의 개요에 대해서 Adobe Systems사 FlashPlayer담당 그룹 프로덕트 메니저 Emmy Huang의 이야기다.

Update3은 주로 퍼포먼스 향상에 주력하고 있어 다양한 신기능의 추가나 기능 강화를 도모하고 있다고 한다. 또 이번은 크로스 플랫폼에서 제공하는 것을 중시하고 있고 처음으로 Windows/Macintosh/Linux판을 동시에 출시 한다고 한다.

추가되는 새로운 기능으로서는 크게 나누어 4개가 있는데, 우선 첫 번째로 거론되는 것이 하드웨어의 가속화에 의한 풀 스크린 모드이다.(예전에 포스트로 올려 놓은 것이 있는데 동영상을 위해서 기초적인 기능만을 첨부한 swc파일 컴포넌트로 복사해야 한다)  update3은 하드웨어 스켈링을 하기 위한 랜더링 속도를 향상하여 고해상도인 브라우저상에서 재생하고 있는 동영상을 부드럽게 재생할 수 있는 것이 특징이라고 한다. 물론 종래의 버전에서도 풀 스크린을 서포트하고 있고 고해상도의 동영상을 재생할 수 있었지만 컴퓨터의 처리 능력이 높지 않으면 재생이 어려웠던 것이 사실이다. 그러나 update3에서는 보다 많은 머신으로 고해상도의 동영상을 풀스크린으로 재생 할 수 있다. 『웹 브라우저로 이만큼의 HD 퀄리티의 영상을 제공할 수 있는 것은 adobe에 있어서도 매우 익사이팅한 일입니다』 라고 FlashPlayer 그룹 프로덕트 매니저의 Emmy Huang의 이야기다.

리치 인터넷 어플리케이션 관련 기능 강화


이 밖에도 리치 인터넷 어플리케이션 관련해서도 기능 강화가 있다고 한다. Adobe 플랫폼 컴포넌트에 추가된 새로운 플레이어의 캐시는 플랫폼 라이브러리를 포함하는 장소에서 정확히 브라우저 캐시와 같이 한 번 다운로드를 해 저장하면 두 번째에서는 곧바로 사용할 수 있게 된다고 한다. 이 기능을 우선 최초로 활용하는 것은 Flex 체제라고 한다. 약 500KB 정도의 Flex 파일을 캐시  시키는 것으로 swf파일의 사이즈를 작게 하는 것과 동시에 start up 시간을 단축할 수 있다고 한다. 현재 adobe labs에서 베타판을 다운로드하여 이 기능을 사용해 볼 수 있다. 미래지향적으로 라이브러리를 추가해 나가기 때문에 캐시를 사용해 다양한 작업을 시도할 수 있을 것이라고 이야기한다.

또 Flash와 브라우저와의 통신에 사용하는 API가 있지만 이 커뮤니케이션도 개선되고 있다고 한다. 즉 브라우저의 컴퍼넌트와 FlashPlayer의 통합, 인터그레이션이 보다 좋아지고 있다고 한다.

그 외의 추가 기능은 아래와 같다.

Internet Exploler(IE)에 보안 관련 API가 서포트 되고 있었지만 Windows 플러그인 외에 FireFox에도 서포트 된다는 설명이다.

Flash Media Server(FMS)에 전달되는 컨텐츠의 보호를 할 수 있도록 RTMP 프로토콜로 암호화가 서포트 된다고 한다.

    

설정

트랙백

댓글

[AS3] 무게 중심축과 질량

Project/Programming 2007. 8. 7. 03:08
검은 바탕화면에서 마우스를 Down하고 있으면 CircleParticle을 생성하게 되는데 갯수는 16개로 한정하였다. 중력에 의해서 아래로 하강할 때 스테이지 밖으로 밀려나는 것들에 대해서는 삭제하였다. 
















    

설정

트랙백

댓글

[AS3] Array의 index값이 소수이면 index가 아니다?

Programming/ActionScript 3.0 2007. 8. 6. 12:57
var ary:Array = new Array(111,222,333);
trace(ary[1/2]); // undefined
AS3의 dynamic 클래스의 인스턴스는 실행시 동적으로 프로퍼티를 추가할 수 있는데 예를 들어
var obj:Object = new Object();
obj.value = 444;
trace(obj.value); // 444
위와 같이 obj에 추가한 value 변수의 값을 동적으로 할당할 수 있다. ActionScript에서는 이러한 동적인 프로퍼티의 할당은 해시 맵(연상배열 or 결합배열)으로 되어 있어 [] 연산자로 액세스가 가능하다.
var obj:Object = new Object();
obj.value = 555;
trace(obj["value"]); // 555

obj["name"] = "AS3";
trace(obj.name); // AS3
이와 같이 Array도 dynamic class이므로 동적으로 프로퍼티를 할당할 수 있다.
var ary:Array = new Array(111,222,333);
ary["value"] = 444;
ary["name"] = "AS3";

trace(ary.value); // 444
trace(ary["name"]); // AS3
trace(ary[0]); // 111

배열의 index를 문자열이 아닌 음수나 소수로 할 경우에는 정수로 치환되지 않고 문자열인 결합배열로 취급한다.
var ary:Array = new Array();
ary[1/2] = 111;
trace(ary[0.5]); // 111
trace(ary["0.5"]); // 111

배경에는 length를 통해서 배열 원소의 개수를 취득할 수 있는데 이때 결합배열(문자열 키로 참조)로 되어 있는 것은 length에 포함되지 않는다.
var ary:Array = new Array(111,222,333);
ary[1/2] = 111;
trace(ary.length); // 3

아래와 같이 동적으로 배열의 인덱스 값을 계산하여 사용할 경우에는 int형으로 치환해 주는 것에 주의해야 한다.
var ary:Array = new Array(111,222,333);
ary[int(1/2)] = 444;
trace(ary[0]); // 444

    

설정

트랙백

댓글

[AS3] 1행짜리 Tetris

Programming/ActionScript 3.0 2007. 8. 6. 08:47

[Flash] http://jasu.tistory.com/attachment/cfile9.uf@244FC33F58802128306F6E.swf


게임방법 : [H][L]왼쪽과 오른쪽, [J][K] 회전, [SPACE]는 떨어뜨리기.
게임 화면을 클릭해서 키보드 포커스를 줄 필요가 있다.


* import *를 사용함.
* 정수명이나 이벤트명은 직접적으로 쓰면 import를 생략.
* for문이나 if 의 생략 할 수 있다 {}은 생략.
* const 보다 var를 씀.
* with 사용할 수 있는 곳은 사용.
* true , false 보다 1 ,0
* switch ~case 보다 함수 테이블을 사용.
* new Array() 보다 []
* drawRect()의 endFill()를 생략.
* 인스턴스 변수를 1 행으로 전부 선언하면 var 를 줄일 수 있다.
* 로컬 변수 를 인스턴스 변수로 옮기면 var를 삭제할 수 있다.
* 클래스명과 constructor 이외의 public ,private는 삭제.
* 배열 의 첨자에 사용한 int 형 변수 이외의 「: 형명」은 삭제.
* 변수 이름이나 함수 이름을 1 문자로.
* 개행은 모두 삭제, 연속하는 공백은 하나의 공백으로.
* 연산자 ,{ ,} ,( ,) ,; , 의 전후의 공백은 삭제.
* 「} 」의 직전의 「; 」는 삭제.

이러한 방법으로 외국의 한 ASer가 1872 문자(1.83kb)의 테트리스를 만들어 놓은 것이 있어 올려 놓는다. 0x000000과 같은 것을 0으로 할 수 있겠지만 이미 질려서 여기까지 한다는 제작자의 설명이 있었다. 테트리스는 게임 프로그래밍에 있어서 기초적인 것이지만 프로그래밍의 중요한 구조적 성격을 가지고 있다고 생각된다.

예전 DOS시절에 C언어로 헥사와 테스트리스를 접목한 게임을 만든 적이 있었는데 그때 만들었던 게임의 룰은 테트리스 처럼 가로 행이 채워졌을 때도 삭제하고 대각선과 세로에서도 같은 색이 연속으로 5개 있을 때도 삭제하게 했던 기억이 난다. 도스 시절이었기 때문에 아마도 5.25인치 디스크에 보관을 하다가 잃어버린 것 같다.

Assembly 언어는 대학교 다닐 때 가장 골치 아픈 녀석이었다. 직접 기계어로 작성한다는 매력과 그 속도 면에서 반할만한 언어이기는 했지만 그것을 이해하기에는 나의 두뇌가 너무 아날로그적이었던 기억이다. C언어를 배울 당시에도 point(*) 개념으로 point -> point 까지만 들어가도 그때부터 뇌세포가 사경을 헤맸으니…

그러고 보면 ActionScript는 참 친절한 언어라는 생각이 든다… 나 또한 ActionScript를 향해 좀더 친절해 져야겠다는 생각이 든다.. 쿠쿠



Tetris.as 소스

package{import flash.display.*;import flash.text.*;public class Tetris extends Sprite{var W=10,H=20,T=16,C=[0x000000,0x00FFFF,0xFFFF00,0x22FF22,0xFF2222,0x4444FF,0xFF8844,0xFF22FF],P=[[[1,1,1,1]],[[0,2,0],[2,2,2]],[[3,3,0],[0,3,3]],[[0,4,4],[4,4,0]],[[5,5],[5,0],[5,0]],[[6,6],[0,6],[0,6]],[[7,7],[7,7]]],s=[30,20,10,5],b=[],p,r,t=new TextField(),f=[],l=0,c=0,g,j:int,i:int,v:int,u:int;public function Tetris(){t.x=W*T;t.autoSize="left";t.text="Next:";addChild(t);for(j=0;j<H;++j){b[j]=[];for(i=0;i<W;++i)b[j][i]=0}f[72]=function(){v-=w(v-1,u,p)};f[74]=function(){m(1)};f[75]=function(){m(0)};f[76]=function(){v+=w(v+1,u,p)};f[32]=function(){d();h()};stage.addEventListener("keyDown",function(e){if(f[e.keyCode]){f[e.keyCode]();n()}});h();h();addEventListener("enterFrame",function(e){if(--c<0){c=s[int(l/10)];if(w(v,u+1,p)){++u;n()}else{d();h()}}})}function m(o){var q=new Array(p[0].length);for(j=0;j<q.length;++j)q[j]=[];for(j=0;j<p.length;++j)for(i=0;i<q.length;++i)if(o)q[i][p.length-1-j]=p[j][i];else q[q.length-1-i][j]=p[j][i];if(w(v,u,q))p=q}function n(){with(graphics){clear();for(j=0;j<H;++j)for(i=0;i<W;++i){g=0;if(u<=j&&j<(u+p.length)&&v<=i&&i<(v+p[0].length))g=p[j-u][i-v];if(!g)g=b[j][i];beginFill(C[g]);drawRect(i*T,j*T,T,T)}for(j=0;j<r.length;++j)for(i=0;i<r[j].length;++i){beginFill(C[r[j][i]]);drawRect((i+W+1)*T,(j+2)*T,T,T)}}}function w(x:int,y:int,p){for(j=0;j<p.length;++j){if(0>(y+j)||(y+j)>=H)return 0;for(i=0;i<p[j].length;++i){if(0>(x+i)||(x+i)>=W)return 0;if(p[j][i]&&b[y+j][x+i])return 0}}return 1}function d(){for(;w(v,u+1,p);u++);for(j=0;j<p.length;++j)for(i=0;i<p[j].length;++i)if(p[j][i])b[u+j][v+i]=p[j][i];for(j=0;j<H;++j)if(b[j].indexOf(0)<0){b.splice(j,1);b.unshift([]);for(i=0;i<W;++i)b[0][i]=0}l++;if(l/10>=s.length)l=0}function h(){p=r;if(p){v=(W-p[0].length)/2;u=0;if(!w(v,u,p))t.text="GAME OVER"}r=P[int(Math.random()*P.length)]}}}

*위 소스를 Tetris.as 파일로 생성하여 Flash CS3에서 Document class에 등록하고 퍼블리시 하면 된다.

    

설정

트랙백

댓글