세번째 튜토리얼은 스프라이트 조작하기 입니다.
이 프레임워크는 단계를 차례로 진행해야
실행이 되는데요. 이전 튜토리얼에서 png 파일을
콘텐트 파이프라인(mgcb editor)에 추가하여
rebuild 하여 로드하는 것 까지 했습니다.
이미지 로드하기 (Draw Sprite) - monogame 튜토리얼 2
지금 하려는 것은 2D 그래픽입니다. monogame은
이미지 파일을 가져와서 Texture2D 객체로 만듭니다.
너무 어렵게 생각할 필요 없이 Texture2D 객체가
png 파일이라고 보면 됩니다. 단지 프로그램에서는
png 파일을 가져와서 Texture2D라는 타입에
로드하려면 복잡한 내부 과정이 필요한데
mgcb editor 도구를 사용하여 그 과정이
처리된다고 보면 됩니다.
Texture2D _texture = Content.Load<Texture2D>("파일이름");
- 이것은 Generic 클래스를 로드하는데
게임의 콘텐트에는 2D 텍스쳐 말고도
배경음, 사운드 이펙트, 3D 모델 등 여러가지
형태가 있습니다. 당연히 클래스 타입과
콘텐트(png 파일)가 일치 되야 합니다.
2D 게임에서 이미지가 이동하는 원리는
스프라이트의 위치(좌표, position)를
이동시키는 것 입니다.
'monogame 시작하기' 에서 설명했는데
게임루프(gameloop)는 게임이 초기화
되고 난 후 draw 와 update 가 반복됩니다.
반복되는 횟수는 game clock tick 이라는
gametime 을 단위로 하는데 monogame에서는
기본 FPS를 60 으로 합니다.
쉽게 말하면 draw와 update가 1초에 60회
실행됩니다. update 에서 스프라이트의
좌표를 이동시키면 스프라이트도 움직입니다.
스프라이트의 Draw 메소드의 매개변수로
x와 y 좌표를 가진 2D 벡터를 사용하는 이유를 알 수 있지요.
그럼 전체 소스코드를 보겠습니다. 하다보면
monogame 프레임워크의 와꾸(skeleton code)
에 점점 익숙해질 것 입니다.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace MyMonogame
{
public class Game1 : Game
{
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
// 텍스처와 벡터 좌표 객체 변수
private Texture2D _texture;
// private Texture2D _stickman;
private Vector2 _position;
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void Initialize()
{
base.Initialize();
SetupWindows();
}
private void SetupWindows()
{
// 화면 해상도 초기화
_graphics.PreferredBackBufferWidth = 600;
_graphics.PreferredBackBufferHeight = 400;
_graphics.ApplyChanges();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
// 콘텐츠 빌드에서 텍스처를 로드
_texture = Content.Load<Texture2D>("st1");
_position = new Vector2(0,0);
}
protected override void Update(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.Up))
{
// up
_position.Y -= 2;
}
if (Keyboard.GetState().IsKeyDown(Keys.Down))
{
// down
_position.Y += 2;
}
if (Keyboard.GetState().IsKeyDown(Keys.Left))
{
// left
_position.X -= 2;
}
if (Keyboard.GetState().IsKeyDown(Keys.Right))
{
// right
_position.X += 2;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// 스프라이트를 추가합니다.
_spriteBatch.Begin();
_spriteBatch.Draw(_texture, _position, Color.White);
_spriteBatch.End();
base.Draw(gameTime);
}
}
}
지난번 이미지 로드 때는 draw 메소드에
SpriteBatch 객체를 draw 했습니다.
이번에는 update 에서 벡터 좌표를
키입력에 따라 바꿔줍니다.
Keyboard.GetState().IsKeyDown(Keys.키값)
에서 키보드 값에 따라 상하좌우로
포지션을 움직여줍니다.
스크린에서의 포지션은 monogame 창을
기준으로 좌측 상단이 0,0으로 시작하여
우로가면 x 가 증가하고 아래로 가면
y가 증가합니다. 그러니까 좌상에서
우하로 내려오는 방식이지요.
우리가 학교에서 배운 수학과는 좌표체계가
좀 다릅니다. 그런데 monogame 뿐만 아니라
웬만한 그래픽 라이브러리에서는 이렇게
약속되어 있으므로 익숙해질 필요가 있습니다.
그림으로 보면 아래와 같습니다.
_position.X 벡터의 x값
_position.Y 벡터의 y값
으로 float 형입니다.
요즘 일반적인 모니터 해상도가
풀스크린으로 1920x1080 이니까
update마다 1씩 좌표를 이동하면
1초에 60 픽셀 이동할 것이고
이는 (0,0)에서 (1920,0) 까지 32초
(0,0)에서 (0,1080)까지 18초 걸리는
사이즈로 게임을 설계할 때 참고합니다.
위의 예제에서는 2씩 이동시켰는데
1씩 이동시키는 것 보다 덜 지루합니다.
2D 스프라이트에서는 이 좌표의 이동량이
속도(speed)와 같은 의미입니다.
if 조건문은 키보드 입력 이벤트를 확인한 후
분기하는 형태이지만 update 메소드에
그냥 _position.X += 2 라고 하면
키입력 없이도 스프라이트가 오른쪽으로
이동합니다. 몇개의 조건문을 넣으면
무한 반복하는 애니메이션을 만들 수도 있지요.
2D 벡터 포지션의 개념은 스프라이트의 이동 뿐
아니라 리사이즈(resize), 충돌감지(collision) 등에
기본이 되기 때문에 사용법을 숙지하도록 합니다.
다른 앱들도 마찬가지지만 게임 프로그래밍은
기초가 없으면 다음 단계로 잘 진행이 안됩니다.
이해가 안되면 구글 검색해보고 그래도 모르면
다시 돌아가서 확인하는 실습을 반복해야 합니다.
그래서 monogame 포스팅 시리즈는 가급적
순서적으로 맞게 작성하고 있습니다.
내용도 중요하지만 순서도 동일하게 중요합니다.
앱을 실행하면 스프라이트 텍스쳐가
방향키에 따라 이동하는 것을 볼 수 있습니다.
*도움되는 연습
_position의 X와 Y 필드를 변경하여 속도를 바꿔보고,
Keys.키값도 변경해봅니다. 요즘에는 WSAD 를
상하좌우로 사용하니까 화살표 키를 바꿔봅니다.
Update 메소드에서 저절로 이동하도록 바꿔봅니다.