Difference between revisions of "Drawing Shapes"

From TRCCompSci - AQA Computer Science
Jump to: navigation, search
(PrimitiveBatch)
(PrimitiveBatch)
Line 28: Line 28:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Using a LineList every pair of vectors is a single line. A TriangleList will take every 3 vectors to create a triangle:
+
Using a LineList, every pair of vectors is a single line. A TriangleList will take every 3 vectors to create a triangle:
 
<syntaxhighlight lang=c#>
 
<syntaxhighlight lang=c#>
 
primitiveBatch.Begin(PrimitiveType.TriangleList);
 
primitiveBatch.Begin(PrimitiveType.TriangleList);

Revision as of 16:42, 20 February 2019

Believe it or not, MonoGame doesn't include any methods for drawing shapes. But you can still use one of many techniques to draw shapes:

Primitives

Install a Library - Primitives2d

The correct and most efficient way to draw shapes in monogame is to use draw primitives, this more difficult than using textures below:

https://bitbucket.org/C3/2d-xna-primitives/wiki/Home

PrimitiveBatch

Add the primitivebatch.cs to your project, you can get this from here.

Declare a PrimitiveBatch, ideally after SpriteBatch in your Game1.cs:

PrimitiveBatch primitiveBatch;

In LoadContent add the following to setup PrimitiveBatch:

primitiveBatch = new PrimitiveBatch(graphics.GraphicsDevice);

In the Draw method you can draw a line by doing:

primitiveBatch.Begin(PrimitiveType.LineList);
primitiveBatch.AddVertex(new Vector2(0, 0), Color.White);
primitiveBatch.AddVertex(new Vector2(0,10), Color.White);
primitiveBatch.End();

Using a LineList, every pair of vectors is a single line. A TriangleList will take every 3 vectors to create a triangle:

primitiveBatch.Begin(PrimitiveType.TriangleList);
primitiveBatch.AddVertex(new Vector2(0, 0), Color.White);
primitiveBatch.AddVertex(new Vector2(0,10), Color.White);
primitiveBatch.AddVertex(new Vector2(10,10), Color.White);
primitiveBatch.End();

Using Textures

Much easier than drwaing primitives, we can use a texture to draw each point of the shape, the texture is generated using 1 x 1 pixels:

Filled Rectangle

// Make a 1x1 texture named pixel.  
Texture2D pixel = new Texture2D(graphicsDeviceReferenceHere, 1, 1);  
 
// Create a 1D array of color data to fill the pixel texture with.  
Color[] colorData = {  
                        Color.White,   
                    };  
 
// Set the texture data with our color information.  
pixel.SetData<Color>(colorData);  
 
// Draw a fancy purple rectangle.  
spriteBatch.Draw(pixel, new Rectangle(0, 0, 300, 300), Color.Purple);

Outline Only

// In LoadContent() 
Texture2D pixel = new Texture2D(GraphicsDevice, 1, 1, false, SurfaceFormat.Color); 
pixel.SetData(new[] { Color.White }); // so that we can draw whatever color we want on top of it 

// In Draw() 
spriteBatch.Begin(); 
Rectangle titleSafeRectangle = GraphicsDevice.Viewport.TitleSafeArea; 
DrawBorder(titleSafeRectangle, 5, Color.Red); // can draw any rectangle here 
spriteBatch.End(); 

private void DrawBorder(Rectangle rectangleToDraw, int thicknessOfBorder, Color borderColor) 
{ 
// Draw top line 
spriteBatch.Draw(_pixel, new Rectangle(rectangleToDraw.X, rectangleToDraw.Y, rectangleToDraw.Width, thicknessOfBorder), borderColor); 

// Draw left line 
spriteBatch.Draw(pixel, new Rectangle(rectangleToDraw.X, rectangleToDraw.Y, thicknessOfBorder, rectangleToDraw.Height), borderColor); 

// Draw right line 
spriteBatch.Draw(pixel, new Rectangle((rectangleToDraw.X + rectangleToDraw.Width - thicknessOfBorder), 
rectangleToDraw.Y, 
thicknessOfBorder, 
rectangleToDraw.Height), borderColor);
 
// Draw bottom line 
spriteBatch.Draw(pixel, new Rectangle(rectangleToDraw.X, 
rectangleToDraw.Y + rectangleToDraw.Height - thicknessOfBorder, 
rectangleToDraw.Width, 
thicknessOfBorder), borderColor); 
}

Adding new methods

You need to have a working MonoGame project, so from the project tab choose new class. Give the class a name and copy the code below (remember to keep the same namespace as your project):

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace DrawingShapes
{
    public static class DrawShapes
    {
        private static Texture2D _blankTexture;

        public static void LoadContent(GraphicsDevice graphicsDevice)
        {
            _blankTexture = new Texture2D(graphicsDevice, 1, 1, false, SurfaceFormat.Color);
            _blankTexture.SetData(new[] { Color.White });
        }

        public static void LoadContent(Texture2D blankTexture)
        {
            _blankTexture = blankTexture;
        }

        public static void DrawLineSegment(this SpriteBatch spriteBatch, Vector2 point1, Vector2 point2, Color color, int lineWidth)
        {

            float angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
            float length = Vector2.Distance(point1, point2);

            spriteBatch.Draw(_blankTexture, point1, null, color,
                       angle, Vector2.Zero, new Vector2(length, lineWidth),
                       SpriteEffects.None, 0);
        }

        public static void DrawPolygon(this SpriteBatch spriteBatch, Vector2[] vertex, int count, Color color, int lineWidth)
        {
            if (count > 0)
            {
                for (int i = 0; i < count - 1; i++)
                {
                    DrawLineSegment(spriteBatch, vertex[i], vertex[i + 1], color, lineWidth);
                }
                DrawLineSegment(spriteBatch, vertex[count - 1], vertex[0], color, lineWidth);
            }
        }

        public static void DrawRectangle(this SpriteBatch spriteBatch, Rectangle rectangle, Color color, int lineWidth)
        {
            Vector2[] vertex = new Vector2[4];
            vertex[0] = new Vector2(rectangle.Left, rectangle.Top);
            vertex[1] = new Vector2(rectangle.Right, rectangle.Top);
            vertex[2] = new Vector2(rectangle.Right, rectangle.Bottom);
            vertex[3] = new Vector2(rectangle.Left, rectangle.Bottom);

            DrawPolygon(spriteBatch, vertex, 4, color, lineWidth);
        }

        public static void DrawCircle(this SpriteBatch spritbatch, Vector2 center, float radius, Color color, int lineWidth, int segments = 16)
        {

            Vector2[] vertex = new Vector2[segments];

            double increment = Math.PI * 2.0 / segments;
            double theta = 0.0;

            for (int i = 0; i < segments; i++)
            {
                vertex[i] = center + radius * new Vector2((float)Math.Cos(theta), (float)Math.Sin(theta));
                theta += increment;
            }

            DrawPolygon(spritbatch, vertex, segments, color, lineWidth);
        }
    }
}

Now in your Game1.cs, you need to add the code below into the Initialize method:

DrawShapes.LoadContent(GraphicsDevice);

Now in the Draw method you can use the methods to draw a shape, for example:

spriteBatch.Begin();
spriteBatch.DrawRectangle(new Rectangle(0, 0, 200, 200), Color.White, 5);
spriteBatch.End();

Remember DrawRectangle, DrawPolygon, DrawCircle, and DrawLineSegment methods can be used to draw the appropriate shapes.