꽃미남 프로그래머 김포프가 창립한 탑 프로그래머 양성 교육 기관 POCU 아카데미 오픈!
절찬리에 수강생 모집 중!
프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다.
Posted by 대마왕J

KGC2012 PT 공유합니다.
이번 달 제 원고는 이걸로 슥삭 (후후후후)
너무 비난하지 말아주세요. 이런거 준비하려면 한 달은 족히 걸리는거 다 아시잖아요. 후다닥.



그리고 아무래도 회사의 녹을 먹어 가면서 살고 있는 직장인이니,
버릇없이 광고 한번 하겠습니다ㅎ 

뒤엎는 삽질없이 진짜 개발시간을 많이 들여서 만든건데 잘 되길 바랍니당 ㅎ






반응형
,
Posted by 알 수 없는 사용자

안녕하세요. 랩하는 좀비. 랩좀비입니다. 실제로 랩은 잘 못합니다. 뭐 중요한 것은 그게 아니고.

DOD에 대해서는 많이들 들어보셨을 겁니다. 

2010말에 DICE와 너티독 형님들에 의해서 체계적으로 정리 되어 발표 되었고, 작년 초에는 한국에도 소개가 많이 되어서 이런 저런 논의가 있었습니다. 적어도 작년말까지만 해도 꽤 활발한 토의가 진행되었었죠. 하지만 지금은 별 다른 이야기가 없어요. -이제 논의자체가 할 게 없는 것인가? 라는 생각도 듭니다.- 그냥 저렇게 하면 괜찮다. 하지만 적용 하기에는 좀 힘들지 않을까? 가 주된 내용인 것 같습니다.

OOP와 분리해서 생각 한다면 적용하는 것에 큰 문제는 없는 것 같습니다. 
이 글에서는 DOD의 복습과 어떻게 적용하였는지, 적용한 후에 프로그램은 얼마만큼 빨라졌는지에 대해서 얘기해 볼까 합니다.

DOD란?
...사실 새로 적을 것도 없기에 링크로 대체합니다.
친절한티스님의 글 : http://kindtis.tistory.com/341
김학규님의 글 : http://www.lameproof.com/index.php?mid=neolith&document_srl=174115
작년에 발표한 슬라이드 : http://www.slideshare.net/hyurichel/data-oriented-design-8284688
최근 이것과 관련해서 글을 써보자 하는 계기가 된 슬라이드 : http://www.slideshare.net/ssmim101/data-oriented-design-13941654

순서대로 읽으시면 쉽게 DOD가 무엇인지 파악할 수 있습니다.
간단히 요약하자면 배열로 잡아버리고 한번에 Update를 하자. 가 되겠습니다.

적용해보자
DOD는 대규모 데이터를 처리하는 데 가장 좋은 방식입니다.
게임에서 대규모로 처리할 부분이 있다면? 여기서는 Rendering Material들의 Update와 옥트리 컬링을 대표적인 예로 들까 합니다.

1. Material 업데이트
게임에서 렌더링되는 오브젝트들은 자신의 Material을 알고 있습니다. 그리고 Material이 시간에 따라 변화하게 된다면 당연히 CPU에서 해당 정보를 Update하여 Shader에 알려주어야 하지요. 이 Update하는 것을 OOP관점에서 디자인 한다면...

이렇게 되겠습니다. 지금까지 다들 그래왔고, 이것이 진리라고 생각했을 겁니다. ...나만 그랬나. 이런 구조를 만들어 놓으면 새로운 타입의 Material이 추가되어도 Update하는 방식은 외부에서 몰라도 되는 아주 OOP적인 디자인입니다.

이것을 DOD형태로 바꾸어 볼까요?


그림이 개발새발이지만 잘 아시리라 믿습니다.

이렇게 되겠습니다. 기본 구조는 똑같습니다. OOP의 장점을 버릴 수는 없습니다. 렌더링용 Material은 커다란 Pool에서 관리하도록 하고 CType1과 CTyp2는 포인터만 들고 있습니다. Pool에서 삽입과 삭제만 상수시간으로 결정할 수 있다면 성능 저하도 없습니다. 새로운 머터리얼 타입이 추가되어도, OOP의 이점으로 클래스를 추가하고 Pool에서 새로운 데이터 타입만 만들어주면 됩니다.

그럼 얼만큼 빨라졌을까요?


OOP의 Update. 0.41866ms가 소모됩니다.


DOD할 때는 0.23460의 시간이 소모되었습니다.

기본 2~3배 정도 속도향상이 됩니다.
의외로 성능향상이 별로 없습니다. 하지만 DOD의 이점은 Thread와 결합할 때 빛을 발합니다. 
OpenMP를 이용하여 적용해 보았습니다.

그냥 DOD Pool에서의 Update. 2.40707


Thread로 돌렸을 때, Core가 100%로 돌아가고 있습니다. 0.56839

5배 정도 성능이 향상되었네요. OOP에서 DOD로 2배. DOD에서 DOD_Thread로 5배.
총 10배의 성능이 향상되었습니다.
게임에 적용된다면 OOP보다 적어도 4-5배는 더 빨라졌을 것이라고 예상됩니다.


2. 옥트리 컬링
화면에 보이는 오브젝트를 걸러내기 위해서 옥트리 컬링을 하고 있습니다. ...이것도 DOD형태로 바꿔봅시다.
바꾸는 형식은 위의 Material 업데이트를 참고해서 하면 될 것 같습니다.

스크린샷은 올릴 수가 없기 때문에 그냥 글로써 얘기하자면, 옥트리와 비슷하거나 2-3배 정도 빠릅니다.
옥트리는 카메라의 위치에 따라서 속도의 변동이 있고, DOD는 속도의 변동이 없습니다.
또다른 이점으로 캐릭터나 Effect, Sound등등도 같이 한 번에 묶어서 컬링할 수 있기 때문에 좀 더 많은 성능 향상이 있었습니다.

결론

대규모 데이터를 처리할 때 DOD만큼 좋은 것은 없는 것 같습니다. Pool에서 삽입삭제만 상수시간으로 가능하다면 꽤 멋진 디자인입니다. Thread도 Lock-Free로 돌아가니 뭔가 한 듯한 기분도 듭니다. 결과적으로 좀 짱인 것 같습니다.

여러분도 적용해 보아요.

반응형
,
Posted by 밥을먹는선비

0. 들어가며....

지금 글을 쓰는 시점은 추석전인데 아마 글이 다완성 되면 추석이 지난 10월 초쯤일거라는 생각이 듭니다. 개인적으로 이세상에서 가장존경하는 분이 아버지라는 분이 계시는데 전 그분이 세상에서 제일 부럽기도 하고 동시에 잘이해가지 않는 것도 사실입니다. 웬지 저와는 다른 세계인거같기도 하고요. 

아버지와 전 지지하는 대선 후보부터 극과극으로 다름니다. 

한마디로 불행한거지요.

그렇지만...올해는 정말 아버지를 존경하고 싶습니다.


추석을 맞이하여 때론...

남남은 return처럼 쿨할수있지만.. 

혈육은 yield와 같다는 생각을 해보며 강좌를 시작 해보겠습니다.


1. yield 문법


yield [coroutine | YieldInstruction]


위와 같이 코루틴 또는 yield명령어가 오거나 또는 아무것도 오지않을수있습니다. 


기본적으로 yield문이 오면 그위치부터 실행이 일단 보류됩니다. 그 다음에 뒤에오는 명령어또는 코루틴이 종료가될때까지 다음으로 진행하지 않습니다.

해당 자바스크립트에서만 실행이보류되고 다른 자바스크립트로 실행이 넘어 가는것입니다. (만약 해당 자바스크립트내에서 최상위 함수였다면)

이것은 멀티쓰레드에서 비선점형 방식으로 스케쥴링하는것과 비슷합니다.


그래서 당연히 뒤에 아무것도 없다면 그 부분에서 단순히 실행만 보류되고 바로 호출한 윗단계 함수로 실행이 넘어가게됩니다.






foo1 foo2 라는 코루틴을 차례로 호출해본 예입니다. 이것을 실행 시키면 결과는 다음과 같습니다.






여기서 만약 28번째 라인의 foo1()을


yield foo1();  으로 수정해주면 결과 값은 아래와 같이 바뀌게 됩니다.






앞에써준 yield  때문에 foo1이 완전히 끝날때 까지 기다렸다가 foo2가 실행됩니다. 그렇지만   foo1이 끝날때까지 기다린다고해서 실행전체가 블러킹이 되는것이 아닙니다.



2. return 과 yield


코루틴을 실행할때 앞에 yield가 붙는것과 붙지않는것의 차이점은 다음과 같습니다.


yield가 앞에 붙으면...

코루틴이 호출되기 전에 실행이 보류되며 해당코루틴이 완전히 종료될때까지 그 다음 라인으로 진행하지않는다. 코루틴내에서 실행보류가 일어나더라도 호출한 함수측에서 그 다음 라인으로 진행은 하지않는다.


그냥 코루틴만 호출되면..

코루틴이 실행보류 상태가 되고 호출한 측으로 돌아와서 그 다음 라인의 실행이 재개된다. 그다음 프레임에 다시 보류된 라인부터 실행이 재개된다.  


여기서 얻을수 있는 결론은 코루틴내에서 yield는 마치 리턴문처럼 실행 흐름이 호출한 측으로 다시 되돌아가지만, 리턴문처럼 해당 코루틴의 실행을 종료하지않고 그부분부터 다시 실행을 재개할수있다는 점이 리턴문과는 다르다는것을 알 수 있습니다. 


이부분이 좀 많이 헷깔릴수도 있는 부분이라서 익숙하게 다루기 위해서는 연습이 많이 필요한 부분입니다.


yield 와 return을 닮을 꼴로 보시고 return은 완전히 쫑난거고 yield는 먼가 미련이 남은 상태라고 보시면됩니다. 예를 들면 여친과 헤어졌는데 쿨하지못하게 연락처를 남겨놓앗다면  이것은 yield가되는것이죠.





또하나의 예를 헤어진 여친의 명품백 선물의 카드할부값이 아직 남아 있는상태라고 보셔도 무방합니다.

return은 일시불이고요.


3. 결론


yield가 컨택스트 스위칭을 해주는것은 아닙니다. 다만 좀 비슷할뿐입니다. 예전 영화중에 좋은놈 나쁜놈 이상한놈이라는 영화가 있었는데 좀 그런 어정쩡한 개념일수도있습니다. 유니티에서 우리가 생각하는 컨택스트 스위칭 비슷한 일이 일어나는시점은 자바스크립트내에서 최상위 코루틴에서 yield가 나올때입니다. 단 예외로 update에는 yield문의 사용이 금지됩니다.





 





반응형
,
Posted by 알 수 없는 사용자
우리의 목표.

우리의 목표.


지난 시간에 MUD(Multi User Dungeon)을 만들겠다고 선언했습니다.
뜬금없이 MUD를 만드는 목적은 MUD 그 자체가 목적이 아닙니다.
최종 목적은 다수의 유저가 접속하고 게임 서비스를 진행해주는 C/S 시스템을 만드는 것인데,
그것을 위해 기본이 되는 컨텐츠가 필요하기에 MUD를 만드는 것입니다.

다행히 MUD는 상당수의 MMORPG와 비슷합니다.
MMORPG도 MUD에 결국 그래픽이 덮씌워진 것입니다.
물론 그래픽을 비롯해 여러 최신 기법들이 적용되어 있고 언젠가 그것들을 이해해야 합니다.
하지만 처음부터 복잡한 원리를 억지로 이해할려고 하는 것보다 먼저 그게 왜 필요했는지를 알면 더 좋을 거라 생각듭니다.
이번 튜터리얼을 통해 MUD를 만들며 거기에 대한 해답을 얻을수 있었으면 합니다.

1. RPG 게임의 기본 요소, 혹은 객체
MUD를 구현하기에는 RPG가 가장 알맞으니까 RPG를 만들 것입니다.
소드 아트 온라인을 만들고 싶다!!!!


그럼 반도의 흔한 양산형(^^;;) RPG에는 어떤 요소들이 필요할까요?

1) 공간
지형이죠. 땅은 물론이고 하늘과 바다같은 공간입니다.
공간이 있어야 플레이어와 몹이 뛰어다니고 날라다닐수 있습니다.
특별한 경우를 제외하면 지형 이나 공간 자체가 객체가 되는 일은 없습니다만
공간이야말로 캐릭터들을 위한 가장 기본적인 데이터가 됩니다.

위엄돋는 프로브

위엄돋는 프로브


대부분의 땅은 2차열 배열로 충분합니다.
물론 게임이 커지며 쿼드트리, 옥트리나 분할타일...등등 다양한 방식들이 존재하는데 지금은 굳히 어려운 기법으로 구현할 필요 없습니다.
필요할때 공부하면 됩니다. 사실 클라이언트와 결합되면 이런 것들만 소개해도 책 몇권 나올겁니다. 그래서 우리는 엔진을 선택하죠. ㅠ.ㅠ;

2차원 배열, 다시 말해 타일앱(Tilemap)은 게임에 있어서 뼈대와 같습니다.
아니 2D 게임이라면 죄다 타일맵입니다. 배열을 보여줄때 어떤 꽁수를 부리느냐에 따라 사각형이나 마름모가 될뿐입니다.
이것도 2차열 배열

이것도 2차열 배열

요것도 2차원 배열

요것도 2차원 배열

심지어 이것도 2차원 배열~

심지어 이것도 2차원 배열~

2차원 타일앱에 대해 더 알고 싶다면,
http://kangcom.com/sub/view.asp?sku=200107040021http://kangcom.com/sub/view.asp?sku=200407060008 책을 추천합니다.
좀 고전적인 내용이긴 합니다만 그만큼 기초적이며 필수적인 내용들을 다루고 있습니다.
꽤 오래된 책이긴 하죠? ^^

꽤 오래된 책이긴 하죠? ^^

사실 Isometric Game Programiing with DirectX는 쓸때없이 두껍습니다.
정작 필요한 챕터는 몇십페이지가 안됩니다.
반면 DirectX9를 이용한 전략 게임 프로그래밍은 길찾기부터 전반적인 내용이 다들어가고 있고
정말 좋아했던 번역자분이 번역하신 책입니다. 좋은 번역이 무엇인지를 제대로 보여주는 몇안되는 기술서적이죠.

너구리 같은 사이드뷰(side view) 방식, 혹은 장기같은 탑뷰(top view)타일맵의 기본은 정말이지 너무 간단합니다.
사이즈에 맞는 2차원 배열을 만들고 for() 문 두개면 뚝딱 나옵니다.
일단 가로x세로, 각각 10칸씩 차지하는 맵을 만들어봅시다.
int map[MapSizeX][MapSizeY] =
{
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
네 이것으로 다입니다. ^-^;;;
배열 처음 배울때 배운 것 그대로입니다.


땅을 화면에 표현해볼까요?
void DrawAllMap()
{
    for(int MapX = 0; MapX < MapSizeY; MapX++)
    {
        for(int MapY = 0; MapY < MapSizeX; MapY++)
        {
             cout << MapY << "," << MapX << ": " << map[MapX][MapY] << " ";
         }
       cout << endl;
   }
}
 

드디어 첫선을 보이는 소드 아트 온라인(?) 머드

몇 바이트 안되는 자료구조로 캐릭터가 뛰어놀 땅이 생긴 것입니다.
각각의 배열은 좌표계를 의미합니다.
그래픽 게임이라면 각 칸을 이동하는 애니메이션이 추가되면 됩니다.
하지만 이건 MUD니까 그냥 "~로 이동했다" 정도로 표시하면 될 것입니다.

 

드디어 첫선을 보이는 소드 아트 온라인(?) 머드
드디어 첫선을 보이는 소드 아트 온라인(?) 머드

만약 공간 구현에 있어 데이터 최소사이즈 덕후가 되어 보고 싶다면 이 책을 추천합니다.
http://kangcom.com/sub/view.asp?sku=200205090004&mcd=571
제가 아주 좋아하는 책인데 지형뿐만 아니라 앞으로 다룰 플레이어 객체와의 상호작용까지 다룹니다.
각종 게임회사 입사 퀴즈 문제가 이 안에 있음.

각종 게임회사 입사 퀴즈 문제가 이 안에 있음.

 

2) 캐릭터 - PC/NPC
보통 플레이어와 몹을 따로 생각하는 경향이 있지만 결국 같은 액터(actor)라고 봐도 무방합니다.
보통 유저가 직접 조작할수 있는 PC(Playable Character)와 NPC(None Playable Character)로 나뉩니다.
NPC는 상점 주인이나 몹이 대표적입니다.

PC와 NPC의 구분이란?

PC와 NPC의 구분이란?


경우에 따라 특정 아이템이나 장치도 NPC가 될수 있습니다.
상자를 열자마자 나타나는 저주받은 칼이라던가 두동강 내는 절단 장치 등도 게임에 따라 내부적으로 NPC로 구현된 경우가 있습니다.
이런 캐릭터야말로 OOP방식으로 게임을 만든다면 가장 기본적인 객체로 구분할 수 있을 것입니다.
물론 이동, 공격, 스킬도 캐릭터의 가장 중요한 속성입니다.

우선 싱글 위주로 구현을 해보죠.
원래는 C++ 없이 C만으로도 게임 만들기 쉽다는 것을 보여주기 위해 순수 C로 만들어볼 생각이었지만,
역시 C++을 안쓰니 제가 불편해 구조체 대신 C++ 클래스로 만들었습니다.

우리의 캐릭터, 아니 플레이어 객체가 가지고 있어야할 가장 기본적인 데이터는 무엇일까요?

1) 클래스 자체의 정보 - RTTI를 위해
2) 현재 위치 - 플레이어가 뛰어다닐 공간은 2차원 배열이니까 2차원 배열의 X, Y값이 들어갑니다.
3) 이름, 레벨, 경험치...
4) 소유 아이템
5) 가능한 퀘스트(이벤트)/현재 퀘스트(이벤트)

이중 우선 움직이는게 관건이니 2)의 현재 위치를 먼저 구현하겠습니다.
나머지는 다중 사용자와 컨텐츠가 붙으며 천천히 구현해도 될 것 같네요.
1)의 클래스 자체의 정보는 고급 토픽입니다.
일단 상속과 다른 캐릭터들이 추가되며 그때 다시 이야기해보지요.

enum _DIRECTION
{
    NORTH = 0,
    EAST = 1,
    SOUTH = 2,
    WEST = 3
};

typedef struct _GamePosition
{
    int iPosX;
    int iPosY;
    _DIRECTION Direction;
} GamePosition;


class CGamePlayer
{
public:
    CGamePlayer(GamePosition& playerPos);
     ~CGamePlayer(void);

    int SetPosition(GamePosition& playerPos);
    GamePosition GetPosition();

private:
    GamePosition m_playerPos;
};

일단 위치만 넣었습니다만 위치 변수를 int형 X, Y를 그대로 사용하지 않고 GamePosition이라는 구조체를 만들어 썼습니다.
중요한 것은 위치정보 안에 _DIRECTION이라는 방향정보까지 들어가 있다는 점이죠.
게임을 만들때 위치가 있으면 대부분 바라보는 방향도 있으니까요.
이렇든 구현을 하다보면 자체의 데이터를 정의하기 위한 구조체나 클래스들이 어쩔수 없이 많이 나오게 됩니다.
그리고 이런 것들을 잘 쓰는게 OOP의 은닉화, 혹은 캡슐화(encapsulation)입니다.

아뭏든 상기의 플레이어 클래스를 보니 현재 이 게임은 10x10의 공간 속에 방향을 가지고 위치를 이동하는 게임이라는 것이 명확해졌습니다.

여담으로 며칠전 간만에 학부생들이 한가득한 어떤 프로그래밍 게시판을 들렀습니다(후빨 받을려고 간거 아님).
언제나처럼 불변의 진리로 "숙제 때문에" 클래스와 인터페이스 설계 떡밥은 가라앉질 않더군요.
학교에서 내주는 클래스 설계 숙제나 초보용 예제는 그 힘든 OOP 개념을 설명하긴 설명하긴 해야겠는데,
억지로 간단한 수준에서 구현할려보니 도리어 더 헛갈린다고 생각합니다.
사실 상속이나 인터페이스는 학부 교재 수준의 단순한 코드를 위해 만들어진건 아닙니다.
실제 캐릭터들간의 교과서적인 상속같은 것 역시 별로 중요한 문제도 아닙니다.
개념적인 상속을 받지 않고도 구현할 수 있고 다양한 방법들이 많습니다.
예를 들면 클라이언트라면 코드의 재사용이 아닌 렌더러를 타기 위해 상속을 받거나, 상속 자체보다 통보 메시지를 일시에 받기위한 다형성(polymorphism)이 보다 중요합니다.

이런 이야기 역시 천천히 진행해볼까 합니다. 물론 여기는 현업 개발자마다 프로젝트마다 다른 방법이 있고 치고 박고 싸울 떡밥은 충분히 됩니다만, 저라면 제일 중요한게 "라이브할때 편한 방식"입니다. 라이브팀에게 "이거 만든 넘이 너지?!"하면서 등에 칼맞긴 싫거든요.

3) 돈/아이템
돈과 아이템이 없는 게임이 있을까요.
아이템은 캐릭터의 상태와 속성을 변화시키고 수치를 바꾸고 이벤트를 발생시킬수도 있습니다.
아이템은 C/S 환경에서 더욱 복잡해집니다.
언젠가부터 필수 요소인 경매장도 아이템 설계에 많은 변형을 가져와야 했으며 복사템 문제는 여전히 골치를 앓게 합니다.
이 부분은 구현 이전에 알아야할 다른 문제들이 있으니 조금 더 나중으로 미루겠습니다. ^^

여담으로 최근 가장 관심이 갔던 아이템은 디아블로3의 "소멸의 염료"였습니다. 하의는 항상 소멸의 염로로 염색한다!

캐릭터 객처와 아이템 객체간 상호작용에 대한 아주 좋은 사례

캐릭터 객처와 아이템 객체간 상호작용에 대한 아주 좋은 사례

(출처 : Bump of Romance http://djrtoddl.egloos.com/3328165)

4) 퀘스트/이벤트
사람과 팀에 따라 구현방식이 달라지겠지만,
저는 퀘스트와 이벤트도 하나의 객체로 취급합니다.
이런 개념의 차이는 게임 구현에 큰 영향을 끼치게 됩니다.
아이템과 함께 퀘스트/이벤트는 캐릭터와 끊임없는 상호 작용을 거치게 됩니다.
NPC를 통해 퀘스트를 해결하는 좋은 사례

NPC를 통해 퀘스트를 해결하는 좋은 사례


아이템과 같이 일단 긴 설명은 시기상조입니다만 상기의 네가지들은 게임 컨텐츠를 만드는데 있어서
제가 뽑은 가장 기본적인 필수요소들이라 생각합니다.
있어 보일려고 한다면 더 적을수도 있겠지만 정말이지 이 네가지면 기본은 충분합니다.

3. 움직이자!!
아무리 좋은 동영상도 단순한 게임 그래픽보다 못합니다. 게임은 입력을 받아 인터랙티브하게 움직여 주니까요.
이제 움직여야죠.
플레이어를 움직이게 하는 것은 간단히 getchar()나 cin이면 충분합니다. 오오~ CUI 창의 위대함이여~
C 첫 시간에 배운 순환문과 입력함수면 게임 루프를 만들수 있습니다.

여기에서 한가지 기억해둬야 할 것은 사용자가 여러개의 입력을 한 경우입니다.
아쉽게도 C/C++ 표준함수만으로는 깔끔하게 한글자만 정확히 입력받을순 없습니다.
아래 보시면 while문이 있는데 첫번째 글자 이후로는 리턴시킵니다.

움직임은 플레이어의 위치 값만 바꿔주면 됩니다.

int SetMovePlayer(CGamePlayer* pGamePlayer)
{
 cout << "어디로 이동할 것인가?" << endl;
 cout << "E: 동쪽 W: 서쪽 S: 남쪽 N: 북쪽 .: 종료" << endl;

 char ch;
 while((ch = cin.get()) != '.')
 {
  ch = tolower(ch);
  switch(ch)
  {
  case 'e' :
   {
    GamePosition pos = pGamePlayer->GetPosition();
    pos.iPosY++;
    
    if(pos.iPosY >= MapSizeY)
    {
     pos.iPosY--;
     cout << "그곳으로는 이동할 수 없다." << endl;
    }
    else
    {
     cout << "키리토는 동쪽으로 이동하였다." << endl;
     pGamePlayer->SetPosition(pos);
    }    
   } 
   break;

 

// 생략

 

  default:
   cout << "잘못된 명령입니다." << endl;
  }
  
  while(cin.get() != '\n')
   continue;

  SetDirectionPlayer(pGamePlayer);
 }

 return 1;
}

흠....2차원 배열이라는게 깔끔하게 직관적인 X, Y 좌표계가 아니라서 이동이 좀 헛갈리겠군요.
그림으로 그려보니 이렇게 동남쪽을 향하는 좌표계가 되었습니다.

SOA의 제멋대로 좌표계

SAO의 제멋대로 좌표계


논리적 좌표계는 게임마다 다른거니 귀찮아서 수정하지 않고 이대로 갈까합니다.
(이미 Move함수를 만들어 두었으니 또써먹으면 되니까요.)
위의 소스 정말 쉽죠?
방향에 따라 X, Y 위치만 바꿔주면 정말로 이동합니다, 아니 이동하는 것처럼 됩니다.
그리고 중요한 부분이 있죠, 바로 화면 밖으로 나가지 못하도록 하는 클리핑(clipping)입니다.
너무나 중요해서 다시 적습니다, 이 부분이죠, 이 부분.

pos.iPosY++;

if(pos.iPosY >= MapSizeY)
{
pos.iPosY--;
cout << "그곳으로는 이동할 수 없다." << endl;
}

그런데 코드를 보니 일단 이동한번 해봤다가 조건에 걸리면 뒤로 빼는군요.
아!!!!!!!!!!!!!!!!!!
이래서 게임을 하다보면 오브젝트에 끼워 왔다리 갔다리 화면이 덜덜덜덜 거리는 현상이 일어나는가 봅니다!!!

다음 시간에 다룰 것이지만 이 루틴에 조건들만 추가하면 그럴싸한 충돌처리가 됩니다.

아래 부분에 while()과 continue 가 있습니다.
이 부분의 역활은 무엇일까요?
사용자가 방향이라는 한 단어 대신 "eeeeeeeeeeeeeeeeee"식으로 여러개의 명령이 왔을때 skip하는 부분입니다.
이런 입출력에 대한 예외처리는 이런 단순한 게임이라도 반드시 들어가며 나중에 완성도를 좌지우지하는 중요한 부분입니다.
아직 공부 중이라 작은 소품들을 만드는 것은 아주 훌륭합니다만,
이런 예외처리를 놓치지 마세요.
거대한 프로젝트라도 바로 이런 부분에서 새어버리면 망하는 지름길이 됩니다.

그런데 일부러 코드에서 이 부분을 빼버리면 어떨까?
흠.................. ?

 

4. 사실같은 그래픽

마음의 눈으로 보면 실사같은 그래픽이 됩니다.

마음의 눈으로 보면 사실같은 그래픽이 됩니다.


사실같은 그래픽까지는 바라지도 않고 원작같은 그래픽 뽑고 싶습니다!!!!!!!!!!!
...는 무리고 현재 배열과 플레이어의 위치를 능력껏 최대한 화려한 그래픽으로 뽑아봅시다.

배열에 따라 땅과 플레이어의 방향을 표시할 것입니다.
이번에도 for()문 두개면 끝납니다.
조건은 플레이어의 위치와 방향입니다. 아무 것도 없는 땅은 "▦"로 표시합니다.

void DrawAllMapWithPlayer(CGamePlayer* pGamePlayer)
{
 for(int MapX = 0; MapX < MapSizeY; MapX++)
 {
  for(int MapY = 0; MapY < MapSizeX; MapY++)
  {
   if((pGamePlayer->GetPosition().iPosX == MapX) && (pGamePlayer->GetPosition().iPosY == MapY))
   {
    switch(pGamePlayer->GetPosition().Direction)
    {
    case EAST :
     cout << "▶";
     break;
    case WEST :
     cout << "◀";
     break;
    case SOUTH :
     cout << "▼";
     break;
    case NORTH :
     cout << "▲";
     break;
    default:
     break;
    }
   }
   else
   {
    cout << "▦";
   }
  }
  cout << endl;
 }
}

그럭저럭 이번 원고 완성 ㅜㅜ

그럭저럭 이번 원고 완성 ㅜㅜ

자, 몇줄 안되는 코드로 나름 MUD같은게 나왔습니다. 정확히 말하자면 싱글게임이지만요.
이번 화에서 강조하고 싶은 것은 게임 컨텐츠를 만드는데 엄청난 실력까지 필요없다는 것입니다.

소스를 보면 아시겠지만, 대입, 순환, 조건과 너무나 간단한 기본 입출력으로 게임틱한 프로젝트를 만든 것입니다.

"지형, 플레이어, 입력, 이동", 거기에 예외처리까지 이번 화속에 다 들어있습니다.
화려한 상용게임도 크게 다르지 않습니다.

그야말로 존경하옵는 다익스트라님의 증명이 다시한번 이뤄지는 순간입니다.


다음 시간에는 NPC와 전투를 다뤄볼까 합니다. 조금씩 덩치가 커지며 필요한 클래스들도 추가될 것 같습니다.

이제 추석 연휴군요, 추석 동안 살찌지 말고 친척분들에게 정신공격 당하지도 공격하지도 않으시길 바랍니다.

건강하게 연휴를 보내고 다시 뵙겠습니다.

PS) 소스를 실행시키면 사실같은 그래픽...뿐만 아니라 화려한 사운드가 나옵니다.

내용은 맘대로 퍼갈수 있지만 동의없는 수정은 안되며 출처(http://www.gamedevforever.com/ , http://rhea.pe.kr/)를 명시해주세요.

SAO1.zip



반응형
,
Posted by 밥을먹는선비

0. 시작하면서...


강좌를 많이 건너뛴듯합니다. 맹장염이 갑자기 걸리는 바람에 또다시 날짜를 넘겨버리고 말았네요. 역시 나이 먹으니 잘먹고 잘생활하는 게 중요한거같습니다. 애들도 크고 좀더 제대로된 내집을 좀 마련해 보려고 식비라도 줄여 돈을 아끼려 몇달간 라면만 먹고 살았더니 내장일부가 썩고 맹장은 완전히 썩어서 결국 수술을 하게 되었습니다. 내장이 썩어 간다는게 생각보다 끔찍하더군요. 내장곳곳이 검게 그을듯한 모습이 좀 끔직하더군요. 젊은 분들도 마찬가지겠지만 마흔넘어서는 되도록 라면같은 음식은 자주 먹어선 안되겠다는 생각이들었습니다.

운이 없는 지 좋은 건지는 몰라도 6인실 병실에 저말고 모두 시한부 판정받은 암환자 분들만 모여있는 방으로 배정을 받았습니다. 그런분들하고있다보니 인생이 참 별거없다는 생각이 들더군요. 그리고 우리의 시간은 매우 한정되 살고있다는 생각도들고요. 그러기 때문에 잠시도 무의미해게 하기 억지로 싫은걸하고 살기엔 너무 짧다는 생각도 들었습니다. 잠시나마 억지로 돈을 아껴가며 무리하게 살았던 제가 어리석었다는 생각이 들었습니다.


1. coroutine(동시루틴)


언어에 따라서 컴파일러 차원에서 지원해주는 개념입니다. 유니티의 자바스크립트의경우는 컴파일러 차원에서 코루틴을 지원해줍니다. 

StartCoroutine 함수에 인자로 코루틴을 호출하는 형태로 넣어줍니다. (언제든지 yield문을 만나면 중간에 함수에서 일시적으로 나올수있도록 함수를 호출 하라는 뜻)


예>


...

StartCoroutine(WaitAndPrint(2.0)); 

...



그러나 유니티의 자바스크립트에서는  만약 호출되는 함수측에 yield 구문이 존재하면 자동으로 StartCoroutine을 하는 해주게됩니다. 유니티엔진에서 사용되는 자바스크립트는 언어차원에서 코루틴을 지원하기 때문입니다. 여기서 쓰인 StartCoroutine는 이전의 소스와 호환을 유지하기위해 존재할뿐 별의미는 없습니다.( 생략해도 됩니다!)

표준 자바스크립트(ECMA script)는 아직 언어수준에서 코루틴을 지원하고 있지는 않습니다. 차기 버전에서 부분적으로 코루틴을 지원할예정이라고합니다.

물론 코루틴이라는게 언어차원에서 지원하지않는다고 못할것은 없기 때문에 관련 라이브러리등이 나와있습니다.


일반적인 함수호출은 함수가 종료되어 return이 되면 호출했던 측으로 돌아와 실행을 재개하지만 코루틴으로 호출이되면 종료되지않아도 yield를 만나면 언제든지 이전 호출 단계로 다시 돌아왔다가 적당한 시점에(게임에서는 그 다음 애니메이션 프레임루프인경우가 대부분임, WaitForFixedUpdate 같은것을 써서 실행 타이밍을 고정프레임으로 지정할수도 있음) 그다음부터 다시 실행을 재개하는 방식입니다.


2. 동시 루틴 적용예


아래 예제에서 WaitAndPrint함수는 그안에 yield구문이 존재 하므로 컴파일러가 알아서 코루틴으로 호출을합니다.

16번 라인은 주석처럼

StartCoroutine(WaitAndPrint(2.0)); 과 같고 또한


StartCoroutine( "WaitAndPrint",2.0); 과도 같습니다.





위의 소스에서 화살표옆에 있는 숫자들은 실행의 순서를 표시한것입니다. 색깔별로 화살표를 구분했는데요 그 이유는 색깔별로 실행단계의 평행성을 구분 지어 놓은것입니다. 

예를 들어 3번 실행단계 이후에 4번 실행단계가 오는 것은 이 자바스크립트안에서는 순차적으로 바로 다음 단계이지만 그사이에 다른 실행 단계들이 끼어 들어 올수 있는 일종의 시간의 틈새 역활을 해주게됩니다.(이부분의 평행 세계 이론에서 나오는 시간의틈의 개념과 많이 유사합니다. )


이 자바스크립트소스가 하나의 실행컴포넌트로써 동작하는 것은 하나의 평행세계가 되고 이세계에서는 다른 평행셰계가 틈세로 겹쳐있지만 전혀 인지를 못하는 것이지요.(마치 우리가 다른 평행세계의 나를 전혀 알수없듯이 말이죠.)


[실행결과]





3. 그럼 평행세계를 구현해서 멋에 쓰게요?


맞습니다. 쓰얄대기 없는 짓일수도있습니다. 그리고 코루틴은 엄밀히 말해서 멀티쓰레드 처럼 마법이 아닙니다. 그냥 조잡해 보이는 단일쓰레드 눈속임이라고 무시해버릴수도 있습니다. 더구나 이거 안쓴다고 경찰출동 할일도 없고요. (이거 안쓰고도 게임 만드는데 전혀 지장없습니다.^^)

그러나 비동기적인 방식으로 처리해야하는 많은 게임상의 로직을 복잡한 추상클래스나 상속 다중상속들으로 해결하는 기존의 객체지향적인 방법론들이 꼭 정답이라는 생각을 하기에는 우리의 상상력이 너무 삭막해지지않을까? 하는 잉여로운 생각을 해봅니다.






혹시 시간 되시면 영화 소스 코드를 한번 보시고 시간의 틈사이에 존재 하는 사바 세계에서 헤메이는 주인공처럼 코딩을 시작해보시는 것은 어떨지요.^^; 











반응형
,
Posted by 알 수 없는 사용자


안녕하세요?
정말이지 5개월만에 네트워크 게임 튜터리얼 연재를 다시 시작합니다.

비 한방울 내리지 않던 무더운 여름, 헬파이어 미사일을 맞은 듯한 시간을 보내다 부활했습니다.
기나긴 슬럼프를 극복시켜준 것은, 소드 아트 온라인 덕분입니다.

덕분에 이런 주말 http://twitter.com/RheaStrike/status/247300021152788480/photo/1 을 보냈지만 이게 다 네크로먼서질 당하는 과정임.

얼떨결에 나를 부활시켜준 아스나

얼떨결에 나를 부활시켜준 아스나


먼저 지난 1기(멋대로 1기 타령... 한 쿨도 아닌 주제에ㅠㅠ)에 배운 것을 정리해볼까요?
1화 : 떡밥 투척
2화 : C/S와 P2P의 간략한 구조
2-1화 : 홀펀칭 좀 적다가 생략. 본진에도 업로드 안함.
3화 : ADO를 이용한 데이터베이스 연결 및 로긴
4화 : 로비 - 예제없음. 크윽
5화 : boost.serialize를 이용한 직렬화. 사실 5화를 보면 3, 4화를 바탕으로 셀프 제작 가능해야함.

돌아보니 주로 서버 엔진측에 대한 필수+기초만을 다룬 것 같습니다.
사실 연재를 못한 기간동안에도 대략 이런 일들과 플랫폼 서버쪽을 만들고 놀고 있었습니다.
실전에서도 언제나 이런 밑밥투척부터 잘 되어야 튼튼한 프로젝트가 되기 때문입니다.

그래서 연재방향도 자칫 미들웨어(middle ware) 제작 쪽으로 흘러갈뻔 하다가...
네, 마음대로 지난 1기를 종결하고 새롭게 2기를 시작해봅니다.
2기 때부터는 본격 컨텐츠 제작 이야기를 해보죠, 물론 제목대로 네트워크는 필수입니다.
이 모든게 소드 아트 온라인 때문입니다.

저두 서버측 밑밥 엔진 이야기만 하다보니 질린게 사실이고요.

그럼 2기도 떡밥 투척부터 시작하겠습니다.

1. 보통 프로그램팀의 인력구성은?
먼저 말씀드리고 싶은게 흔히 말하는 "프로그램팀"의 인력구성입니다.
라이브를 하지 않고 신규 개발만 하는 팀이라면 사실 10여명이면 왠만한 서버와 클라이언트등 게임에 필요한 애플리케이션들을 뽑아냅니다.
또한 실력은 보통 10명 중 3~4명은 고수, 5명은 중수, 1~2명은 뉴비 정도로 이뤄집니다.
제가 감히 실력을 구분짓는건 무언가 아니겠지만 보통 이렇게 이뤄지는게 사실입니다.

그리고 이 10명은 어떻게 일을 할까요?
10명이 개떼처럼 서버를 뚝딱 만들고 클라이언트를 뚝따 만들지는 않을 것입니다.
보통 서버파트와 클라이언트 파트로 나눠지며 혹은 서버 파트, 컨텐츠 파트, 클라이언트 파트로 구성되기도 합니다.
(참고 : http://rhea.pe.kr/283)

흔히 말하는, 게임을 공부하는 분들이 가고 싶어하는 분야가 클라이언트 파트라고 생각합니다.
시중에 나와있는 책들의 대부분이 렌더러를 포함하여 클라이언트 기술들이죠.
그러나 실제 렌더러만 전담하는 개발자는 이 10명중 1, 2명이거나 아예 엔진팀이 별도로 있는 경우가 많습니다.
따라서 클라이언트 개발자는 절대 렌더러 개발자가 아닙니다.
서버 역시 마찬가지입니다. 이 10명 중, 제대로 소켓을 다룰수 있는 개발자는 2, 3명만 되어도 어떻게든 팀은 돌아갑니다.
그렇다면 렌더러도 아니고 서버도 아닌 5명은 무엇을 할까요?

가장 많은 수를 차지하는 것은 컨텐츠 개발자입니다.
라이브팀에는 90%가 컨텐츠 개발자로 구성된다고 봐도 무방할 정도입니다.

물론 가장 좋은 상황은 이 10명이 전부 렌더러, Win32 애플리케이션, 서버, 미들웨어, DB, 그리고 게임 컨텐츠를 다 할수 있는데,
자기가 하고 싶은 것에 따라 업무를 맡는 것일 겁니다.
그리고 프로그램팀의 리더는 이것들을 전부 경험해본 사람이 단연코 좋습니다.
나는 밑에 애들 잘시키면 되지, 기술적으론 잘몰라도돼~ 라는 개소리를 하시는 "실무 리더"분이 간혹 있는데,
대부분 오래 못가 오리알 신세됩니다.

내가 바라는 개발팀

내가 바라는 개발팀


현실

현실


경고!!
투자가, 사장님을 비롯한 높으신 분들이 혹시 이 글을 봤다면 절대 이 글을 따라 아는 체하며 인력구성을 하지말고
팀장이나 젤 똑똑한 애 요청대로 팀을 짭니다. 안그러다간, 아주 좆돼는 경우가 생깁니다.


2. 게임은 컨텐츠다
네, 따라서 게임 프로젝트는 컨텐츠 프로젝트입니다.
화려한 렌더링과 가공할 성능의 서버 시스템이 있어도 게임이 재미없으면 망합니다.
이 컨텐츠 프로그래밍을 하는데에는 렌더링도 서버도 처음에는 필요없습니다.

게임 개발을 꿈꾸는 분이라면 평소의 모든 현상을 게임 컨텐츠로 옮길수 있는 코딩 능력이 있으면 참 좋습니다.
애시당초 객체지향 프로그래밍이란 현실을 컴퓨터로 옮기는 작업 아니겠습니까?

혼자서, 혹은 아마츄어 팀으로 게임 프로젝트를 시작하며 망하는건, 무리하게 상용게임을 흉내낼려는 것에도 원인이 있습니다.
엄청난 자본과 시간과 인력이 투입된 게임에 비교하면 자신의 것은 초라해지고 의욕마저 상실합니다.

그러나 그래픽과 네트워크를 제외하고 생각해보면 이야기는 달라집니다.

다음은 엔하위키에서 퍼온 스타크래프트2의 한 대목입니다.
(출처 : http://rigvedawiki.net/r1/wiki.php/%EC%8A%A4%ED%83%80%ED%81%AC%EB%9E%98%ED%94%84%ED%8A%B8%202?action=show&redirect=스타크래프트2 )


이 게시물은 오직 게임컨텐츠에 대한 설명입니다.
먼저 글상자 안에 있는 내용은 공격력에 대한 내용인데 필수적으로 공격의 주체와 공격을 받는 객체들의 판정에 대한 이야기입니다.
구조체, 아니 C언어로 사칙연산만 할수 있는 초보자라도 위의 공식을 프로그래밍 언어로 옮길 수가 있을 것입니다.
고스트 객체;
마린 객체;

결과 = 고스트 객체.기본공격(마린);

if(으앙쥬금 == 결과)
{
    delete 마린 객체;
    MessageToAllUser(마린 객체, 쥬금);
}


스타크래프트2는 물론 초당 몇십 프레임이 돌아가고 이동이 자유로운 게임입니다만, 공격이라는 한 순간을 구현하면 위와 같은 루틴으로만 끝내버릴수 있습니다. 이런게 바로 컨텐츠 안에서의 로직 부분에 해당합니다. 좀더 추가해 객체별 상성관계 역시 if 문과 숫자 증감으로 쉽게 구현 가능합니다. 아마 이 글을 읽고 계신 분들 중에 이 정도도 코딩 못하시는 분은 없을 것입니다.

그런데 설명을 읽어보니 컨트롤에 대한 이야기가 나오는군요.
컨트롤이라는 것은 앞서 적은대로 실시간으로 객체들이 계속 돌아가는 게임이기 때문에 생기는 현상입니다.
그래도 별것 없습니다. 객체들이 계속 돌아간다는건, 게임 프로그램이 윈도우 메시지를 처리하지 않는 Idle 타임중에 계속 로직과 화면을 뿌려주는 것에 불과하기 때문이죠. 아, 물론 키보드, 마우스, 네트워크 입력도 같이 받습니다.

while(pGameWnd->OnSystemMessageIdle())
{
    네트워크 수신();
    키보드 입력감지();
    마우스 입력감지();
    ......
    고스트 객체;
    마린 객체;

    결과 = 고스트 객체.기본공격(마린);

 

    if(으앙쥬금 == 결과)
    {

     delete 마린 객체;
     MessageToAllUser(마린 객체, 쥬금);
    }
    ......
    화면갱신();
}

간단하죠?
여기서 더 신경써야할 것은 각 객체들의 생성, 소멸, 함수간 전달 관리이며
입출력을 위한 Win32 애플리케이션, 3D, 네트워크 공부인 것입니다.

여기의 게임을 이루는 객체들의 관리가 결국 게임프로그래밍입니다. 비록 허술하다고 하더라도 이것이 게임 코딩의 본질입니다.
물론 사용자 경험을 만들어주는 렌더러의 중요성은 이 자리에서 언급하기 민망할 정도이지만 렌더러 만으로는 절대 게임이 되지 않습니다.
렌더러도 충돌이 들어가야지 비로소 게임틱해집니다 충돌이 들어갔다는 말도 단순히 렌더 타겟이 아니라 게임 객체가 되었다는 말입니다.


뜬금없는 이상적인 렌더러의 사례

3, 그래서 MUD를 만들어봅시다.
2기에서는 이제는 기억에서 잊어진 게임 쟝르인 MUD(multi user dungeon)를 만들어 볼 것입니다.
(절대 그래픽 코딩하기 귀찮아서가 아님.)
마음은 사실같은 그래픽으로 해드리고 싶네요...... .

마음만은 사실같은 그래픽으로 해드리고 싶네요...... .


사실 MUD에서 사용되는 기술은 현재의 MMORPG와 큰 차이가 없습니다.
단지 실시간 이동과 공격이라는 것을 지원하기 위해 데드리커닝(dead reckoning)이 추가되었을 뿐이며
3D가 추가되며 부분적으로 여기에 3D 연산이 들어갑니다. ...사실 서버에 3D 안써도 클라만 잘하면 깜쪽같이 자~알 됩니다.
사족을 달면 실제 서버 3D나 넌타게팅 같은 것보다 수십, 수백대의 서버 동기화나 빠른 DB처리가 같은 장비 영역와 섞인 부분이 훨씬 더 어렵습니다.

부활 신호탄은 여기까지 적고,
2화 부터 "소드 아트 온라인 MUD"을 구현해보도록 하겠습니다. 역시 개발환경은 C++과 Win32/64입니다.
그리고 다시 연재를 시작하게 되어 무척 기쁩니다.
이제 다른 멤버들에게 도망다니지 않을수 있게 되었어!!! ㅠㅠ

내용은 맘대로 퍼갈수 있지만 동의없는 수정은 안되며 출처(http://www.gamedevforever.com/ , http://rhea.pe.kr/)를 명시해주세요.

PS) 올해 KGC2012에는 나가지 않습니다만, 제 가까이 있는 아주 훌륭한 컨텐츠 개발자 두분이 나가십니다.
      근데 무슨 주제인지는 저두 몰라요...... . -ㅅ-;;


반응형
,