'게임 개발'에 해당되는 글 332건

  1. 2010/07/31 파일 선택 대화 상자 띄우기
  2. 2010/07/22 URL 인코딩(Encoding) (4)
  3. 2010/06/12 토털 사커에서 배워야 하는 팀의 운영
  4. 2010/05/09 스타크래프트 팀 플레이에서 3 대 3을 많이 하는 이유 (4)
  5. 2010/04/17 작업자를 위한 기획서를 쓰는 방법 (2)
  6. 2010/04/04 게임에서 수직 동기화
  7. 2010/03/14 코딩용 추천 글꼴
  8. 2010/02/14 폴리곤 수를 줄이는 미들웨어(Middleware) (4)
  9. 2010/02/14 게임용 라이팅(Lighting) 미들웨어(Middleware) (4)
  10. 2010/02/14 가시성 최적화 미들웨어(Middleware) (6)
  11. 2010/01/27 게임 엔진은 게임 개발의 결과물이어야 합니다 (4)
  12. 2010/01/19 컴퓨터 그래픽스에서 앨비도우(Albedo)의 뜻 (2)
  13. 2010/01/17 즉흥적인 결정을 피할 것 (2)
  14. 2010/01/17 게임 재미에 대한 연구의 필요성 (4)
  15. 2010/01/17 C++에서 비트 연산자를 쓸 때엔 우선순위를 항상 생각할 것
  16. 2010/01/17 데이터 수동 입력을 줄이기 위해서 네이밍(Naming)을 활용할 것
  17. 2010/01/17 회의를 효율적으로 하는 방법
  18. 2010/01/17 Visual C++ (Visual C++) 창의 레이아웃을 원래대로 돌리기
  19. 2010/01/12 바둑이 뛰어난 전략 게임인 이유
  20. 2010/01/10 기획자와 현장 고객의 비교
  21. 2010/01/10 온라인 게임은 영화보다 드라마에 가깝습니다
  22. 2010/01/09 스크럼(Scrum) 프로세스에 대한 의문 (2)
  23. 2010/01/09 퍼포스(Perforce)에서 잘못된 체인지리스트(Changelist)를 지우는 방법
  24. 2010/01/09 마우스 휠 처리
  25. 2010/01/04 소수 구하기
  26. 2010/01/03 IME에서 조합 중인 글자를 강제로 완성시키기
  27. 2010/01/02 mbstowcs나 wcstombs가 올바르게 동작하게 하려면, setlocale 설정이 필수
  28. 2010/01/01 게임 밸런스는 최소한만 수정할 것
  29. 2009/12/24 윈도에서 디버거에 연결돼 있는지 확인하기 (2)
  30. 2009/12/05 게임 그래픽스에서 정적 조명과 동적 조명
파일 선택 기능은 도구를 만들다 보면 자주 필요한 기능입니다. 간단하게 사용법만 예제로 정리해 둡니다.

char old_directory[MAX_PATH];
GetCurrentDirectory(sizeof old_directory, old_directory);

OPENFILENAME open_file_name = {};
open_file_name.lStructSize = sizeof open_file_name;
open_file_name.hwndOwner = NULL;
open_file_name.lpstrFilter = "파일(*.ext)\0*.ext\0모든 파일(*.*)\0*.*\0";
char file_path[MAX_PATH] = {};
open_file_name.lpstrFile = file_path;
open_file_name.nMaxFile = sizeof file_path;
open_file_name.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

if (GetOpenFileName(&open_file_name) != FALSE)
{
// GetOpenFileName이 현재 디렉토리를 바꿔 버리므로, 원래 디렉토리로 되돌려야 합니다.
SetCurrentDirectory(old_directory);

// 여기에서 open_file_name.lpstrFile를 이용해 필요한 일을 처리하면 됩니다.
}
2010/07/31 22:15 2010/07/31 22:15
문자 집합의 제한 등으로 인해, 일반적인 유니코드나 ANSI 문자 집합을 그대로 쓸 수 없을 때가 있습니다. 특히 텍스트를 XML이나 이메일 등으로 전달해야 할 때 이런 일이 종종 발생합니다. 이럴 때 우회하는 인코딩 방법으로 base64 인코딩이나 URL 인코딩이 많이 쓰입니다. 여기에선 URL 인코딩을 알아 보겠습니다.
 
URL 인코딩은 인터넷 익스플로러에서 사이트 주소를 보다 보면 쉽게 발견할 수 있을 정도로 많이 쓰이는 인코딩입니다. 실제로 구현해 보니 base64 인코딩보다 인코딩 효율이 떨어지는 단점이 있지만, 구현이 간단하고 이해하기 쉬워서 좋습니다.

URL 인코딩을 하려면, 알파벳, 숫자, -, ., _, 그리고 ~는 그대로 표현하고, 그 외의 문자는 16진수로 변환한 값 앞에 %를 붙여서 표현하면 됩니다.

다음은 소스 코드입니다.
using std::string;

string encode(const string& source)
{
string target;

for (string::const_iterator iterator = source.begin(); iterator != source.end(); ++iterator)
{
const unsigned char source_character = static_cast<unsigned char>(*iterator);

if (isalnum(source_character) || strchr("-._~", source_character))
target += source_character;
else
{
target += '%';
target += convert_to_hex(source_character >> 4);
target += convert_to_hex(source_character);
}
}

return target;
}

char convert_to_hex(char code)
{
return "0123456789abcdef"[code & 0xf];
}
참고:
2010/07/22 13:39 2010/07/22 13:39
지금은 압박 축구로 변형되긴 했지만, 토털 사커는 현대 축구에 새로운 방향을 제시한 전술입니다. 우리는 토털 사커에서 특히 포지션의 개념이 약화됐다는 것에 주목해야 합니다.

공격수는 공격만 하고, 수비수는 수비만 하는 축구는 효율적이지 못합니다. 공격할 때엔 체력 부담을 낮추면서 역습을 대비할 수 있는 정도로만 수비를 하고, 되도록 많은 사람이 공격에 참여하는 게 훨씬 효율적입니다. 반대로, 수비할 때엔 공격수도 전방에서부터 압박을 해 줘야 효율적입니다.

게임 개발에서 팀의 운영도 마찬가지입니다. 기획을 할 때엔 많은 팀원이 다양한 아이디어를 내고, 기획자는 수집한 아이디어를 토대로 기획서를 작성하며, 프로그래머와 아티스트가 작업자 입장에서 문제점을 미리 검토하고, QA가 게이머 입장에서 사용성도 검토해야 효과적입니다. 기획뿐만 아니라 프로그래밍, 그래픽, 그리고 테스트도 모두 마찬가지입니다. 각자의 역할이 중요한 게 아니라, 지금 팀이 무슨 일에 집중해야 하는가가 중요한 것입니다.

하지만, 아직도 많은 팀이 기획자는 기획만 하고, 프로그래머는 코딩만 하고, 아티스트는 그래픽 작업만 하며, QA는 테스트만 합니다. 이렇게 각자의 권한을 지나치게 강조하면, 다른 파트의 도움을 받을 수 없게 됩니다.

전역적 최적화를 고려하지 않는 부분적 최적화는 좋지 않습니다. 팀은 개인을 단순히 모아 놓은 집합이 아니라, 한 목표를 향해 일사불란하게 움직이는 하나의 덩어리가 돼야 합니다.
2010/06/12 14:47 2010/06/12 14:47
스타크래프트 배틀넷에서 팀 플레이가 제일 많이 이뤄지는 인원 구성은 3 대 3입니다. 팀 플레이에서는 헌터와 그 변종 맵이 제일 많이 사용됩니다. 그 맵들은 최대 4 대 4까지 지원합니다. 하지만, 실제로 2 대 2나 4 대 4로 게임을 하는 때는 드물고, 대개 3 대 3을 많이 하며 그게 더 재미있습니다. 그 이유에 대해 생각해 봤습니다.

첫째, 4 대 4는 인원 수를 채우기가 어렵습니다. 스타크래프트에서 8개의 플레이어 슬롯을 모두 채울 때까지 기다리는 것은 어려운 일입니다. 지루함을 못 참고 중간에 나가는 사람이 많기 때문입니다.

둘째, 팀 당 의사 결정권자의 수가 홀수입니다. 팀 플레이에선 의사 결정을 해야 할 때가 잦습니다. 이때, 한 팀 당 의사 결정을 할 수 있는 사람의 수가 홀수이면, 누군가 기권을 하지 않는 한, 언제나 투표를 통해 결론을 빠르게 낼 수가 있습니다.

셋째, 팀 당 의사 결정권자의 수가 4 대 4일 때보다 적습니다. 의사 결정을 해야 하는 인원 수가 줄어든다는 것은 그만큼 빨리 결론을 낼 수 있다는 뜻입니다. 결론을 빨리 내는 것은 스타크래프트처럼 진행이 빠른 게임에서는 중요한 일입니다.

넷째, 다양한 종족 조합의 플레이가 가능합니다. 2 대 2일 때엔 종족 조합의 가지 수가 많지 않습니다. 그리고 그로 인해서 게임이 좀 더 획일화되기 쉽습니다. 그에 반해, 3 대 3일 때엔 다양한 패턴의 게임이 가능해집니다.

다섯째, 정찰을 하지 않고는 상대방의 위치를 완전히 파악할 수 없습니다. 이건 초반 러쉬에서 중요한 문제입니다. 초반에 무조건 한 곳을 공격하기로 했을 때, 상대방의 위치를 이미 알고 있다면 100% 확률로 공격이 가능합니다. 하지만, 상대의 위치를 확신할 수 없다면, 잘못 짚었을 경우엔 그만큼 손해를 보게 됩니다. 이건 맵의 최대 수용 가능 인원 수보다 적은 인원으로 플레이할 때엔 언제나 생기는 현상입니다.

여섯째, 한 사람이 최대로 방어할 수 있는 적의 인원은 대개 3명 정도입니다. 헌터 맵과 스타크래프트 유닛의 특성상, 한 사람이 지형, 건물, 그리고 유닛 조작 등을 활용해 가까스로 방어할 수 있는 최대 적군 수는 3명 정도입니다. 이렇게 초반 러쉬의 성공 여부를 쉽게 판단하기 어려우므로, 게임을 더 긴장감 있게 할 수 있습니다.

일곱째, 초반에 한 사람이 궤멸당하더라도 남은 두 사람이 충분히 역전시킬 수 있습니다. 2 대 2에서는 한 사람이 궤멸당하면, 1 대 2로 싸우게 돼서 상대 팀보다 두 배로 잘하지 않는 한, 역전이 어렵습니다. 반면에, 3 대 3일 때엔 한 사람이 궤멸당하더라도 2 대 3으로 싸우게 되고, 상대 팀보다 50% 정도만 효과적으로 운영을 해도 이길 수 있게 됩니다. 게다가 실제로는 아군 한 명을 궤멸시킬 때 적군도 어느 정도 피해를 보기 때문에 적군과 아군의 병력 차이는 더 적습니다. 이렇게 역전의 가능성이 남아 있을수록 게임은 흥미진진해집니다.
2010/05/09 14:02 2010/05/09 14:02
기획자가 갖춰야 할 능력 중에 중요한 것으로 문서 작성 능력이 있습니다. 기획자는 문서 중에서도 작업자를 위한 기획서를 쓸 때가 제일 잦을 것입니다. 기획서를 잘 쓰는 것은 효율적인 의사소통을 위해 꼭 필요한 일입니다. 이런 기획서를 쓸 때 중요한 것을 우선순위대로 적어 보겠습니다.

첫째, 명확하게 써야 합니다. 애매모호한 표현은 의사소통에 도움이 되지 않을 뿐만 아니라, 더 나아가 오해가 생기게 합니다. 되도록이면 숫자를 최대한 이용하는 게 좋습니다.

둘째, 구체적으로 써야 합니다. 추상적인 표현은 작업자가 무엇을 해야 하는지 알기 어렵게 합니다.

셋째, 요청 사항을 빠짐 없이 써야 합니다. 기획서만 보고도 모든 작업을 할 수 있도록, 모든 요청 사항을 적어야 합니다. 그리고 각 요청 사항은 어떤 조건에서 무슨 일을 하면 된다고 명시해야 합니다. 특히, 예외적인 부분을 빠트리지 않도록 조심해야 합니다.

넷째, 작업 단위 위주로 문서를 작성해야 합니다. 기획자는 흔히 기획서를 애니메이션, 렌더링, 사운드, UI, 그리고 이펙트 등의 기술적인 구분에 따라 따로 작성합니다. 하지만 이런 기획서는 각 작업자가 전체를 보지 못하게 되는 문제를 일으킵니다. 그래서 기획서는 컨텐츠를 기준으로 작성돼야 합니다. 예를 들어 어떤 무기를 추가한다고 하면, 그 무기와 연관된 플레이 로직, 애니메이션, 렌더링, 사운드, UI, 그리고 이펙트 등을 모두 하나의 문서에 적어야 합니다. 이렇게 되면, 어떤 작업을 완료했는지 판단해야 하는 작업이 단 한 개의 기획서만 검토하는 것으로 가능해집니다.

다섯째, 왜 그런 요청을 하게 됐는지도 써 주면 좋습니다. 꼭 필요한 것은 아니지만, 쉽게 납득하기 어려운 내용이 있다면 보충 설명을 통해 이해시키는 게 좋습니다.
2010/04/17 17:29 2010/04/17 17:29
요즘 게임은 기본적으로 수직 동기화(vertical synchronization)를 사용하지 않는 때가 잦습니다. 그 이유는 요즘 게임은 대체로 프레임 레이트(frame rate)가 낮은 편이라서, 수직 동기화 옵션이 그다지 필요하지 않기 때문인 것 같습니다.

수직 동기화는 화면 티어링(screen tearing) 현상을 방지하기 위해서 필요합니다. 티어링은 화면 출력이 진행 중인데 화면 내용이 바뀌면서 위 아래의 화면이 일치하지 않아 찢어지는 듯한 느낌을 주는 현상을 말합니다.

그런데 프레임 레이트가 모니터의 화면 재생 빈도(수직 회귀율)보다 낮으면, 티어링 현상이 잘 나타나지 않게 됩니다. 게다가 강제로 수직 동기화를 하면, 매 프레임마다 수직 동기화가 될 때까지 기다려야 하기 때문에 프레임 레이트가 더 떨어지게 됩니다.

그래서 프레임 레이트가 낮은 게임에서는 수직 동기화가 오히려 게임 플레이를 방해합니다.
2010/04/04 12:01 2010/04/04 12:01
코딩할 때엔 가독성이 좋은 글꼴을 사용하는 게 좋습니다. 사람들이 추천하는 몇 가지 글꼴을 써 봤는데, 제겐 Dina 글꼴이 제일 잘 맞았습니다. 그 외에 사람들이 많이 추천하는 글꼴로는 Consolas 글꼴, Bitstream Vera Sans Mono 글꼴, 그리고 네이버 나눔고딕 코딩글꼴 등이 있습니다.
2010/03/14 16:32 2010/03/14 16:32
사용해 본 적은 없지만, 이런 것들이 있다기에 정리해 둡니다.


요즘은 폴리곤 수가 그다지 문제되진 않는 것으로 알고 있습니다만, 그래도 어느 정도 최적화는 필요하겠죠.
2010/02/14 21:33 2010/02/14 21:33
실제로 사용해 보진 않아서 잘 모르지만, 대략 다음과 같은 것이 있나 봅니다.



Lightsprint는 실시간 global illumination을 지원하는군요. 성능이 얼마나 나올지는 모르겠지만, 독특한 미들웨어네요. 조명 전처리 때문에 생기는 레벨 디자인 확인 지연을 없앨 수 있다는 점에서는 가치가 있겠습니다.

참고로, Image-Based Lighting도 좀 더 섬세한 정적 조명을 표현하는 방법입니다. 하지만, 그래픽 아티스트가 이미지를 일일이 뽑아 내야 한다는 단점이 있습니다. 맥스 스크립트 등을 활용하면 좀 더 쉬워질 수는 있지만, 그렇다 해도 자동화가 상당히 어렵습니다. 그래서 이런 미들웨어를 활용해 정적 조명 전처리를 완전히 자동화하는 게 생산성 측면에서 더 나은 것 같습니다.
2010/02/14 01:50 2010/02/14 01:50
Umbra Software라는 곳에서 가시성 최적화 미들웨어를 판매하고 있네요. 비슷한 미들웨어가 더 있을 것 같은데, 찾아 보진 않았습니다.

여유 자금이 있다면 이런 미들웨어를 구입해서 가시성 최적화 문제를 해결하는 게 좋은 것 같습니다. 레벨 디자인 단계에서부터 레벨 디자이너가 가시성 최적화를 고민하는 것도 한 가지 방법일 것입니다. 하지만, 게임 개발자는 사용자에게 즐거움을 줄 만한 창의적인 일을 해야 하는 것이고, 기술적인 문제에 대한 고민에 노력을 많이 투자하는 것은 좀 아깝습니다.
2010/02/14 01:44 2010/02/14 01:44
엔진을 만들 때, 많이 실수하는 부분이 있습니다. 그건 바로 엔진을 먼저 만들고, 엔진을 이용해 게임을 만드는 것입니다. 기본적인 것을 먼저 구현하고 그 위에 부가적인 요소를 올리는 게 처음엔 맞는 것처럼 보입니다. 하지만, 실제로 작업해 보면 반대라는 것을 알게 됩니다.

게임을 만들 때엔 다른 것은 생각하지 말고, 게임을 만드는 데에만 집중해야 합니다. 게임을 만들고 나면 자연스럽게 재활용 가능한 기본적인 부분이 보이고, 그걸 따로 정리하면 엔진이 되는 것입니다. 그런데 하나의 프로젝트만으로는 어디까지가 엔진이 돼야 할지가 명확하지 않습니다. 여러 게임을 개발해 보면 각 게임의 컨텐츠와 무관한 코드를 좀 더 명확히 알 수 있게 됩니다.

엔진을 개발하고 싶다면, 게임을 먼저 개발해야 합니다. 그게 훌륭한 엔진을 만드는 방법입니다.
2010/01/27 20:02 2010/01/27 20:02
앨비도우는 반사율인데, 일반적으로 분산광에 대한 반사율을 말합니다. 그래서 분산 텍스쳐 (diffuse texture)를 앨비도우라고도 부릅니다. 그런데 때로는 반사광에 대한 반사율도 specular albedo라고 부를 때가 있어서, 혼란스럽습니다. 용어는 되도록 하나로 통일되면 좋겠습니다.
2010/01/19 00:07 2010/01/19 00:07
결정을 서둘지 말라. 하룻밤을 자고 나면 좋은 지혜가 생긴다. - 푸시킨
게임 개발을 하다 보면, 어떤 일을 결정해야 할 때가 잦습니다. 그런데 이런 상황에서 주의 깊게 생각해 보지도 않고 결정을 내리는 것은 좋지 않습니다. 생각은 즉흥적으로 할 수 있지만, 그 생각을 실제 행동으로 옮기는 것엔 신중해야 합니다. 왜냐하면 한 번 행동으로 옮긴 것을 되돌리는 것은 생각을 바꾸는 것보다 훨씬 어렵기 때문입니다. 즉흥적인 결정 뒤엔 언제나 후회가 뒤따릅니다.
2010/01/17 21:20 2010/01/17 21:20
게임을 개발하다 보면, 사용할 기술에 대해 어느 정도 시간을 갖고 연구할 때가 있습니다. 그런데 신기하게도, 만들 게임의 재미에 대해 연구하는 사례는 거의 못 본 것 같습니다.

다른 게임을 참고하면서 필요한 시스템을 기획하는 것은 흔한 일입니다. 그런데 정작 그 시스템이 왜 재미있는지, 어떻게 해야 더 재미있을지, 그리고 자신의 게임에 접목했을 때 어떤 일이 일어날 것인지를 기획자뿐만 아니라 팀원 전체가 함께 고민하는 일은 드뭅니다. 더 나아가서, 다른 게임에 없는 재미있는 시스템에 대해 고민하고 함께 토론하는 문화는 정말 드뭅니다.

게임은 기술이 주가 아니라 재미가 주가 돼야 합니다. 최신 기술을 연구할 시간에 재미에 대해 더 연구하는 게 훨씬 이득입니다.
2010/01/17 21:08 2010/01/17 21:08
C++을 어렵게 느껴지게 하는 것 중 하나로 연산자 우선순위가 있습니다. C++ 연산자 우선순위는 어떤 자연스러운 규칙에 의해 이해할 수 있는 게 아닙니다. 언어 제작자가 자신이 좋아하는 방식대로 정해 놓았을 뿐이고, 언어를 배우는 사람은 이해가 안 돼도 따라야 하는 규칙일 뿐입니다.

특히 비트 연산자의 우선순위는 상당히 의문스럽습니다. <<나 >>와 같은 비트 연산자는 ==, <=, >=, 그리고 !=와 같은 비교 연산자보다도 우선순위가 낮습니다. 그래서 비트 연산자를 괄호로 묶어 주지 않으면, 예상과 전혀 다른 동작을 할 때가 잦습니다.

비트 연산자가 있는 코드가 제대로 동작하지 않는다면, 연산자 우선순위를 꼭 확인해 봐야 합니다.
2010/01/17 20:59 2010/01/17 20:59
네이밍이 무엇인지 아는 사람은 많지만, 네이밍을 어떻게 활용해야 좋을지 아는 사람은 드문 듯합니다. 데이터 관리에서 네이밍이 효과를 제일 발휘할 때는, 손으로 입력하는 것을 줄이는 것입니다.

예를 들어, 아이디가 A라는 무기가 있다고 하겠습니다. 이 무기의 이름은 big sword이고, 메쉬는 big_sword_mesh.mesh, 아이콘 이름은 big_sword_icon.tga입니다. 이 무기를 관리하려면 위의 값을 따로 입력해서 어딘가에 파일로 저장해 두어야 합니다. 무기가 한 두 개라면 상관 없겠지만, 무기 수가 늘어날수록 관리해야 할 데이터가 계속 늘어나게 됩니다. 더 큰 문제는 데이터가 늘어나면 그만큼 실수도 늘어난다는 것입니다.

위의 예에서 발생하는 문제를 쉽게 해결하려면 네이밍을 사용하면 됩니다. 메쉬는 .mesh를, 아이콘 이름은 .tga를 아이디에 붙여서 표현한다라고 정하면, 별도의 파일에 메쉬 이름과 아이콘 이름을 기록할 필요가 없습니다. 위의 예에선 각각 A.mesh, A.tga가 되겠습니다. 아이디 대신에 무기의 이름을 활용하면 이해하기 더 쉽겠지만, 파일 이름으로 표현하기 어려운 이름이 많으므로 논의를 통해 결정하는 게 좋습니다.

프로젝트 관리의 핵심은 덜 중요한 일에 자원을 적게 할당하고, 더 중요한 일에 자원을 많이 할당하는 것입니다. 네이밍은 그런 일을 가능하게 하는 방법 중 하나입니다.
2010/01/17 20:45 2010/01/17 20:45
어떤 조직이 효율적으로 운영되는지 판단하려면, 회의에 참가해 보면 쉽게 알 수 있습니다. 회의 과정이 비효율적인 조직은 업무도 비효율적으로 처리할 가능성이 높습니다. 최근에 회의를 자주 참석해 보면서, 어떻게 하면 회의를 효율적으로 할 수 있을지 생각해 봤습니다.

첫째, 의제를 명확하고 결과 지향적으로 정해야 합니다. 대부분 회의가 단지 지식 공유를 목적으로 소집되는데, 이것은 명백한 시간 낭비입니다. 회의에 참석하는 사람은 각자 지식에 대한 이해도가 다릅니다. 그런데, 이해가 덜 된 사람을 위해서 이미 내용을 이해하고 있는 사람까지도 계속 참석해 있어야 합니다. 지식을 공유하는 목적이라면, 회의가 아니라 문서를 통해 각자 필요한 부분을 읽어 보게 해야 합니다. 긴급하고 필수적인 내용을 공유해야 한다면 회의 외에는 좋은 방법이 없습니다. 하지만, 그렇지 않을 때가 대부분입니다. 회의는 결정을 내리는 데에만 주로 쓰여야 합니다.

둘째, 아무에게나 발언권을 주면 안 됩니다. 회의를 하다 보면 몇몇 사람만 계속 얘기를 하고, 다른 사람은 듣고만 있게 됩니다. 이건 전적으로 회의 진행자의 실수입니다. 회의에선 모든 사람이 공평한 발언 기회를 갖되, 필요 이상으로 얘기를 많이 하지 않도록 조정해야 합니다. 개인당 발언 시간 제한을 두는 방법이 제일 나을 것입니다.

셋째, 회의 내용에 대해서 사전에 문서 공유를 해야 합니다. 회의에 참석해서야 회의의 내용을 알게 되는 것은 참가자가 미리 준비를 하지 못하게 되는 단점이 있을 뿐만 아니라, 회의 시간이 회의 내용을 이해하느라 소모된다는 단점까지 있습니다. 사전에 모두가 알고 있어야 하는 내용은 미리 전달해 주고, 회의 도중에 생각나는 것은 회의 때에 이야기하는 식이 돼야 합니다.

넷째, 회의와 관련 있는 얘기만 하도록 해야 합니다. 회의를 하다 보면 의제와 전혀 무관하거나 당장은 필요 없는 얘기가 종종 나옵니다. 그런 얘기가 도움이 될 수는 있지만, 의제에 대한 집중도를 떨어트리고 회의에서 다뤄야 할 중요할 내용을 제대로 다루지 못하게 만드는 문제가 생깁니다.

다섯째, 자세한 얘기는 당사자끼리 얘기하도록 해야 합니다. 회의 시간에 모두가 들을 필요가 없는 얘기는 관련된 당사자끼리 따로 모여서 얘기하는 게, 모두의 시간을 조금이라도 덜 낭비하게 만듭니다.

여섯째, 회의 진행 도중의 기록을 반드시 남겨야 합니다. 회의를 하면 아무 기록도 남기지 않고 얘기만 하다가 끝나는 때가 잦습니다. 회의를 했다면 반드시 어떤 기록이 남아서 업무에 활용돼야 합니다.

관리자는 어떻게 하면 회의를 효과적으로 진행할 수 있을지 계속 고민해야 합니다.
2010/01/17 13:56 2010/01/17 13:56
비쥬얼 C++을 사용하다 보면, 의도하지 않게 창 레이아웃이 배치돼 버릴 때가 있습니다. 그리고 원래 상태로 복구하려고 해도 잘 안 돼서 고생하게 됩니다. 그럴 때엔 메뉴에서 Window의 Reset Window Layout을 선택하면 됩니다.
2010/01/17 13:38 2010/01/17 13:38
바둑은 지루하지만 뛰어난 전략 게임입니다. 왜 바둑이 전략 게임으로서 훌륭한지 이유를 적어 보았습니다.

첫째, 바둑에선 하나를 얻으려면 반드시 다른 하나를 포기해야 합니다. 한 사람이 한 턴에 하나의 돌만 놓을 수 있기 때문에, 어떤 수를 선택하면 다른 수는 포기해야 합니다. 이게 전략적 선택을 강요합니다. 전략의 기본은 선택입니다.

둘째, 변화가 다양합니다. 한 칸만 옆에 두어도, 차이가 크기 때문에 다양한 변화가 생깁니다. 심지어는 단 한 수로 전세가 완전히 역전될 수도 있습니다. 게다가 상대가 사람이기 때문에, 그 사람의 성향에 따라 상황이 다르게 흘러갑니다.

셋째, 바둑은 완전히 순간적인 머리 싸움입니다. 물론 정석이나 포석을 많이 외우고 있으면 유리하지만, 그걸 많이 안다고 항상 이기진 않습니다. 게다가 손에 의한 컨트롤은 게임 승패에 전혀 영향을 미치지 않습니다. 운에 의해 승패가 갈리는 경우도 거의 없습니다.

넷째, 바둑엔 급수가 있습니다. 그래서 자신과 비슷한 실력의 상대를 쉽게 찾을 수 있습니다. 그리고 실력 차이가 나더라도, 접바둑을 통해 고수에게 핸디캡을 줄 수 있습니다. 그래서 고수나 하수나 서로 긴장하면서 게임을 하게 됩니다.
2010/01/12 06:30 2010/01/12 06:30
익스트림 프로그래밍(Extreme Programming)의 현장 고객에서 생각을 따와서, 기획자를 현장 고객으로 생각할 수 있습니다. 하지만, 기획자는 일반 고객과 약간 다른 성격을 갖고 있으므로, 그대로 적용하는 것은 어려워 보입니다.

일반적으로 고객은 돈을 지불하는 역할을 합니다. 고객이 생산자에게 원하는 것을 말하면, 생산자는 그것을 생산하는 데에 필요한 비용과 시간을 답해 줍니다. 고객은 생산자의 답변을 참고해서, 그에 맞는 돈을 지불합니다. 그런데 여기서 돈에 관련된 문제는 전적으로 고객의 책임입니다. 예를 들어, 위험 요소가 많다는 답변을 듣고도 돈을 지불했다면, 그 돈을 날리는 것은 고객이 감수한다는 것입니다. 고객 자신이 원하는 것을 충분히 설명하지 않았거나 잘못 설명해서 엉뚱한 물건이 나온다면, 그 또한 고객의 책임입니다.

그런데, 일반적으로 게임 기획자는 결과에 대해 책임을 많이 지지 않습니다. 위험 요소가 많다는 답변을 듣고도 강행한 후에 결과가 잘못돼도, 기획자는 책임을 떠안지 않습니다. 그리고 자신이 원하는 기획을 정확하고 구체적으로 표현하지 않아서 생기는 문제에 대해서도 책임을 지지 않습니다. 실제로 프로젝트에 문제가 생겼을 때 영향을 받는 것은 개발 팀 전체입니다. 이렇다 보니, 기획자는 기획에 대해 책임감을 강하게 느끼기 어렵고, 신중한 결정을 하질 않게 되는 것입니다. 이건 기획자 개인의 문제라기보다는 게임 개발 체계의 문제입니다.

하지만 프로그래머가 기획을 간섭하려 하는 것은 좋지 않다고 봅니다. 기획자의 요구에 대해 예상되는 문제점과 필요한 자원을 정확히 알려 주는 것에 중점을 두어야 할 것입니다. 기획자에게 충분한 정보를 주었음에도 불구하고 일이 잘못된 방향으로 전개된다면, 관리자의 협조를 얻어 함께 조율하는 게 나을 것입니다. 만약 관리자마저도 잘못된 결정을 한다면, 다른 팀이나 회사를 알아보는 게 나을 것입니다.
2010/01/10 13:56 2010/01/10 13:56
흔히 게임을 영화와 비교하곤 합니다. 다양한 분야의 많은 인력이 여러 최신 기술을 이용해 하나의 작품을 단기간에 완성하고, 주로 화려한 볼거리와 광고에 치중하며, 그 작품이 주로 공개 초기에 일반 대중에 의해 소비되기 때문일 것입니다. 이렇듯 패키지 게임은 영화와 비슷한 점이 많습니다. 그런데, 온라인 게임은 영화보다 드라마에 더 가까운 것 같습니다.

온라인 게임은 끊임없이 변화되는 특징을 가집니다. 계속 연장 방영하는 드라마처럼, 온라인 게임은 패치를 계속 하면서 서비스의 수명을 늘려 나갑니다. 시청자의 의견을 반영해서 엔딩을 수정하는 한국 드라마처럼, 온라인 게임도 게이머의 의견을 토대로 패치를 하곤 합니다.

또, 드라마에선 유명 배우나 화려한 볼거리도 중요하지만, 이야기가 잘 짜여지지 않으면 드라마를 계속 보게 만들 수 없습니다. 제가 최고의 미국 드라마 중 하나로 생각하는 프리즌 브레이크 (Prison Break) 시즌 1을 보면, 다음 회를 꼭 보게 만드는 스릴이 있었습니다. 온라인 게임 또한 마찬가지입니다. 다음 이야기에 해당하는 컨텐츠를 지속적으로 만들어 주지 못하면, 온라인 게임을 더 이상 하고 싶어지지 않게 됩니다.

온라인 게임을 제작하는 사람이라면, 영화를 흉내내려고 애쓰기보다는 드라마를 보고 연구하는 게 나을 것입니다.
2010/01/10 07:13 2010/01/10 07:13
제가 있는 팀에서는 현재 어떤 정형화된 소프트웨어 개발 프로세스도 도입해서 쓰고 있지 않습니다. 전에 다른 회사에서 스크럼 프로세스를 경험해 본 적이 있는데, 장점도 있지만 단점도 많았습니다. 다른 분야로부터 도입된 여러 소프트웨어 방법론이 대부분 그렇듯이, 스크럼 프로세스도 소프트웨어 개발, 특히 게임 개발엔 왠지 부적합해 보입니다.

스크럼 프로세스에선 일정 기간 단위로 스프린트라는 것을 정해서 계획을 미리 잡아 두라고 합니다. 그런데 게임 개발에서 30일 단위로 할 일을 정하고 일정을 정하는 게 과연 의미가 있을까요? 일정을 고정시키면 변화하는 상황에 빠르게 대처할 수 없고, 반대로 일정을 바꾸면 계획의 의미가 퇴색됩니다. 개발을 진행하다 보면 무수한 변수가 발생해서, 일정을 언제나 수정해야 할 때가 대부분입니다.

스프린트 첫날에 일정을 잡는 게 과연 정확할까요? 충분한 사전 정보 없이 일정을 잡는 게 큰 의미가 있을까요? 구현하다 보면 예상치 못한 문제가 생기기 마련이고, 그 문제를 해결하는 데 얼마나 시간이 걸릴지는 아무도 모릅니다. 따라서 스프린트 첫날에 비교적 정확한 일정을 잡는다는 것은 불가능에 가깝습니다.

스크럼 프로세스에선 회의를 매일 하기를 권장합니다. 그런데 그게 과연 큰 의미가 있을까요? 필요할 때마다 참석해야 하는 사람끼리 모여서 회의를 하는 게 낫지 않을까요? 특별한 의제 없이 회의를 한다는 것은 시간 낭비입니다.

스크럼 프로세스에선 스프린트 단위로 결과를 공개하고 회고하기를 주장합니다. 이것도 역시 필요할 때마다 공개하는 게 나아 보입니다. 외부의 요청이 있을 때 즉시 공개할 준비는 언제나 돼 있어야 하는 것이고, 반면에 회고는 필요할 때마다 하면 충분해 보입니다.

스크럼에선 스프린트 단위로 한 가지 목표를 정하라고 하는데, 별로 의미가 없습니다. 한 달 단위로 어떤 목표를 세우기가 애매합니다. 왜냐하면, 한 달 동안 한 가지 큰 일조차 못할 수도 있고, 많은 중요한 일을 할 수도 있기 때문입니다.

스크럼 프로세스에 대해 전체적으로 생각해 보면, 고정 생산 분야에나 적합한 방식을 연구 개발 위주의 소프트웨어 분야에 무리하게 적용시킨 것 같습니다.
2010/01/09 21:09 2010/01/09 21:09
퍼포스를 사용하다 보면, 대기 중인 체인지리스트가 불필요하게 남아 있을 때가 가끔 있습니다. 이걸 지우려면 콘솔 명령 창(cmd.exe)을 열어서 다음처럼 하면 됩니다.

p4 change -d [번호]
예: p4 change -d 1000

참고: p4 change
2010/01/09 20:48 2010/01/09 20:48
윈도 메시지 처리 함수에서 다음처럼 처리하면 됩니다.

case WM_MOUSEWHEEL:
POINT window_position_in_screen = {};
ClientToScreen(window_handle, &window_position_in_screen);
UINT wheel_scroll_line;
SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheel_scroll_line, 0);
POINT cursor_position_in_client =
{
GET_X_LPARAM(l_parameter) - window_position_in_screen.x,
GET_Y_LPARAM(l_parameter) - window_position_in_screen.y
};
int wheel_delta = GET_WHEEL_DELTA_WPARAM(w_parameter) / WHEEL_DELTA * wheel_scroll_line;
...
break;
2010/01/09 17:41 2010/01/09 17:41
소수를 실무에서 구해야 할 일은 별로 없습니다. 하지만, 면접 볼 때 관련된 질문을 받을 때가 있습니다. 참고로, 저는 이렇게 실전엔 별로 유용하지 않은 이론적인 질문을 하는 면접을 상당히 싫어합니다.

소수를 구하려면 소수의 성질을 이용하면 됩니다. 어떤 수 n이 소수인지 판별하려면 다음처럼 하면 됩니다. n을 2부터 n - 1까지 하나씩 나누어서 나머지가 0일 때가 한 번도 없으면, n은 소수가 됩니다. 소스 코드는 아래와 같습니다.

bool is_prime_number(unsigned int number)
{
if (number < 2)
return false;
for (unsigned int divisor = 2; divisor < number; ++divisor)
if (number % divisor == 0)
return false;
return true;
}
2010/01/04 19:17 2010/01/04 19:17
IME를 처리하다 보면, 조합 중인 글자를 강제로 완성시켜야 할 때가 있습니다. 예를 들면, 글자 조합 도중에 버튼을 누르는데 조합이 완료된 텍스트를 일반적인 방법으로는 도저히 얻어 낼 수 없을 때입니다. 이럴 때엔 다음처럼 조합 중인 글자를 강제로 완성시키게 하면 됩니다. 하지만 그다지 권장할 만한 방법은 아니므로, 되도록 이런 처리가 필요없도록 하는 게 더 좋습니다.

case WM_LBUTTONDOWN:
HIMC ime_context = ImmGetContext(window_handle);
if (ime_context != NULL)
{
if (ImmGetCompositionString(ime_context, GCS_COMPSTR, NULL, 0) > 0)
ImmNotifyIME(ime_context, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
ImmReleaseContext(window_handle, ime_context);
}
break;
2010/01/03 18:57 2010/01/03 18:57
문자열 코드 변환에 사용되는 함수 중에서 코드 페이지를 인자로 받는 MultiByteToWideChar 함수나 WideCharToMultiByte 함수와 달리, mbstowcs 함수나 wcstombs 함수는 코드 페이지를 인자로 받지 않습니다. 그래서, 미리 코드 페이지 설정을 해 두어야 합니다. 실제로 mbstowcs 함수나 wcstombs 함수의 MSDN 도움말에도 지역 설정이 돼 있어야 한다고 명시돼 있지만, 구체적으로 setlocale 함수를 호출해야 한다고는 명시돼 있지 않아서 좀 혼란스럽습니다.

그런데, 외국에서 만든 일부 소프트웨어는 이런 처리를 하지 않습니다. 그래서 영어가 아닌 문자열을 제대로 인식하지 못할 때가 있는데, 이럴 때엔 당황하지 말고 코드 변환 함수 호출 전에 setlocale(LC_ALL, "")라고 해 주면, 현재 운영체제의 지역 설정에 따라 정상적으로 동작합니다.
2010/01/02 17:31 2010/01/02 17:31
게임 밸런스를 수정할 때 실수하기 쉬운 것이 있습니다. 그건 바로, 밸런스를 조금만 수정해도 게임 플레이에 미치는 영향이 상당히 클 수 있다는 사실입니다.

많은 기획자가 자신의 직관을 믿고 밸런스를 한 번에 목표 값까지 변경하려고 합니다. 하지만, 실제로 플레이해 보면 밸런스 조정이 지나쳐서, 또 다른 부분에서 밸런스를 붕괴시킬 때가 잦습니다. 게임에선 어떤 값을 바꾸면, 그것과 연관된 모든 것의 상대적인 값 또한 바뀌는 셈입니다. 어떤 값 하나를 수정했을 때, 그게 이렇게 보이지 않는 연관 관계에 얼마나 큰 영향을 미치는지 정확히 파악하기는 어렵습니다. 그래서 밸런스 수정은 최소한으로 주의 깊게 해야 합니다.

밸런스는 어디까지나 전체적으로 상대적인 균형을 맞추는 것이며, 부분만 보아서는 안 됩니다. 밸런스를 한 번에 맞춘다는 것은 어려운 일이므로, 최소한으로 수정하고 피드백을 얻어서 이상적인 값으로 조금씩 바꾸는 게 안전합니다. 프로그래밍뿐만 아니라, 밸런스 조정에도 점진적이고 반복적인 접근 방법을 취해야 합니다.
2010/01/01 13:13 2010/01/01 13:13
IsDebuggerPresent 함수를 이용하면 됩니다. 하지만, 특별히 사용할 일은 거의 없는 듯합니다.
2009/12/24 10:00 2009/12/24 10:00
게임 그래픽스에선 조명이 크게 두 가지 종류로 나뉘어집니다. 하나는 정적 조명이고, 다른 하나는 동적 조명입니다. 정적 조명은 실시간으로 속성 변경이 불가능하고 동적 객체로부터 영향을 받지 못합니다. 그래서 사실감이 떨어지므로, 최근엔 정적 조명보다 동적 조명을 지향하는 추세입니다.

정적 조명은 속성이 정적인 조명입니다. 여기서 속성이라 하면 조명의 종류, 위치, 방향, 색깔, 그리고 강도 등이 됩니다. 정적 조명은 동적인 객체(대표적으로 캐릭터)에 독립적(동적인 객체로부터 영향을 받지 않는)입니다. 정적 조명은 동적인 객체로부터 영향을 받지 않지만, 동적인 객체에 영향을 줄 수는 있습니다. 정적 조명은 실시간 계산이 필요없습니다. 그래서 대개 결과를 미리 구해 놓으므로, 복잡한 조명을 구현하더라도 게임 성능엔 거의 영향을 주지 않습니다. 정적 조명은 라이트 그리드(light grid), 라이트맵(lightmap), vertex color, ambient cube, irradiance volume, spherical harmonics environment light probes, 그리고 이미지-베이스드 라이팅(image-based lighting) 등의 기법으로 활용됩니다.

동적 조명은 속성이 동적인 조명입니다. 동적 조명은 동적인 객체의 영향을 받기도 해서, 동적인 객체의 형태가 변하면 그것의 영향을 받는 동적 조명의 결과도 달라질 수 있습니다. 동적 조명은 실시간으로 계산되므로, 조명 구현이 복잡하거나 많은 수의 동적 조명을 사용하면 게임 성능을 크게 떨어트립니다. 그런데 최근엔 deferred rendering과 그 유사한 기법의 등장으로, 상당히 많은 수의 동적 조명을 활용하는 것도 가능해졌습니다. 동적 조명은 크게 두 가지 종류로 나뉘어집니다. 첫 번째는 동적 객체에만 영향을 주는 것입니다. 두 번째는 정적 객체에도 영향을 주는 것인데, 이것은 부하가 당연히 더 큽니다. 대표적인 예로 태양광이 있습니다.

참고:
2009/12/05 14:25 2009/12/05 14:25