블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 


아바타 데모


XBox Live 개정에 자신의 아바타를 만들어서 맵핑 시키는 형태, 아바타 자체가 점수에 따라서 웃기도 하고, 폰의 상태(흔들기)등에 따라서 반응도 하고, 재미있는 개념인듯.

게임 데모


중간중간 보면 알겠지만, 3D 게임 퀄러티가 상당히 훌륭하다는!!


지금까지 대강 윈폰7의 프로그래밍 개념에 대해서 잡아봤고, 오늘은 약간 더 실제 프로그래밍을 하는데 필요한 부분에 대해서 알아봅니다.
스마트폰 애플리케이션을 개발하는데, 가장 많이 사용되고 필수적인 컨트롤은 ListBox 컨트롤입니다. 전화번호 목록, 이메일 목록, 상품 목록등 각종 목록을 표시하는데 필수적으로 사용됩니다. 이번에는 이 ListBox 컨트롤의 사용방법에 대해서 알아보고, 아울러 상당히 중요한 데이터 바인딩 개념에 대해서 소개합니다.

 
오늘 만들어볼 예제 화면입니다. 위의 두개의 텍스트 박스가 있고, 왼쪽에는 이름을 오른쪽에는 이메일을 넣습니다. 그후에 Add 버튼을 누르면 아래 리스트에 추가되고, 아래 리스트에서 아이템을 선택한후에 Remove 버튼을 누르면 삭제되는 아주 간단한 애플리케이션입니다.
데이터 구조는 상당히 간단합니다. Contact이라는 ValueObject가 Name과 Email이라는 속성을 가지고 있고, 이 Contact이라는 ValueObject를 List형태로 저장한 것이 데이터 모델입니다.
Contact Class를 먼저 살펴보면

형태입니다. 간단합니다.
다음으로 UI를 디자인합니다.
TextBox와 Button등을 배열하고, 가장 중요한 ListBox를 추가합니다.

대충 이런식으 코드가 됩니다.
이제 ContactList를 정의할 클래스를 지정하고, ContactList를 List형태로 생성합니다.

List<Contact> contacts = new List<Contact>();

이런 식으로요. 그런데, 이런식으로 코딩을 하고 나중에 수행을 해보면, 아무리 Add나 Remove 버튼을 눌러도 화면에는 새로운 Contact이 추가되거나 삭제되지 않습니다. 왜냐? ListBox UI콘트롤과 이 contacts 변수가 바인딩되서 ListBox는 이 contacts 내부의 내용을 출력하게 되는데, ListBox 컨트롤은 contacts 변수에 값이 추가되는지 안되는지를 모르기 때문입니다. 그래서 contacts 리스트에 데이터가 추가되거나 삭제 되면 이를 ListBox 컨트롤에 알려줘야 하는데, 이렇게 List 형태에서 데이터가 추가되거나 삭제될 때 연결된 UI 컨트롤에 이벤트를 발생해서 전달해주는 클래스로 “ObservableCollection” 가 있습니다.
그래서 contacts를 생성할때는 다음과 같이 해줘야 합니다.

ObservableCollection <Contact> contacts = new ObservableCollection<Contact>();

그리고, Add 버튼이 눌렸을 때 새로운 Contact을 추가하고, Remove를 눌렀을 때 현재 선택된 List 아이템을 삭제하는 코드를 추가합니다. 추가한 MainPage.xaml.cs 내용은 다음과 같습니다.

Add 버튼 클릭에서는 단순히 contacts에 새로운 Contact 객체를 생성해서 Add해주고, Remove는 ListBox :: SelectedIndex라는 메서드를 이용해서 현재 선택되어 있는 아이템 번호를 읽어오고, 그것을 RemoveAt 메서드를 이용해서 지웁니다. 앞에 if문으로 SelectedItem이 null인지 체크하는 것은 예를 들어 현재 3개의 아이템이 있는데, 3번째것을 삭제하고 나면 선택 포커스가 그대로 3번째를 가르킵니다. 3번째를 삭제했는데도 말이지요. 그래서 만약 사용자가 선택을 1,2번째로 바꾸지 않고 그대로 Remove 버튼을 눌러서 삭제하면 Null Pointer Error가 납니다. (3번째 선택에는 아이템이 없기 때문에 삭제할 수 없기 때문에. 말로 설명이 잘 안되는데, 직접 한번 테스트 해보시기를.)
그리고 가장 중요한 것 ListBox UI 컨트롤에 어디서 데이터를 가지고 올지 알려줍니다.

contactListBox.ItemsSource = contacts;

이 말은 ListBox에 데이터를 contacts라는 List형 변수에서 가지고 오라는 이야기입니다. 이것이 데이터 바인딩인데, 이건 조금 있다 설명하기로 하고
자아 끝났습니다. 실행을 하면? 예상과 다른 결과가 나타납니다.


우리가 원하는 것은 contacts 안에 있는 Contact 객체들의 내용 즉 이름과 이메일을 보고 싶은데 생뚱 맞게, ListBoxSample.Contact 들이 목록으로 쭈욱 나옵니다. 그도 그럴것이 ListBox 컨트롤은 Contacts 형태의 리스트만을 가지고 있는 contacts라는 변수만 바인딩을 했을뿐, 실제 Contacts 안의 데이터를 어떻게 나타내야 할지를 모릅니다.
이제 ListBox에게 실제Contacts 객체를 얻어왔을 때 어떻게 데이터를 출력할지를 알려줍니다.MainPage.xml을 다음과 같이 수정합니다.

• 먼저 ListBox에 각각의 아이템을 어떻게 출력하는지를 정의하기 위해서 Template을 정의합니다. ListBox.ItemTemplate이 각각의 아이템을 어떤 형태로 출력할지를 정의하는 겁니다.
• 우리는 데이터를 contacts라는 객체에서 가지고 올것이기 때문에 DataTemplate을 정의하고, 각 하위 엘리먼트에서 contacts의 Item인 Contact 객체의 Attribute (Name,Email)을 각각의 TextBox에 추가하도록 한다.
• ListBox에서 ItemSource를 contacts를 정의했기 때문에, TextBox에서 “{Binding Name}”은 이런식으로 해석된다 DataTemplate에 의해서 contacts의 각각의 아이템이 선택되고 (Contact) 객체, 거기에 {Binding Name}에 의해서 Contact.Name 값이 뽑아지게 된다.
다시 이 개념을 정리해 보면

사실 이 포스트에서의 핵심은 ListBox와 List<> 클래스를 어떻게 바인딩하느냐가 핵심이다. 물론 ListBox 컨트롤 사용법을 알리는것도 목적이 있지만, 이 부분이 상당히 헷갈릴 수 있씁니다., (필자는 여기서 좀 헤맸습니다...) 그래서 다음 포스팅에서는 데이터 바인딩의 개념에 대해서 조금 더 자세하게 설명해보도록 하겠습니다.

참고 : 소스 코드

Learning Kit에 들어가 있는 간단한 게임(갤럭시같은..) 튜토리얼을 따라해보고 리뷰를 올립니다.
먼저 이글을 올리기전에 제 백그라운드에 대해서 소개할 필요가 있는데,
94~97년정도까지 게임 개발을 했습니다. MS-DOS상에서 인라인어셈블리와 C/C++을 이용해서 2D 게임을 만들고, Direct-X 초창기 버전과 Direct 3D등으로 게임을 만들어본 경험이 있습니다.
시절이 10년은 지났으니, 결과적으로 게임 프로그래밍에 대해서 기본 개념은 있지만, 요즘 최신 게임 프로그래밍 기법에 대해서는 정보가 부족한 상황임을 미리 이야기 해둡니다.

사실 윈폰7의 게임 개발 프레임웍쪽에는 아주 기대가 컸습니다. 게임 이라는 컨텐츠가 스마트폰의 킬러앱중의 하나이고, 특히 윈폰7에서 XNA를 기반으로 개발된 게임은 X-BOX에서도 수정없이 포팅되서 돌아갈 수 있기 때문에, 개발자 입장에서는 같은 컨텐츠로 콘솔 게임과 스마트폰 게임 시장 양쪽을 모두 공략할 수 있다는 장점을 가지고 있습니다. 그리고 타 스마트폰 플랫폼과 다르게 전용 게임 플랫폼을 제공한다는 것이 매우 흥미로웠습니다.
일전에 개발자 컨퍼런스에서 윈폰7 XNA를 이용한 3D 게임 개발 데모를 본적이 있었는데, Collision 처리 (충돌처리-두개의 개체가 충돌하였다는 것을 알려주는 처리-예를 들어 총알에 맞았다. 이런거..)가 API하나로 해결되고, 각종 3D 이펙트(먼지가 난다거나, 샤방샤방 별가루가 떨어지는 처리등)이 아주 쉽게 개발되는 것들이 아주 신기했기 때문에, 나름 기대를 하고 튜토리얼에 접했습니다. 사실 제가 게임 개발했을때는 이런건 다 날코딩으로 만들어야 했습니다. 심지어 Direct X 이전에는 애니메이션을 표현하기 위한 스프라이트 처리 엔진 조차 인라인 어셈블리로 다 만들어야 했으니까요.

아래는 예제로 따라서 만든 게임 스냅샷입니다.

따라 해보시면 아시겠지만, 상당히 간단합니다.
2D 게임이라서 그런지, 몬가 대단한것이 있을거라는 기대(?)에 몬가 대단한것은 나오지 않았습니다. (그도 그럴것이 2D 게임에 필요한 프레임웍들이 뻔하니..)

몇가지 특이한것만 집어 보겠습니다.

리소스 로딩
게임에 필요한 음성,캐릭터 이미지,백그라운드 이미지들을 로딩하고 관리해야 합니다. 보통 파일을 열어서 일일이 읽어서 메모리에 적재하고, 필요한 파일들도 배포할때, 묶어서 배포해야 하는데, 이부분이 상당히 편리합니다. 다른 스마트폰 플랫폼에서도 될것 같긴한데... 구닥다리 게임 개발자의 시야에서는 신기하더군요.
필요한 리소스들을 비주얼 스튜디오에서 레퍼런스 부분에 Import만 하면됩니다.
리소스들을 사용할때는

이렇게 Load만 해주면 됩니다.
마치 자바의 리소스 번들과 같은 느낌입니다. 배포할때는 모든 리소스들이 함께 패키징 되니까는 상당히 편리하져.

3 스크린 지원
MS의 전략중에 강력한 전략중 하나가, 3 스크린이라는 전략이 있습니다. TV-PC-모바일을 모두 지원하고, 하나의 플랫폼처럼 지원하겠다는 겁니다. VOD 서비스를 TV-PC-모바일을 통해서 각 장점을 통해서 하겠다 모.. 그런건데..
XNA기반의 게임 역시 이 전략의 연장선산에 있습니다.
위에서도 언급했듯이, XNA기반의 게임은 윈폰뿐만 아니라, X-BOX는 물론이고 PC용 윈도우에서도 작동됩니다.
이를 가능하게 하려면, XNA로 개발한 게임을 해당 타겟 플랫폼에 맞게 빌드하면됩니다.
위에 스크린샷에도 보면 알 수 있듯이 Windows와 X-Box 360용 프로젝트로 만들어서 컴파일이 됩니다.

게임 처리 프레임웍
게임 개발 플랫폼에서 당연한것이겠지만, 게임의 실행 사이클에 맞는 프레임웍을 제공합니다.
게임은 보통 하나의 화면 단위로 진행되고, 하나의 화면은 리소스 로딩후, [ 입력을 받고, 캐릭터의 위치나 충돌 처리등과 같은 계산을 하고, 계산 결과에 따라서 화면과 음성으로 출력] 하는 루프를 반복합니다. 이런 프레임웍들이 내부적으로 다 구현되어 있습니다.
예를 들어 화면 처리 패턴은
class GameplayScreen : GameScreen
이런식으로, 상위 클래스로 지정되어 있구요. :)
스프라이트 처리 패턴을 보면 다음과 같습니다.
SpriteBatch.Draw(tankTexture, player.Position, Color.White);
이런식으로요. 상당히 편리하져.
아직 전체 프레임웍을 다 본게 아니라서 모라 말하기는 어렵지만, 일단 게임 개발의 생산성을 높이고, 게임 개발 패턴을 위한 상당히 성숙된 프레임웍을 갖추고 있습니다.

다음에 시간이 되면 3D 게임쪽을 찾아서 한번 봐야 겠습니다. 3D 게임쪽에서 다른 스마트폰 플랫폼들과 차이가 많이 날것 같네요. 혹시 아이폰이나 안드로이드에서 게임쪽 프로그래밍 하신분 계시면 피드백 환영합니다.


=== 추가 ===

충돌 처리 로직
위에서도 잠깐 언급했었는데, 게임 프로그래밍에서는 충돌 처리 로직이 필요합니다.두개의 객체가 충돌했을때를 감지하는 로직인데, 위의 예제에서는 별도 API를 안쓰고, X,Y 좌표축만으로 해서 몰랐는데, 다른 예제를 보니까는 충돌 처리 API가 있네요.

        void CheckForCollision()
        {
            BoundingBox bb1 = new BoundingBox(new Vector3(spritePosition1.X - (sprite1Width / 2), spritePosition1.Y - (sprite1Height / 2), 0), new Vector3(spritePosition1.X + (sprite1Width / 2), spritePosition1.Y + (sprite1Height / 2), 0));
            BoundingBox bb2 = new BoundingBox(new Vector3(spritePosition2.X - (sprite2Width / 2), spritePosition2.Y - (sprite2Height / 2), 0), new Vector3(spritePosition2.X + (sprite2Width / 2), spritePosition2.Y + (sprite2Height / 2), 0));
            if (bb1.Intersects(bb2))
            {
                soundEffect.Play();
            }
        }

BoundingBox라는 사각형 공간을 정의하고 두 공간간에 충돌을 intersects라는 함수로 비교합니다.
잘 보시면 아시겠지만, BoundingBox를 정의하는것을 두개의 벡터로 정의합니다. 각각의 벡터는 3개의 좌표를 가지고 있습니다. X,Y,Z축 입니다. 즉!! 3D에서 충돌처리를 지원하기 위한 함수라는 것입니다. 위의 예제는 2D의 예제라서 Z축을 0으로 했네요.