[ACCEPTED]-How do I draw lines using XNA?-shapes

Accepted answer
Score: 19

When working with XNA, everything (even 9 2d primitives) have to be expressed in a 8 way that a 3d card can understand, which 7 means that a line is just a set of vertices.

MSDN 6 has a pretty good walkthrough here:

http://msdn.microsoft.com/en-us/library/bb196414.aspx#ID2EEF

You'll 5 find that it takes more code to render a 4 primitive line than it would take to just 3 setup a textured quad and rotate that, since 2 in essence, your doing the same thing when 1 rendering a line.

Score: 16

Following NoHayProblema's answer (I cannot 11 comment yet).

That answer, although the correct 10 one for this old question, is incomplete. Texture2D 9 constructor returns an uninitialized texture, which 8 is never painted on screen. In order to 7 use that approach, you need to set the texture's 6 data like this:

Texture2D SimpleTexture = new Texture2D(GraphicsDevice, 1, 1, false,
    SurfaceFormat.Color);

Int32[] pixel = {0xFFFFFF}; // White. 0xFF is Red, 0xFF0000 is Blue
SimpleTexture.SetData<Int32> (pixel, 0, SimpleTexture.Width * SimpleTexture.Height);

// Paint a 100x1 line starting at 20, 50
this.spriteBatch.Draw(SimpleTexture, new Rectangle(20, 50, 100, 1), Color.Blue);

Take into account that the 5 way you write the data into pixel must be 4 consistent with the texture's SurfaceFormat. The 3 example works because the texture is being 2 formatted as RGB. Rotations can be applied 1 in spriteBatch.Draw like this:

this.spriteBatch.Draw (SimpleTexture, new Rectangle(0, 0, 100, 1), null,
    Color.Blue, -(float)Math.PI/4, new Vector2 (0f, 0f), SpriteEffects.None, 1f);
Score: 10

found a tutorial for that http://www.bit-101.com/blog/?p=2832

its using a BasicEffect 5 (shader) and the built in draw user primitive 4 in XNA 4.0

some code samples i find helpful:

load 3 content method

basicEffect = new BasicEffect(GraphicsDevice);
basicEffect.VertexColorEnabled = true;
basicEffect.Projection = Matrix.CreateOrthographicOffCenter
(0, GraphicsDevice.Viewport.Width,     // left, right
GraphicsDevice.Viewport.Height, 0,    // bottom, top
0, 1);   

draw method

basicEffect.CurrentTechnique.Passes[0].Apply();
var vertices = new VertexPositionColor[4];
vertices[0].Position = new Vector3(100, 100, 0);
vertices[0].Color = Color.Black;
vertices[1].Position = new Vector3(200, 100, 0);
vertices[1].Color = Color.Red;
vertices[2].Position = new Vector3(200, 200, 0);
vertices[2].Color = Color.Black;
vertices[3].Position = new Vector3(100, 200, 0);
vertices[3].Color = Color.Red;

GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, vertices, 0, 2);

have fun and vote 2 up if this helped you. also pay a visit 1 to the tutorial i got this from.

Score: 8

Well, you can do it in a very simple way 4 without getting into the 3D horrible vector 3 stuff.

Just create a quick texture, for example:

Texture2D SimpleTexture = new Texture2D(GraphicsDevice, 1, 1, false, SurfaceFormat.Color);

And 2 then just draw a line using that texture:

this.spriteBatch.Draw(SimpleTexture, new Rectangle(100, 100, 100, 1), Color.Blue);

I 1 hope this helps

Score: 4

The simplest best way, I think, is to get 3 the image of just a white pixel then stretch 2 that pixel in a rectangle to look like a 1 line

I made a Line class,

class Line
{
    Texture pixel = ((set this to a texture of a white pixel with no border));
    Vector2 p1, p2; //this will be the position in the center of the line
    int length, thickness; //length and thickness of the line, or width and height of rectangle
    Rectangle rect; //where the line will be drawn
    float rotation; // rotation of the line, with axis at the center of the line
    Color color;


    //p1 and p2 are the two end points of the line
    public Line(Vector2 p1, Vector2 p2, int thickness, Color color)
    {
        this.p1 = p1;
        this.p2 = p2;
        this.thickness = thickness;
        this.color = color;
    }

    public void Update(GameTime gameTime)
    {
        length = (int)Vector2.Distance(p1, p2); //gets distance between the points
        rotation = getRotation(p1.X, p1.Y, p2.X, p2.Y); //gets angle between points(method on bottom)
        rect = new Rectangle((int)p1.X, (int)p1.Y, length, thickness)

        //To change the line just change the positions of p1 and p2
    }

    public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
    {
        spriteBatch.Draw(pixel, rect, null, color, rotation, new Vector2.Zero, SpriteEffects.None, 0.0f);
    }

    //this returns the angle between two points in radians 
    private float getRotation(float x, float y, float x2, float y2)
    {
        float adj = x - x2;
        float opp = y - y2;
        float tan = opp / adj;
        float res = MathHelper.ToDegrees((float)Math.Atan2(opp, adj));
        res = (res - 180) % 360;
        if (res < 0) { res += 360; }
        res = MathHelper.ToRadians(res);
        return res;
    }

Hope this helps

Score: 2

There is also the "round line" code 2 that "manders" has released on 1 CodePlex:


Here is the blog post about it:

Score: 2

Just stretch a white pixel.

        point = game.Content.Load<Texture2D>("ui/point");

        public void DrawLine(Vector2 start, Vector2 end, Color color)
        {
            Vector2 edge = end - start;
            float angle = (float)Math.Atan2(edge.Y, edge.X);

            spriteBatch.Begin();
            spriteBatch.Draw(point,
                new Rectangle((int)start.X, (int)start.Y, (int)edge.Length(), 1),
                null, 
                color, 
                angle,
                new Vector2(0, 0),
                SpriteEffects.None,
                0);
            spriteBatch.End();
        }

0

Score: 2

I wanted to draw rays so that I could debug 18 rays created by explosions and where they 17 intersect objects. This will draw a single 16 pixel thin line between two points. This 15 is what I did:

Class to store some simple 14 ray data. The XNA default ray class could 13 work, but it doesn't store the length of 12 the ray to intersection.

public class myRay
{
    public Vector3 position, direction;
    public float length;
}   

A list to store 11 the rays that are to be drawn:

List<myRay> DebugRays= new List<myRay>();

Create a BasicEffect 10 and pass it a "Matrix.CreateOrthographicOffCenter" projection 9 with your desired resolution in the LoadContent 8 method.

Then run this in the draw method:

private void DrawRays()
{
    spriteBatch.Begin();

    foreach (myRay ray in DebugRays)
        {
            //An array of 2 vertices - a start and end position
            VertexPositionColor[] Vertices = new VertexPositionColor[2];
            int[] Indices = new int[2];

            //Starting position of the ray
            Vertices[0] = new VertexPositionColor()
            {
                Color = Color.Orange,
                Position = ray.position
            };

            //End point of the ray
            Vertices[1] = new VertexPositionColor()
            {
                Color = Color.Orange,
                Position = ray.position + (ray.direction * ray.length)
            };

            Indices[0] = 0;
            Indices[1] = 1;

            foreach (EffectPass pass in BasicEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.LineStrip, Vertices, 0, 2, Indices, 0, 1, VertexPositionColorTexture.VertexDeclaration);
            }
        }

    spriteBatch.End();
}

So 7 when an explosion happens in my game it 6 does this (Psuedocode):

OnExplosionHappened()
{
    DebugRays.Clear()

    myRay ray = new myRay()
                    {
                        position = explosion.Position,
                        direction = GetDirection(explosion, solid),
                        //Used GetValueOrDefault here to prevent null value errors
                        length = explosionRay.Intersects(solid.BoundingBox).GetValueOrDefault()
                    };

    DebugRays.Add(ray);
}

It's pretty simple 5 (It possibly looks way more complicated 4 than it is) and it'd be easy to put it into 3 a separate class that you never have to 2 think about again. It also lets you draw 1 a whole lot of lines at once.

Score: 1

I encountered this problem my self and decided 3 to make a class called LineBatch. LineBatch 2 will draw lines without needing a spriteBatch 1 or dots. The class is below.

public class LineBatch
{
    bool cares_about_begin_without_end;
    bool began;
    GraphicsDevice GraphicsDevice;
    List<VertexPositionColor> verticies = new List<VertexPositionColor>();
    BasicEffect effect;
    public LineBatch(GraphicsDevice graphics)
    {
        GraphicsDevice = graphics;
        effect = new BasicEffect(GraphicsDevice);
        Matrix world = Matrix.Identity;
        Matrix view = Matrix.CreateTranslation(-GraphicsDevice.Viewport.Width / 2, -GraphicsDevice.Viewport.Height / 2, 0);
        Matrix projection = Matrix.CreateOrthographic(GraphicsDevice.Viewport.Width, -GraphicsDevice.Viewport.Height, -10, 10);
        effect.World = world;
        effect.View = view;
        effect.VertexColorEnabled = true;
        effect.Projection = projection;
        effect.DiffuseColor = Color.White.ToVector3();
        cares_about_begin_without_end = true;
    }
    public LineBatch(GraphicsDevice graphics, bool cares_about_begin_without_end)
    {
        this.cares_about_begin_without_end = cares_about_begin_without_end;
        GraphicsDevice = graphics;
        effect = new BasicEffect(GraphicsDevice);
        Matrix world = Matrix.Identity;
        Matrix view = Matrix.CreateTranslation(-GraphicsDevice.Viewport.Width / 2, -GraphicsDevice.Viewport.Height / 2, 0);
        Matrix projection = Matrix.CreateOrthographic(GraphicsDevice.Viewport.Width, -GraphicsDevice.Viewport.Height, -10, 10);
        effect.World = world;
        effect.View = view;
        effect.VertexColorEnabled = true;
        effect.Projection = projection;
        effect.DiffuseColor = Color.White.ToVector3();
    }
    public void DrawAngledLineWithRadians(Vector2 start, float length, float radians, Color color)
    {
        Vector2 offset = new Vector2(
            (float)Math.Sin(radians) * length, //x
            -(float)Math.Cos(radians) * length //y
            );
        Draw(start, start + offset, color);
    }
    public void DrawOutLineOfRectangle(Rectangle rectangle, Color color)
    {
        Draw(new Vector2(rectangle.X, rectangle.Y), new Vector2(rectangle.X + rectangle.Width, rectangle.Y), color);
        Draw(new Vector2(rectangle.X, rectangle.Y), new Vector2(rectangle.X, rectangle.Y + rectangle.Height), color);
        Draw(new Vector2(rectangle.X + rectangle.Width, rectangle.Y), new Vector2(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height), color);
        Draw(new Vector2(rectangle.X, rectangle.Y + rectangle.Height), new Vector2(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height), color);
    }
    public void DrawOutLineOfTriangle(Vector2 point_1, Vector2 point_2, Vector2 point_3, Color color)
    {
        Draw(point_1, point_2, color);
        Draw(point_1, point_3, color);
        Draw(point_2, point_3, color);
    }
    float GetRadians(float angleDegrees)
    {
        return angleDegrees * ((float)Math.PI) / 180.0f;
    }
    public void DrawAngledLine(Vector2 start, float length, float angleDegrees, Color color)
    {
        DrawAngledLineWithRadians(start, length, GetRadians(angleDegrees), color);
    }
    public void Draw(Vector2 start, Vector2 end, Color color)
    {
        verticies.Add(new VertexPositionColor(new Vector3(start, 0f), color));
        verticies.Add(new VertexPositionColor(new Vector3(end, 0f), color));
    }
    public void Draw(Vector3 start, Vector3 end, Color color)
    {
        verticies.Add(new VertexPositionColor(start, color));
        verticies.Add(new VertexPositionColor(end, color));
    }
    public void End()
    {
        if (!began)
            if (cares_about_begin_without_end)
                throw new ArgumentException("Please add begin before end!");
            else
                Begin();
        if (verticies.Count > 0)
        {
            VertexBuffer vb = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), verticies.Count, BufferUsage.WriteOnly);
            vb.SetData<VertexPositionColor>(verticies.ToArray());
            GraphicsDevice.SetVertexBuffer(vb);

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                GraphicsDevice.DrawPrimitives(PrimitiveType.LineList, 0, verticies.Count / 2);
            }
        }
        began = false;
    }
    public void Begin()
    {
        if (began)
            if (cares_about_begin_without_end)
                throw new ArgumentException("You forgot end.");
            else
                End();
        verticies.Clear();
            began = true;
    }
}
Score: 0

Here is a simple way that I use to make 5 lines by specifying a start coordinate, an 4 end coordinate, width, and color of them:

NOTE: you 3 must add a file named "dot" to the content 2 directory (the line will be made out of 1 these).

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Xna.LineHelper
{
    public class LineManager
    {
        int loopCounter;
        int lineLegnth;
        Vector2 lineDirection;
        Vector2 _position;
        Color dotColor;
        Rectangle _rectangle;
        List<Texture2D> _dots = new List<Texture2D>();
        FunctionsLibrary functions = new FunctionsLibrary();

        public void CreateLineFiles(Vector2 startPosition, Vector2 endPosition, int width, Color color, ContentManager content)
        {
            dotColor = color;
            _position.X = startPosition.X;
            _position.Y = startPosition.Y;
            lineLegnth = functions.Distance((int)startPosition.X, (int)endPosition.X, (int)startPosition.Y, (int)endPosition.Y);
            lineDirection = new Vector2((endPosition.X - startPosition.X) / lineLegnth, (endPosition.Y - startPosition.Y) / lineLegnth);
            _dots.Clear();
            loopCounter = 0;
            _rectangle = new Rectangle((int)startPosition.X, (int)startPosition.Y, width, width);
            while (loopCounter < lineLegnth)
            {
                Texture2D dot = content.Load<Texture2D>("dot");
                _dots.Add(dot);

                loopCounter += 1;
            }

        }

        public void DrawLoadedLine(SpriteBatch sb)
        {
            foreach (Texture2D dot in _dots)
            {
                _position.X += lineDirection.X;
                _position.Y += lineDirection.Y;
                _rectangle.X = (int)_position.X;
                _rectangle.Y = (int)_position.Y;
                sb.Draw(dot, _rectangle, dotColor);
            }
        }
    }

    public class FunctionsLibrary
    {
        //Random for all methods
        Random Rand = new Random();

        #region math
        public int TriangleArea1(int bottom, int height)
        {
            int answer = (bottom * height / 2);
            return answer;
        }

        public double TriangleArea2(int A, int B, int C)
        {
            int s = ((A + B + C) / 2);
            double answer = (Math.Sqrt(s * (s - A) * (s - B) * (s - C)));
            return answer;
        }
        public int RectangleArea(int side1, int side2)
        {
            int answer = (side1 * side2);
            return answer;
        }
        public int SquareArea(int side)
        {
            int answer = (side * side);
            return answer;
        }
        public double CircleArea(int diameter)
        {
            double answer = (((diameter / 2) * (diameter / 2)) * Math.PI);
            return answer;
        }
        public int Diference(int A, int B)
        {
            int distance = Math.Abs(A - B);
            return distance;
        }
        #endregion

        #region standardFunctions

        public int Distance(int x1, int x2, int y1, int y2)
        {
            return (int)(Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
        }

        #endregion



    }
}

More Related questions