it-swarm.com.de

Wie zeichne ich Linien mit XNA?

Ich habe eine Reihe von Tutorials mit XNA (und verschiedenen Versionen) gelesen und bin immer noch etwas verwirrt beim Zeichnen von Primitiven. Alles scheint wirklich kompliziert zu sein.

Kann mir jemand die einfachste XNA-Implementierung zeigen, indem ich mit Code eine oder zwei Zeilen auf den Bildschirm zeichnet? Vielleicht mit einer kurzen Erklärung (einschließlich der Heizplatte)?

Ich bin kein Spieleprogrammierer und habe wenig Erfahrung mit XNA. Mein ultimatives Ziel ist es, ein paar Linien auf den Bildschirm zu zeichnen, die ich schließlich durch Rotationen usw. (von Hand) verwandeln werde. Für diesen ersten Schritt muss ich jedoch einfach die Linien zeichnen! Ich erinnere mich noch an meine alten OpenGL-Tage, dass es ziemlich einfach war, mit ein paar Methodenaufrufen eine Linie zu zeichnen. Sollte ich einfach nicht verwaltete Directx-Anrufe verwenden?

44
mmcdole

Wenn Sie mit XNA arbeiten, muss alles (auch 2d-Primitive) so ausgedrückt werden, dass eine 3D-Karte sie verstehen kann. Dies bedeutet, dass eine Linie nur eine Menge von Scheitelpunkten ist.

MSDN hat hier eine ziemlich gute Lösung:

http://msdn.Microsoft.com/de-de/library/bb196414.aspx#ID2EEF

Sie werden feststellen, dass zum Rendern einer primitiven Linie mehr Code erforderlich ist als zum Erstellen eines strukturierten Quads und zum Drehen dieses, da Sie im Grunde dasselbe tun, wenn Sie eine Linie rendern.

19
FlySwat

Der Antwort von NoHayProblema folgend (kann ich noch nicht kommentieren).

Diese Antwort ist zwar die richtige für diese alte Frage, aber unvollständig. Der Texture2D-Konstruktor gibt eine nicht initialisierte Textur zurück, die niemals auf dem Bildschirm dargestellt wird .. Um diese Methode verwenden zu können, müssen Sie die Texturdaten wie folgt einstellen:

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);

Beachten Sie, dass die Schreibweise der Daten in Pixel mit dem SurfaceFormat der Textur übereinstimmen muss. Das Beispiel funktioniert, weil die Textur als RGB ..__ formatiert wird. Rotationen können in spriteBatch.Draw folgendermaßen angewendet werden:

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

ein Tutorial dafür gefunden http://www.bit-101.com/blog/?p=2832

es verwendet einen BasicEffect (Shader) und das eingebaute Draw-Benutzerelement in XNA 4.0

einige Codebeispiele finde ich hilfreich:

methode zum Laden von Inhalten

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);   

methode zeichnen

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);

viel Spaß und stimme ab, wenn dir das geholfen hat. Besuchen Sie auch das Tutorial, von dem ich das bekommen habe.

7
ColacX

Nun, Sie können dies auf sehr einfache Weise tun, ohne sich mit den schrecklichen 3D-Vektoren zu befassen.

Erstellen Sie einfach eine schnelle Textur, zum Beispiel:

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

Und dann zeichne einfach eine Linie mit dieser Textur:

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

Ich hoffe das hilft

7
No hay Problema

Ich denke, der einfachste Weg ist, das Bild eines weißen Pixels zu erhalten und dann dieses Pixel in einem Rechteck zu strecken, um wie eine Linie auszusehen

Ich habe eine Line-Klasse gemacht, 

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;
    }

Hoffe das hilft

4
Viviano Cantu

Es gibt auch den Code "Round Line", den "manders" auf CodePlex veröffentlicht hat:


Hier ist der Blogpost darüber:

2
Luke Quinane

Ich wollte Strahlen zeichnen, um von Explosionen erzeugte Strahlen zu debuggen, und wo sie Objekte schneiden. Dadurch wird eine dünne Linie mit einem einzelnen Pixel zwischen zwei Punkten gezeichnet. Das habe ich gemacht:

Klasse zum Speichern einiger einfacher Strahlendaten. Die XNA-Standard-Ray-Klasse könnte funktionieren, speichert jedoch nicht die Länge des Strahls als Schnittpunkt.

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

Eine Liste zum Speichern der Strahlen, die gezeichnet werden sollen:

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

Erstellen Sie einen BasicEffect und übergeben Sie eine "Matrix.CreateOrthographicOffCenter" -Projektion mit der gewünschten Auflösung in der LoadContent-Methode. 

Dann führe das in der draw Methode aus

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();
}

Wenn also eine Explosion in meinem Spiel passiert, geschieht dies (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);
}

Es ist ziemlich einfach (es sieht möglicherweise komplizierter aus, als es ist) und es wäre leicht, es in eine separate Klasse zu stecken, über die Sie nie wieder nachdenken müssen. Sie können auch eine ganze Reihe von Linien gleichzeitig zeichnen.

2
NuBc4k3

Ich bin auf dieses Problem selbst gestoßen und habe mich dafür entschieden, eine Klasse namens LineBatch zu erstellen. LineBatch zeichnet Linien, ohne dass SpriteBatch oder Punkte benötigt werden. Die Klasse ist unten.

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;
    }
}
0
trinalbadger587

Hier ist eine einfache Methode, die ich zum Erstellen von Linien verwende, indem ich eine Startkoordinate, eine Endkoordinate, eine Breite und eine Farbe davon definiere:

HINWEIS: Sie müssen dem Inhaltsverzeichnis eine Datei mit dem Namen "dot" hinzufügen (die Zeile wird aus diesen Zeilen gebildet).

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 RollDice(int sides)
        {

            int result = (Rand.Next(1, sides + 1));
            return result;
        }
        public void ConsoleWelcomeMessage(string gameName, string playerName = "\b")
        {
            Console.WriteLine("Welcome " + playerName + " to " + gameName + "!");

        }
        public string ConsoleGetName()
        {
            Console.WriteLine();
            Console.Write("Type your name: ");
            string name = Console.ReadLine();
            Console.WriteLine("Your name will be: " + name);
            return name;
        }
        public int ConsoleGetDifficulty(int min, int max)
        {
            bool done = false;
            int difficulty = 1;

            Console.WriteLine();
            Console.Write("Choose your difficulty from " + min + " to " + max + ": ");
            while (done == false)
            {
                try
                {
                    string input = Console.ReadLine();
                    difficulty = int.Parse(input);
                    if (difficulty < max + 1 && difficulty > min - 1)
                    {
                        done = true;
                    }
                    else
                    {
                        //Ends the try block with an impossible action (bool.Parse)
                        bool tester = bool.Parse(input);

                    }
                }
                catch
                {
                    Console.Write("Enter a valid number: ");
                }
            }
            Console.WriteLine("Your difficulty will be: " + difficulty);
            return difficulty;
        }

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

        public void Test()
        {

        }
        #endregion



    }
}
0
Finn Bear