스프라이트(Sprite) 클래스를 만드는
이유는 OOP 방식으로 프로그램을
만들기 위해서 입니다.
monogame 의 DesktopGL 템플릿의
기본 와꾸 코드는 Game1.cs 에 만들어지는데
이 한개의 파일에 모든 코드를 집어넣을 수
있겠지만 코드가 늘어날 수록 라인수도
늘어나고 관리가 어려워 집니다.
해서 전체에서 부분을 나누게 되는데
C#은 객체지향 프로그래밍 언어이므로
객체 단위로 쪼갤 수 있습니다.
가장 기본은 2D의 캐릭터를 구성하는
텍스처2D 스프라이트를 객체화 하는 것 입니다.
쉽게 말해 2D Player 캐릭터나 Mob 캐릭터의
기본 클래스를 만드는 것이라 보면 됩니다.
(자바에서는 부모 클래스라고 하는 것)
이렇게 하면 Game1.cs 소스코드를
좀더 체계적으로 정리, 작성할 수 있습니다.
지난 튜토리얼에서 사용한 MyMonogame
네임스페이스를 사용합니다.
새로운 파일 이름을 Sprite.cs 로 Game1.cs 와
같은 폴더에 만들어서 아래처럼 코딩합니다.
Sprite 코드를 만드는데 딱히
정답이란 것은 없다고 보는데
기본 와꾸를 짜두는 겁니다.
파생 클래스에서 여러가지 기능을
추가할 거니까 너무 모든 내용을
넣을 필요는 없습니다.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace MyMonogame
{
class Sprite
{
private Texture2D _texture;
public Vector2 Position;
public float Speed = 2f;
public Sprite(Texture2D texture)
{
this._texture = texture;
}
public void Update()
{
if(Keyboard.GetState().IsKeyDown(Keys.A))
{
Position.X -= Speed;
}
if(Keyboard.GetState().IsKeyDown(Keys.D))
{
Position.X += Speed;
}
if(Keyboard.GetState().IsKeyDown(Keys.W))
{
Position.Y -= Speed;
}
if(Keyboard.GetState().IsKeyDown(Keys.S))
{
Position.Y += Speed;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(this._texture, Position, Color.White);
}
}
}
이렇게 보면 명확히 알 수 있는게
스프라이트 객체의 필드와 생성자,
Draw와 Update에서 하는 일이 무엇인지
이해하기가 쉽습니다. Game1 클래스는
게임 전체에서 클래스 생성자와
Draw, Update 메소드라면 Sprite 객체는
그 객체의 부분에서 일어나는 일들임을
알 수 있습니다. 게임이 복잡해질 수록
그에 따라 여러개의 객체를 만들 수 있겠지요.
다음은 Game1.cs의 코드입니다.
필드인 Sprite 객체 두개를 추적해보면
LoadContent와 Update, Draw 메소드에서
사용되고 있습니다. 처음에 콘텐트를 로드하고
그 다음은 Update와 Draw의 번갈아
무한루프인데 Sprite 의 메소드에서도
Update와 Draw를 반복합니다.
기존 코드에 비해 정리가 된 느낌입니다.
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;
// 스프라이트 객체 2개
private Sprite _sprite;
private Sprite _spriteOther;
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void Initialize()
{
SetupWindows();
base.Initialize();
}
private void SetupWindows()
{
// 화면 해상도 초기화
_graphics.PreferredBackBufferWidth = 600;
_graphics.PreferredBackBufferHeight = 400;
_graphics.ApplyChanges();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
// first texture
Texture2D texture = Content.Load<Texture2D>("st1");
_sprite = new Sprite(texture);
_sprite.Position = new Vector2(0, 0);
_sprite.Speed = 2.5f;
// second texture
Texture2D textureOther = Content.Load<Texture2D>("st2");
_spriteOther = new Sprite(textureOther);
_spriteOther.Position = new Vector2(100, 0);
_spriteOther.Speed = 5f;
}
protected override void Update(GameTime gameTime)
{
_sprite.Update();
_spriteOther.Update();
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Chocolate);
// 스프라이트를 추가합니다.
_spriteBatch.Begin();
_sprite.Draw(_spriteBatch);
_spriteOther.Draw(_spriteBatch);
_spriteBatch.End();
base.Draw(gameTime);
}
}
}
막 긴 코드가 나와있는 것 같은데
monogame 튜토리얼을 1부터 읽고
실습해보면 어려운 내용은 아닙니다.
시리즈 포스팅에서 종종 강조하는데
프레임워크는 사용방식이 정해져 있어서
전부분에서 사용법을 놓치면 뒤로갈 수록
계속 헷갈리는 것들이 많아서 차근차근
코드의 기초를 쌓아서 올라가는게 좋습니다.
기초라는게 별거 아니고 그냥 같은 예제를
가지고 이것저것 변형해보면서 실행과
피드백을 반복하는 것 정도 입니다.
어느정도 코드에 익숙해지기 전에는
최대한 많은 코드를 직접 쳐보고,
복붙도 해보고 변경해 보는게 좋습니다.
막상 해보면 소스코드만 잘 쓴다고
되는게 아니라 IDE 툴이나 운영체제의
유틸리티 같은 것 등 알아야할 것이 많습니다.
게임은 Game Asset(스프라이트, 오디오파일 등
게임의 리소스) 관리하는데도 시간이 많이 걸립니다.
프로그래머가 그래픽 디자이너는 아니지만
그래픽 구현에 대한 지식이 필요한 것도 사실입니다.
...잡설은 이 정도로 하고 이렇게
Sprite 클래스를 마무리하겠습니다.