사각형 그리기

약간 믿기 힘들지 모르겠는데

monogame 프레임워크는 OpenGL을

사용하면서도 도형을 그리는 기본

메소드가 없습니다;;;

 

그래픽을 다루는 게임 라이브러리라면

보통은 drawRectangle() 이나 drawLine()

같은 함수가 있는게 당연하다고 생각했는데

monogame에는 왜 없는지 잘 모르겠습니다.

이런 기본은 built-in 되야 하는게 아닌가?

게임 SDK보다 그래픽 기능이 약학

GUI 라이브러리에도 들어가니까요.

(아마 MS가 처음에 설계했기 때문에??)

 

아마 최초 개발할 때 콘텐트 파이프라인의

스프라이트를 잘 활용해라는 취지가 아닌가

쓸데없는 기능들을 있을 필요가 없어서

굳이 구현하지 않은 것일수도 있습니다.

XNA가 monogame으로 바뀌면서

오픈소스가 된 후에도 기본 도형을

그리는 함수는 구현되지 않았는데요.

하긴 딱히 실용적이진 않기 때문에

그럴 수도 있겠다 싶습니다.

약간 monogame이 성숙한 커뮤니티라고

하는데 그렇게 유저 친화적이진 않습니다.

 

 

영어권 2D/3D 인디게임에 포커스를

맞췄기 때문에 정서적으로 한계가 있습니다.

 

이것은 단점일수 있지만 바꿔 생각하면

자유도가 매우 높다고도 말할 수 있습니다.

 

monogame에서 사각형을 그리고 싶으면

Texture2D 객체로 직접 구현해야 합니다.

 

png 이미지 파일을 변환하여 사각형을

구현할 수도 있지만 그렇게 되면

사이즈 조절하는게 더 복잡해지니까

그냥 함수로 만들어 보겠습니다.

 

아래 코드에서 setRectangle 함수에 구현합니다.

사각형을 생성해서 +X축으로 이동하는 코드입니다.

 

함수에 대해서 밑에서 설명하겠습니다.

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using System.Diagnostics;

namespace MonogameTut
{
    public class Game1 : Game
    {
        private GraphicsDeviceManager _graphics;
        private SpriteBatch _spriteBatch;

        Texture2D _texture;
        Vector2 _position;


        // 게임창 크기
        private int WindowWidth = 480;
        private int WindowHeight = 270;

        
        public Game1()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;
        }

        protected override void Initialize()
        {
            MonogameWindowSetup(WindowWidth, WindowHeight);
            _position = new Vector2(0, 135);
            
            base.Initialize();
        }

        protected override void LoadContent()
        {
            _spriteBatch = new SpriteBatch(this.GraphicsDevice);
        }

        protected override void Update(GameTime gameTime)
        {
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            // 수평 이동 반복
            _position.X += 3f;
            if(_position.X > WindowWidth)
            _position.X = 0;

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            this.GraphicsDevice.Clear(Color.CornflowerBlue);

            setRectangle(70, 50, Color.Brown);

            Debug.WriteLine(this.GraphicsDevice.Viewport.Width);
            Debug.WriteLine(_position.X);

            _spriteBatch.Begin();
            _spriteBatch.Draw(_texture, _position, Color.White);
            _spriteBatch.End();

            base.Draw(gameTime);
        }

        private void MonogameWindowSetup(int width, int height)
        {
            // 게임창 크기 설정
            _graphics.PreferredBackBufferWidth = width;
            _graphics.PreferredBackBufferHeight = height;

            Debug.WriteLine("monogame window is created!");
            Debug.WriteLine($"width: {_graphics.PreferredBackBufferWidth}, height: {_graphics.PreferredBackBufferHeight}");

            _graphics.ApplyChanges();
        }

        private void setRectangle(int width, int height, Color color)
        {

            _texture = new Texture2D(this.GraphicsDevice, width, height);

            int rectSize = width * height;

            Color[] colorData = new Color[rectSize];
            for (int i = 0; i < rectSize; i++)
            {
                colorData[i] = color;
            }

            _texture.SetData<Color>(colorData);
        }
    }
}


setRectangle에서는 매개변수로 너비와 높이

그리고 색상을 넣습니다.

Texture2D 객체를 new로 생성합니다.

이미지나 스프라이트를 로드할 때는

Content.Load<> 제너릭을 사용했는데

여기서 Texture2D 객체를 생성합니다.

생성자는 GraphicsDevice, 너비와 높이입니다.

이미지 로드시에는 알아서 너비와 높이가

계산이 되었는데 여기서는 직접 넣습니다.

 

텍스쳐의 크기를 직접 정의할 수 있습니다.

 

다음에 텍스쳐를 만드는 것은 역시

픽셀에 들어가는 배열입니다.

그런데 2D라고 2차원 배열일 것 같은데

그냥 1차원 배열입니다. 배열 데이터를

쭈욱 넣으면 너비에 따라 짤라서

다음 행의 픽셀에 들어가기 때문입니다.

 

Color 정보는 RGBA (알지비 알파) 입니다.

픽셀하나에 RGBA, 픽셀하나에 RGBA 이렇게

채워집니다. 예를들어 width가 50이고

height가 50이다. 그러면 배열의 요소는

2500개 됩니다. 2500개의 RGBA가 사각형에

채워져서 사가형이 나옵니다.

 

        private void setRectangle(int width, int height, Color color)
        {

            _texture = new Texture2D(this.GraphicsDevice, width, height);

            int rectSize = width * height;

            Color[] colorData = new Color[rectSize];
            for (int i = 0; i < rectSize; i++)
            {
                colorData[i] = color;
            }

            _texture.SetData<Color>(colorData);
        }

 

 

도형을 이동시키는 것은 Update에서

Vector2 객체의 포지션을 변경하면 됩니다.

X위치가 화면을 넘어가면 다시 0으로

바꾸고 무한 반복하게 됩니다.

 

            _position.X += 3f;
            if(_position.X > WindowWidth)
            _position.X = 0;

 

monogame 사각형

 

monogame 커뮤니티에서는 기본 도형을

그리는 확장 라이브러리를 직접 만들기도 하는데

그런 부분은 좀 불편한 것 같습니다.

자유도가 가장 큰 장점이지만

시간과 노력도 많이 소요되므로

'don't reinvent the wheel'

(수레바퀴를 다시 발명하지 마라)

라는 프로그래밍 격언에는 맞지 않긴 합니다.

 

이것을 사용하다 보면 유니티가

왜 그렇게 인기가 많은지 알 수 있습니다.

 

어쨋든 사각형을 만들어 보는 정도라면

하겠지만 그 이상의 기본 도형도 막상

그릴려면 복잡하기 때문에 손이 잘 안가긴 합니다.

 

*참고 링크 - monogame 확장 라이브러리 (Shape)

 

Coding Games [#00] - Introduction - YouTube

공유하기

facebook twitter kakaoTalk kakaostory naver band