Deprecated: Assigning the return value of new by reference is deprecated in /home/heungsub/blog/wp-settings.php on line 512 Deprecated: Assigning the return value of new by reference is deprecated in /home/heungsub/blog/wp-settings.php on line 527 Deprecated: Assigning the return value of new by reference is deprecated in /home/heungsub/blog/wp-settings.php on line 534 Deprecated: Assigning the return value of new by reference is deprecated in /home/heungsub/blog/wp-settings.php on line 570 Deprecated: Assigning the return value of new by reference is deprecated in /home/heungsub/blog/wp-includes/cache.php on line 103 Deprecated: Assigning the return value of new by reference is deprecated in /home/heungsub/blog/wp-includes/query.php on line 61 Deprecated: Assigning the return value of new by reference is deprecated in /home/heungsub/blog/wp-includes/theme.php on line 1109 Heungsub Blog

3년만의 픽셀애니메이션

December 19th, 2008

기말고사 마지막 시험을 치르며 이 시간 이후 집에서 보낼 이틀 간 뭘 하면 좋을지 고민해봤습니다. 그 때 생각난 것이 고등학교 1학년때까지 주력하다 포기한 픽셀애니메이션이었습니다.

Project 630: Attack

3년만에 하는 작업은 어떨지 궁금하기도 했고 오래전부터 그려보고 싶던 것도 있고 해서 집에 돌아가는 길에 열심히 구상했죠.

그리고자한 것은 격투게임 캐릭터 같은 대기자세를 취하고 있는 저를 그린 자화상이었습니다.

img_81421

그림이 엉망이네요. 아무튼 이 스케치를 바탕으로 바로 드로잉에 들어갔습니다.

fighter01

이걸 작업할 때만 해도 “뭔가 이상하긴 하지만 이정도면 흡족하군”이라고 생각했습니다. 그래서 제 미투데이에 올려 흡족한 부분은 뽐내고 뭔가 이상한 부분은 지적받기로 했습니다. 여러가지 의견이 달렸고, 다행히 김준민 선배께선 정말로 좋은 지적을 해주셨습니다.

코트 속에 다리 그려봤어? 그려보면 허벅지가 비정상적으로 긴 사람이 될거야… 만약 실제로 그렇다고 해도 키높이 구두를 신겨줘…. 그리고 저번에 재석이 합성이 이상했던건 다리는 긴데 팔이 짧아서야. 다리가 길면 팔도 늘려주세요 ㅎㅎ 그림자는 다리를 좀 굵게 그리면 괜찮지 않을까?

아하! 얘기를 듣고보니 정말 엉망이었네요. 또 이날 잠시 만난 해멍 누나는 그림자가 어디어디에 들어가야할지 지도해주셨습니다. 준민 선배의 지적에 따라, 해멍 누나의 지도에 따라,

img_8136

그리고 오른팔은 실제로 사진을 찍은 후 참고하여 그림을 다음과 같이 수정했습니다.

fighter02

여기에 부족한 하이라이트는 조재희 씨의 도움으로 덧붙일 수 있었습니다.

fighter03

fighter04

첫째날 작업은 여기까지였습니다. 시시때때로 빈둥거리며 작업해서 속도는 굉장히 느렸습니다.

이튿날, 바로 애니메이션 작업에 들어갔습니다. 전 본격적인 애니메이션 작업에 앞서 그림의 부분부분을 떼어내 옮겨서 프로토타입을 구성합니다. 다음은 첫 번째 프로토타입입니다.

fighter05

어딘가 어색하길래 사막여우 누나에게 조언을 구했습니다. 이번엔 몸통이 앞뒤로 움직이는 것이 어색하다는 지적을 받았습니다. 바로 상하운동만 하도록 수정했고 결과는 만족스러웠습니다.

fighter06

프로토타입에 생긴 틈들을 메우고 다듬기만 하면 간단한 애니메이션은 완성됩니다. 거기에 목도리의 파동을 가이드할 선을 추가했습니다.

fighter07

마지막으로 바람에 휘날리는 목도리를 그려넣고, 자잘한 부분을 손 봄으로써 마침내 작품을 완성했습니다.

fighter07

3년동안 손 놓고있던 것에 비하면 꽤 만족스러운 작품이 나왔다고 생각합니다. 만약 저 혼자서 작업했다면 잘못된 형태, 어색한 그림자와 동작을 해결하지 못해 형편없는 작품이 만들어졌을 것입니다. 처음부터 뭔가 어색한 것 같긴 하다고 느꼈으나 이론적인 바탕이 전혀 없다보니 그 이유를 알 수 없음에 굉장히 답답해 했습니다. 다행히 몇몇 분이 그 의문을 해소시켜주었고 나은 방향으로 인도해주었습니다.

완성하는데 도움 주신 분들, 아낌없이 칭찬해주신 분들께 감사하며 역시 혼자만으로의 한계는 다른 사람과의 협동으로 쉽게 극복할 수 있단걸 다시 한 번 느낀 기회였습니다.

MooJoe 0.9.0 릴리즈

October 30th, 2008

얼마 전 강규영 님은 JavaScript 객체와 DOM Element를 맵핑시켜주는 JOE공개하셨습니다. JOE는 DOM Element를 모델 스토리지로 사용할 수 있게 해주는 굉장히 유용한 프로젝트입니다.

하지만 아쉽게도 jQuery 기반으로 만들어져 MooTools 1.2를 사용하는 VLAAH나 개인 작업에는 사용할 수 없었죠. 저는 곧 바로 JOE를 MooTools 스타일로 포팅하는 MooJoe 프로젝트를 시작했는데 한참 잊고 있다가 이제서야 공개합니다.


Simple Mapping

다음과 같은 HTML 코드가 주어졌습니다.

<div id="names">
    <p class="name">
        <span class="first">Heungsub</span>
        <span class="last">Lee</span>
    </p>
    <p class="name">
        <span class="first">Alan</span>
        <span class="last">Kang</span>
    </p>
</div>

척 보기에도 서버 측에서 두 개의 Name 객체를 div#names에 출력한 모습입니다. MooJoe는 JOE와 마찬가지로 DOM Element를 JavaScript 객체에 동기화시켜줍니다. 동기화를 하기 위해 먼저 Name 클래스를 정의합니다.

var Name = new MooJoe.Class({
    first: '.first',
    last: '.last'
});

MooJoe의 클래스는 MooJoe.Class 생성자로 만들 수 있습니다. 인자로 맵핑 룰을 지정할 수 있는데 Name 클래스의 경우 first 속성에 .first라는 CSS 셀렉터를, last 속성에 .last라는 CSS 셀렉터를 지정했습니다. CSS 셀렉터를 맵핑룰로 쓰기 때문에 .last가 항상 두 번째 span이라면 다음과 같이 써도 무관합니다.

var Name = new MooJoe.Class({
    first: 'span.first',
    last: 'span:nth-child(2)'
});

이제 div#names의 내용을 방금 만든 Name 클래스의 인스턴스로 만들어봅시다.

var names = [
    $$('#names p.name')[0].toObject(Name),
    $$('#names p.name')[1].toObject(Name)
];
// [name_instance#1, name_instance#2]

MooJoe는 MooTools의 Element 클래스를 확장해 Element.prototype.toObject 메서드를 제공합니다. 이 메서드에 맵핑시킬 MooJoe 클래스를 넘기면 맵핑된 객체를 반환합니다. 물론 다른 MooTools의 Element 메서드처럼 Elements.prototype.toObject로 짧게 쓰는 것도 가능합니다. 다음 코드는 방금 전 예제와 동일합니다.

var names = $$('#names p.name').toObject(Name);

맵핑시킨 속성들에 접근해볼까요? getter/setter는 MooTools 1.2의 컨벤션을 따릅니다.

names[0].get('first');
// 'Heungsub'
names[0].get('last');
// 'Lee'

names[0].set('first', 'Haesam');
names[0].get('first');
// 'Haesam'

또한 속성 값을 변경할 경우 맵핑된 Dom Element에도 즉각 반영됩니다.

...
    <p class="name">
        <span class="first">Alan</span>
        <span class="last">Kang</span>
    </p>
...

이 Element는

$$('#names p.name .first')[1].get('html')
// 'Alan'

names[1].set('first', 'Sungryong');

$$('#names p.name .first')[1].get('html')
// 'Sungryong'

이렇게 변합니다.

...
    <p class="name">
        <span class="first">Sungryong</span>
        <span class="last">Kang</span>
    </p>
...

여기까지는 단순히 자식 Element의 내용으로 속성을 맵핑시키는 간단한 사용법이었습니다. 하지만 속성이 항상 자식 Element에 표현되지만은 않겠죠. 가령 이름과 홈페이지 주소를 표현하는 경우를 생각해볼 수 있습니다.

<a class="person" href="http://heungsub.net/">이흥섭</a>

a.person으로부터 namehomepage 속성을 갖는 Person 객체를 만들고싶습니다. 어떻게 해야할까요?

Complex Mapping

MooJoe는 복잡한 맵핑룰을 제공합니다. 위 a.person을 객체로 만들기 위해 먼저 Person 클래스를 정의합니다.

var Person = new MooJoe.Class({
    name: ['', 'text'],
    homepage: ['', 'href']
});

맵핑룰에 CSS 셀렉터 대신 배열이 쓰였습니다. 이 경우 name 속성은 “이 Element의 text 값”에 맵핑시키고 homepage 속성은 “이 Element의 href 값”에 맵핑시킨다는 뜻입니다. 배열의 첫 번째 원소인 빈 문자열이 바로 “이 Element”를 가리킵니다. texthref는 MooTools의 getter/setter로 접근 가능한 키워드로, 각각 innerHTMLhref Attribute를 의미합니다.

var hs = $$('a.person')[0].toObject(Person);
// person_instance#1

hs.get('name');
// '이흥섭'
hs.get('homepage');
// 'http://heungsub.net/'

조금 더 복잡한 Person 예제를 볼까요?

<div class="person">
    <p class="face">
        <img src="http://farm4.static.flickr.com/3122/2894552409_3439382280_s.jpg" />
    </p>
    <p class="name">
        <a href="http://heungsub.net/">
            <span class="first">Heungsub</span>
            <span class="last">Lee</span>
        </a>
    </p>
    <p class="age">18</p>
</div>

이제 Person은 이름과 홈페이지 주소 뿐 아니라 사진, 나이, 게다가 Name 객체까지 표현해야합니다. 다행히 MooJoe으로 맵핑한 각 값을 특정한 타입이나 클래스로 캐스팅해줄 수 있습니다. Person 클래스를 다시 정의해봅시다.

var Person = new MooJoe.Class({
    name: ['.name a', Name],
    homepage: ['.name a', 'href', String],
    face: ['.face img', 'src', String],
    age: ['.age', Number]
});

homepageface의 룰은 3개의 원소로 되어있습니다. 각각 맵핑할 Element, 맵핑할 Attribute, 타입(클래스)을 나타냅니다. 맵핑할 Element인 첫 번째 원소를 제외하고는 순서가 바뀌어도 상관 없으며 기본값으로 각각 'text'String을 갖기 때문에 다음과 같이 써도 동일합니다.

...
    homepage: ['.name a', String, 'href'],
    face: ['.face img', 'src'],
...

name의 캐스팅 클래스는 Simple Mapping 예제에서 정의해뒀던 Name 클래스입니다. 자 그럼 객체로 구워볼까요?

var hs = $$('.person')[0].toObject(Person);

hs.get('name');
// name_instance#3
hs.get('name').get('first');
// 'Heungsub'

hs.get('face');
// 'http://farm4.static.flickr.com/3122/2894552409_3439382280_s.jpg'

hs.get('age');
// 18

name 속성은 Name 객체로, face는 문자열로, age는 숫자로 잘 캐스팅되는군요.

참 쉽죠?
(강규영 님 블로그에서 보고 너무 재미있어서 퍼왔습니다)

Detached Object

MooJoe 클래스를 MooTools 클래스처럼 사용할 수도 있습니다. 임의의 Name 객체를 만들어보겠습니다.

var new_name = new Name('Dachimawa', 'Lee');
new_name.attached;
// []

new_name.get('first');
// 'Dachimawa'
new_name.get('last');
// 'Lee'

생성자에 보낼 인자 순서는 맵핑룰 순서와 동일합니다. first 속성이 첫 번째 룰이었으므로 'Dachimawa'first 값이 됩니다.

attach() 메서드로 연결되어있지 않은 MooJoe 객체는 언제라도 Dom Element에 동기화시킬 수 있습니다.

...
    <p class="name">
        <span class="first">Sungryong</span>
        <span class="last">Kang</span>
    </p>
...

다음과 같이.

new_name.attach($$('.name')[1]);
new_name.attached;
// [<p.name>]

동기화시키는 순간 Dom Element의 내용도 업데이트됩니다. 원래의 내용이 MooJoe 객체의 내용으로 덮어씌워집니다.

...
    <p class="name">
        <span class="first">Dachimawa</span>
        <span class="last">Lee</span>
    </p>
...

다시 뗄 때는 detach() 메서드를 사용합니다.

new_name.detach();
new_name.attached;
// []

MooJoe 0.9.0은 다음과 같이 체크아웃 받을 수 있습니다.

svn checkout http://moojoe.googlecode.com/svn/tags/0.9.0 MooJoe

개발버전을 받고싶으시면 다음을 사용해주세요.

svn checkout http://moojoe.googlecode.com/svn/trunk MooJoe

버그 리포트 및 기능 제안은 프로젝트 이슈 페이지에서 해주세요.

아직 버그가 있긴 하지만 앞으로 차근차근 발전시켜나가야겠습니다. 특히나 MooJoe 프로젝트는 저의 첫 개인프로젝트이니만큼 애정을 갖고 말이죠. 그럼 0.9.1 버전 릴리즈 소식도 기대해주세요!

Phunctional 0.9.1 릴리즈

July 18th, 2008

PHP에서의 함수형 프로그래밍을 돕는 프레임워크 Phunctional가 새로 릴리즈되었습니다. 자세한 업데이트 내용은 Phunctional Blog에 기재해두었습니다. 홍민희 선배 수고 많으셨습니다.

VLAAH 디자인 개편

July 9th, 2008

VLAAH Wallpaper

꽤 오랜 시간이 걸렸습니다. 그 동안 열심히 일한 성과를 드디어 여러분께도 보여드릴 수 있게 되었네요. 우리들의 취향 공유 VLAAH가 오늘 새벽에 성공적으로 디자인 개편을 마쳤습니다. 제가 개발과 디자인을 동시에 맡고있어 작업량이 많았던 만큼 이번 개편에 애착이 많이 생깁니다. 이번 개편을 통해 바뀐 점들은 VLOG에 자세히 써두었습니다.

VLAAHLunant(야간개발팀)의 첫 번째 작품으로, 회원들끼리 취향을 공유하는 Social Network Service입니다. 현재 클로즈드베타가 진행 중입니다. 제게 이메일 주소를 보내주시면 초대장을 드리겠습니다.

준협 씨와의 첫 만남

June 5th, 2008

이준협 씨

최근에 겪은 일들 중 가장 설레였던 것은 6년 전 NZEO.COM에서 처음 알게된 이준협 씨와의 만남이었습니다. 그와는 픽셀아트 강좌 게시판에서 만나 오랫동안 서로 실력을 겨루고 이끌어주며 굉장히 친하게 지내고 있었습니다. 4년 후 어쩐 일인지 연락이 끊기게 되었는데 그로부터 2년이 지난 얼마전 그때가 문득 그리워졌습니다. 어렴풋이 기억나는 단서로 이곳저곳을 알아본 끝에 결국 다시 연락할 수 있게 되었습니다.

준협 씨는 얼마 전까지 뉴질랜드에서 생활하다가 올 해 한국으로 귀국해 한국과학기술원에 입학했다고 합니다. 마침 며칠 전 방학을 맞이해 서울로 올라오셔서 처음으로 오프라인에서 함께하는 자리를 마련하게 되었습니다. 종로와 신촌을 오가며 거의 하루동안 유익한 이야기를 많이 나눌 수 있었습니다.

준협 씨의 2005년 작품 『optiques』

준협 씨는 고등학교 3학년 때까지 예술가를 꿈꿨다고 합니다. 메신저로 고등학교 때 만든 작품 몇 점을 받아볼 수 있었는데 미술의 기초도 배운 적 없다는 사람이 이렇게 창의적이고 멋진 작품을 만들어냈다는 사실에 경탄하지 않을 수 없었습니다. 당시엔 예술이란 무엇일까 하는 생각을 주로 했다고 합니다. 불쌍한 우리나라 입시미술생들이 학원에서 기계처럼 발상과표현, 석고소묘, 칸만화 등을 찍어낼 때 준협 씨는 다른 수준의 고민과 수련을 하고있었던 것입니다. 안타까운 입시미술 시스템에 대해 이야기해주자 그는 우리나라 입시미술학원에서 그토록 강조–강요하는 기초라는게 자신이 예술을 공부하는 데 있어서는 필요하지 않았을 뿐이라고 당연하다는 듯이 대답해주었습니다.

제가 디자이너에서 프로그래머로 꿈을 바꾸었듯 준협 씨도 지금은 과학자를 꿈꾸고 계신다고 합니다. 오늘 만남을 통해 물리학이나 뇌과학, DNA, 양자역학 등에 이르는 해박한 과학 지식과 과학에 대한 애정을 엿볼 수 있었습니다. 특히 그는 벌 군체와 동물의 뇌를 예로 들며, 작고 멍청한 연산 하나하나는 별 의미가 없지만 방대하게 모였을 때는 마치 고도의 지능처럼 작용한다는 점에 경이로움을 느낀다고 했습니다. 내년에 선택하게 될 전공도 바이오뇌과학 과가 될 것 같다고 합니다.

그는 한 때 예술이란 무엇일까 고민한 끝에 보는 이로 하여금 어떤 생각이나 감정을 유도해낼 수 있는 무엇으로 생각하게 되었다고 합니다. 그 때 표현기법은 너무 사소한 것이어서 무엇이 되어도 상관없고, 예술의 범위와 경계는 무한히 확장 될 수 있다는 얘기도 덧붙였습니다. 그런 의미에서 자신이 지금 과학을 배우고 있어도 사실은 예술을 공부하고있는 것이고 자신의 꿈도 여전히 예술가라고 자부했습니다. 저와 함께 픽셀아트를 할때나 고등학교때 미술을 할때나 지금 과학을 공부할때나 예술하는 마음가짐은 언제나 변함 없었답니다. 오늘 준협 씨와 나눈 이야기 중 가장 인상 깊은 이야기였습니다.

아쉽게도 막차 시간이 다가와 조만간 또 뵙기를 기약하며 헤어졌습니다. 오늘 만난 준협 씨는 키도 헌칠하고 그림도 잘그리고 박식하며 유학파에 한국과학기술원 학생인 엄친아 같은 분이었습니다. 이런 소중한 인연을 만날 수 있었단 것에 크게 감사하며 앞으로는 연락 끊기는 일 없이 유익한 이야기를 계속 나눌 수 있길 바랍니다.