7

How do you draw shapes, such as Rectangles and Circles, in MonoGame without having to save the a predrawn shape in the Content folder?

DrawRectangle() and DrawEllipse() are for Windows Form and do not work in OpenGL, which is what I am using.

Evorlor
  • 7,263
  • 17
  • 70
  • 141

3 Answers3

12

Use 3D primitives and a 2D projection

Here's a simple example with explanations

I define a 10x10 rectangle and set the world matrix to make it look like a 2D projection :

Note : the BasicEffect is what draws your primitive

protected override void LoadContent()
{
    _vertexPositionColors = new[]
    {
        new VertexPositionColor(new Vector3(0, 0, 1), Color.White),
        new VertexPositionColor(new Vector3(10, 0, 1), Color.White),
        new VertexPositionColor(new Vector3(10, 10, 1), Color.White),
        new VertexPositionColor(new Vector3(0, 10, 1), Color.White)
    };
    _basicEffect = new BasicEffect(GraphicsDevice);
    _basicEffect.World = Matrix.CreateOrthographicOffCenter(
        0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1);
}

Then I draw the whole thing :D

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

    EffectTechnique effectTechnique = _basicEffect.Techniques[0];
    EffectPassCollection effectPassCollection = effectTechnique.Passes;
    foreach (EffectPass pass in effectPassCollection)
    {
        pass.Apply();
        GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineStrip, _vertexPositionColors, 0, 4);
    }
    base.Draw(gameTime);
}

There you have your rectangle !

enter image description here

Now this is just the tip the of the iceberg,

Or as mentioned in one of the posts above you could use a shader that does it instead ...

I needed to draw a Superellipse a while ago and ended up sketching this shader :

Drawing a SuperEllipse in HLSL

As you can see in the post a Superellipse not only draws ellipse but also other shapes and maybe even circles (I did not test) so you might be interested in it.

Ultimately you will want some class/methods to hide all these details so you just have to invoke something like DrawCircle().

Tip : by posting @ https://gamedev.stackexchange.com/ you will likely get more answers for Monogame-related questions

:D

aybe
  • 15,516
  • 9
  • 57
  • 105
  • Shouldn't the vertex array contain 5 vertexes in order to draw 4 primitive lines? – Rudey Jun 03 '16 at 18:37
  • No because it is a line strip :D – aybe Jun 03 '16 at 22:20
  • From MSDN: `The data is ordered as a sequence of line segments; each line segment is described by one new vertex and the last vertex from the previous line seqment. The count may be any positive integer.`. Vertex 1 and 2 make a line segment, vertex 2 and 3, vertex 3 and 4... Won't the 4th line segment need a 5th vertex to connect with vertex 4? – Rudey Jun 04 '16 at 13:00
  • I agree that is kind of confusing but it does work ... count the number of strips: there are 4 of them. As we've passed `4` the method knows to *loop* against the array for drawing the last strip, using last and first vertex. – aybe Jun 04 '16 at 17:09
  • There is some library that will do all this stuff for me? I am doing math visualisation using monogame(cuz love c# and don't know py) and honestly don't want to learn hlsl at all. – Kemsikov Jan 09 '22 at 18:26
  • @Kemsikov you could try Unity, totally different approach. – aybe Jan 10 '22 at 20:12
11

If you need to create a rectangle in 2D you can just do this:

 Color[] data = new Color[rectangle.Width * rectangle.Height];
 Texture2D rectTexture = new Texture2D(GraphicsDevice, rectangle.Width, rectangle.Height);

 for (int i = 0; i < data.Length; ++i) 
      data[i] = Color.White;

 rectTexture.SetData(data);
 var position = new Vector2(rectangle.Left, rectangle.Top);

 spriteBatch.Draw(rectTexture, position, Color.White);

Might be a tad bit easier than Aybe's answer in some situations. This creates a solid rectangle.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
Zillo
  • 321
  • 2
  • 8
  • 1
    You can draw (out)lines with this method, too. Just stretch and rotate the rectangle to draw "lines". – Rudey Sep 12 '16 at 13:19
3

I found a simple solution for drawing filled and non-filled shapes, I don't know if it's power consuming or not, but here it is anyway:

    {
        //Filled
        Texture2D _texture;

        _texture = new Texture2D(graphicsDevice, 1, 1);
        _texture.SetData(new Color[] { Color.White });

        spriteBatch.Draw(_texture, Rect, Color.White);
    }


    {
        //Non filled
        Texture2D _texture;

        _texture = new Texture2D(graphicsDevice, 1, 1);
        _texture.SetData(new Color[] { Color.White });

        spriteBatch.Draw(_texture, new Rectangle(Rect.Left, Rect.Top, Rect.Width, 1), Color.White);
        spriteBatch.Draw(_texture, new Rectangle(Rect.Right, Rect.Top, 1, Rect.Height), Color.White);
        spriteBatch.Draw(_texture, new Rectangle(Rect.Left, Rect.Bottom, Rect.Width, 1), Color.White);
        spriteBatch.Draw(_texture, new Rectangle(Rect.Left, Rect.Top, 1, Rect.Height), Color.White);
    }