Your First Game: Microsoft XNA Game Studio Express in 2D XNA 튜토리얼
2006/12/26 00:59 |
이번 튜토리얼은 2D 이미지를 스크린에 그리고 움직이는 것으로 XNA를 Install 하면 볼 수 있는 'XNA Game Studio Express Documentation'의 내용을 참고로 제작한 것이다.
1. 프로그램을 제작하기 전에 필요한 프로그램을 Install 했는지 확인!!(XNA Express v1.0 정식 버전과 Visual C# 2005 Express)
2. 새 프로젝트 만들기
<XNA 실행>
정상적으로 Install 했다면 시작 프로그램에서 확인할 수 있다.
시작->프로그램->Microsoft XNA Game Studio Express->XNA Game Studio Express를 클릭하여 XNA 프로그램을 시작한다.
<XNA 실행 화면>
XNA를 실행하면 위와 같은 시작 화면이 나타난다. 새로운 프로젝트를 만들기 위해 File->New Project를 클릭하거나 단축키 'Ctrl+Shitf+N'을 클릭한다.
<New Project>
만들 수 있는 프로젝트 스타일이 여러개 보인다. 윈도우 버젼의 게임을 만들것이므로 Window Game을 선택, Name란에는 MyFirstXNAGame이란 제목을 넣어주고 OK를 클릭한다.
<프로젝트 실행 화면>
새 프로젝트를 만들어 실행한 화면이다. 프로그래머가 아닌 사람들에게는 난해하게 보일 수 도 있겠지만 실제 코드는 몇 줄 안되고 설명(주석)들이 주로 이루고 있다. 우측창(Solution Explorer)에 보이는 Game1.cs라는 파일의 내용들이다.(어려울 거 없다. 그냥 텍스트 파일이다.)
3. 코드 보기
게임 프로그램은 일반적으로 다음의 다섯가지 단계에 따라 순차적으로 진행이 된다. ( Game1.cs 파일의 내용들이 바로 이러한 내용들을 적어 놓은 것이다. )
Initialize --> 초기화 단계, 게임의 로직과 관련된 수치들을 초기화 값으로 채워 넣는다. (캐릭터 정보 값과 같은 것들로 그래픽 리소스와는 별개이다.)
LoadGraphicsContent --> 그래픽 리소스들을 읽어 들인다. 캐릭터 이미지 같은 것들을 읽어 들인다.
위의 두 단계를 거쳐 다음 두 단계에서는 루프를 돌며 게임이 끝날때까지 Update와 Draw를 반복한다.(우리가 흔히 게임 프레임이 60프레임이라고 하는 것도 이 루프가 1초에 60번 돈다고 생각하면 쉽게 이해가 갈 것이다.)
Update --> 키보드/마우스 등의 입력을 받고 게임 내 모든 오브젝트들의 상태를 업데이트한다. 예를 들어 주인공 캐릭터를 동쪽으로 1초 동안 2타일 만큼 움직이고 쉽다면 매 프레임마다 이 곳에서 입력을 받아 캐릭터 좌표의 상태값을 변경시켜 주는 것이다.
Draw --> Update 뒤에는 항상 그려주기(Draw)가 따라 온다. Update가 컴퓨터 내부적으로 계산되는 보이지 않는 단계라면 우리는 Draw라는 단계를 거쳐서 원하는 데로 캐릭터가 이동하는 지를 확인할 수 있다.
UnloadGraphicsContent --> 유저가 더 이상 게임을 하고 싶지 않아 게임을 종료하고 타이틀 화면으로 나가거나 윈도우 화면으로 나간다면 그 때까지 메모리에 담고 있던 이미지나 사운드 파일들을 해제해 줘야 한다.(그렇지 않다면 RAM이 가득 차서 문제가 생길테니까)
게임 기획자로서 이정도만 이해하고 있어도 여러모로 도움이 될 듯 싶어 조금 설명을 길게 했다. 게임 프로그래머라면 너무나 뻔할 것이다.^^ 게다가 Direct X까지 다루었다면 너무나 익숙한 내용들일테니...
먼저 아무런 코드의 추가없이 실행해보자.
메뉴의 build -> build solution을 클릭(F6)해 빌드한 뒤, debug -> start debugging을 클릭(F5) 해 실행한다.
<실행 화면>
아무 것도 그려지는 것 없이 파란색을 배경으로 한 창만 덩그러니 떠 있다. 이제부터 여기다 스프라이트를 그려 볼 것이다.
4. 스트라이트 더하기
우측의 Solution Explorer 창에 마우스 오른쪽을 클릭해 Add -> existing item을 클릭한다.
<스프라이트 더하기-1>
파일 열기 창이 나타나면 자신이 추가하고자 하는 이미지(jpg, bmp 등)를 선택한다. 여기서는 smile.jpg를 선택했다.
Texture2D myTexture;
// 스프라이트를 그릴 스크린 상의 좌표이다. vector2.zero를 통해 스크린 상의 (0, 0)부터 이미지를
Vector2 spritePosition = Vector2.Zero;
// 사용할 스프라이트 오브젝트를 선언한다.
// 그려질 이미지를 로드한다. 위에서 추가한 'smile.jpg'를 로드하는 것이다.
protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
myTexture = content.Load<Texture2D>("smile");
}
}
{
// 배경색을 CornflowerBlue로 채워준다.
// Begin은 그리기의 시작을 알리고 End는 그리기의 끝을 알린다.
spriteBatch.Draw(myTexture, spritePosition, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
<실행화면>
아까와는 다르게 스마일 이미지가 스크린 좌표 (0, 0) 부터 그려져 있다.(아무 움직임은 없다.)
5. 스트라이트 움직이기
이제 상태값을 변화시켜 주는 코드를 추가해 보자. 이 루틴을 통해서 정지해 있던 이미지가 45도 방향으로 움직이며 벽에 닿으면 튕겨나가는 것을 확인할 수 있을 것이다.
// Vector2를 이용해 sprite의 이동속도 값을 담을 구조체를 선언한다.
Vector2 spriteSpeed = new Vector2(50.0f, 50.0f);
// Draw 루틴과 함께 가장 중요한 게임 내 오브젝트들의 상태값을 변경시켜 주는 루틴이다.
protected override void Update(GameTime gameTime)
{
// 게임 플레이 중에 나가는(exit) 것과 관련된 루틴이다. 아직은 중요치 않으니 그냥 넘어가자.
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// UpdateSprite라는 함수 루틴을 호출한다.
UpdateSprite(gameTime);
base.Update(gameTime);
}
void UpdateSprite(GameTime gameTime)
{
// elapsed time을 기준으로 매 프레임마다 스프라이트의 포지션에 값을 더해준다.
// elapsed time이란 프레임에서 다음 프레임까지의 시간을 나타낸다. 이 시간은 Update와
// Draw 루틴의 계산 양이나 PC의 사양에 따라 서로 다른 값을 갖는다.
spritePosition += spriteSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
// 스프라이트 이미지가 화면상에서 움직일 수 있는 최대치의 값과 최소값을 얻어낸다.
// Viewport란 스크린 크기를 말한다.
int MaxX = graphics.GraphicsDevice.Viewport.Width - myTexture.Width;
int MinX = 0;
int MaxY = graphics.GraphicsDevice.Viewport.Height - myTexture.Height;
int MinY = 0;
// 이미지가 이동을 하다 최대값이나 최소값에 도달하면 방향과 각도를 바꿔서 이동하게 한다.
if (spritePosition.X > MaxX)
{
spriteSpeed.X *= -1;
spritePosition.X = MaxX;
}
else if (spritePosition.X < MinX)
{
spriteSpeed.X *= -1;
spritePosition.X = MinX;
}
if (spritePosition.Y > MaxY)
{
spriteSpeed.Y *= -1;
spritePosition.Y = MaxY;
}
else if (spritePosition.Y < MinY)
{
spriteSpeed.Y *= -1;
spritePosition.Y = MinY;
}