Pergunta

Eu li um monte de tutoriais envolvendo XNA (e suas várias versões) e eu ainda estou um pouco confuso sobre as primitivas de desenho. Tudo parece estar realmente complicado.

Alguém pode me mostrar, usando o código, a mais simples aplicação XNA de desenhar uma ou duas linhas para a tela? Talvez com uma explicação breve (incluindo o clichê)?

Eu não sou um programador de jogos e eu tenho pouca experiência XNA. O meu objectivo final é o de desenhar algumas linhas sobre a tela que eu acabará transformam com rotações, etc (por lado). No entanto, para esta primeira etapa .. Eu preciso simplesmente desenhar as linhas! Lembro-me de volta em meus antigos dias OpenGL era relativamente simples quando desenhar uma linha com algumas chamadas de método. Devo simplesmente reverter para usando chamadas do DirectX não gerenciados?

Foi útil?

Solução

Ao trabalhar com XNA, tudo (até mesmo primitivas 2D) tem que ser expressa de uma forma que uma placa 3D pode entender, o que significa que uma linha é apenas um conjunto de vértices.

MSDN tem uma boa bastante passo a passo aqui:

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

Você verá que é preciso mais código para tornar uma linha primitiva do que seria necessário apenas configurar um quad texturizado e girar que, uma vez que, em essência, o seu fazendo a mesma coisa quando o processamento de uma linha.

Outras dicas

Após a resposta de NoHayProblema (não posso comentar ainda).

Essa resposta, embora o correto para essa questão de idade, está incompleta. Texture2D construtor retorna uma textura não inicializado, que nunca é pintado na tela. Para utilizar essa abordagem, você precisa definir os dados da textura como este:

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

Leve em conta que a maneira de escrever os dados em pixel deve ser consistente com SurfaceFormat da textura. O exemplo funciona porque a textura está sendo formatado como RGB. Rotações pode ser aplicado em spriteBatch.Draw assim:

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

Bem, você pode fazê-lo de uma forma muito simples, sem entrar no material vector horrível 3D.

Apenas criar uma textura rápida, por exemplo:

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

E, em seguida, basta desenhar uma linha usando essa textura:

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

Espero que isso ajude

encontrei um tutorial para isso http://www.bit-101.com/blog/?p=2832

sua usando um BasicEffect (shader) e construído no usuário empate primitiva em XNA 4.0

alguns exemplos de código i encontrar útil:

método de conteúdo de carga

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

método desenhar

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

se divertir e votar-se se isso te ajudou. também fazer uma visita ao tutorial eu tenho isso.

A melhor maneira simples, eu acho, é fazer com que a imagem de apenas um pixel branco, em seguida, esticar o pixel em um retângulo para se parecer com uma linha

Eu fiz uma classe Line,

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

Espero que isso ajude

Há também o código "linha round" que "comandantes" lançou no CodePlex:


Aqui está o post sobre isso:

Eu queria desenhar raios de modo que eu poderia depurar raios criados por explosões e onde eles se cruzam objetos. Isso vai chamar a uma única linha fina de pixel entre dois pontos. Isto é o que eu fiz:

Classe para armazenar alguns dados de raios simples. A classe ray XNA padrão poderia funcionar, mas não armazena o comprimento do raio de intersecção.

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

A lista para armazenar os raios que estão a ser desenhado:

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

Criar um BasicEffect e passá-lo uma projeção "Matrix.CreateOrthographicOffCenter" com a resolução desejada no método LoadContent.

Em seguida, executar este no método draw:

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

Assim, quando uma explosão acontece no meu jogo ele faz isso (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);
}

É muito simples (É, possivelmente, parece muito mais complicado do que é) e que seria fácil para colocá-lo em uma classe separada que você nunca tem que pensar novamente. Ele também permite que você desenhar um monte de linhas ao mesmo tempo.

Aqui está uma maneira simples que eu uso para fazer linhas especificando um início de coordenadas, um fim coordenar, largura e cor deles:

NOTA:. Você deve adicionar um arquivo chamado "ponto" para o diretório de conteúdo (a linha será feita fora destes)

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



    }
}

Eu encontrei este problema meu eu e decidiu fazer uma classe chamada LineBatch. LineBatch será desenhar linhas sem a necessidade de um SpriteBatch ou pontos. A classe está abaixo.

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

Apenas esticar um pixel branco.

        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();
        }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top