문제

나는 XNA (그리고 다양한 버전)와 관련된 많은 튜토리얼을 읽었으며 여전히 프리미티브를 그리는 데 약간 혼란스러워합니다. 모든 것이 정말로 복잡해 보입니다.

누군가가 코드를 사용하여 화면에 하나 또는 두 줄을 그리는 가장 간단한 XNA 구현을 보여줄 수 있습니까? 아마도 간단한 설명 (보일러 플레이트 포함)이 있습니까?

나는 게임 프로그래머가 아니며 XNA 경험이 거의 없습니다. 나의 궁극적 인 목표는 화면에 선을 그리는 것입니다. 그러나이 첫 번째 단계를 위해 .. 나는 단순히 선을 그려야합니다! 나는 고대 Opengl 시절에 몇 가지 방법 호출이있는 줄을 그릴 때 상당히 간단한 것을 기억합니다. 관리되지 않는 DirectX 통화 사용으로 간단히 되돌아 가야합니까?

도움이 되었습니까?

해결책

XNA로 작업 할 때는 3D 카드가 이해할 수있는 방식으로 모든 (2D 프리미티브)를 표현해야합니다. 즉, 선은 일련의 정점 일뿐입니다.

MSDN은 여기에 꽤 좋은 연습을 가지고 있습니다.

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

텍스처 쿼드를 설정하는 것보다 원시 라인을 렌더링하는 데 더 많은 코드가 필요하고 본질적으로 라인을 렌더링 할 때 동일한 작업을 수행하기 때문에 회전합니다.

다른 팁

NoHayProblema의 답변에 따라 (아직 언급 할 수 없습니다).

이 대답은이 오래된 질문의 올바른 대답이지만 불완전합니다. Texture2d 생성자는 화면에 절대 페인트되지 않은 초기화되지 않은 텍스처를 반환합니다. 해당 접근법을 사용하려면 다음과 같은 텍스처 데이터를 설정해야합니다.

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

데이터를 픽셀로 작성하는 방식은 텍스처의 표면 형식과 일치해야합니다. 텍스처가 RGB로 형식화되기 때문에 예제는 작동합니다. 회전은 Spritebatch.Draw에 다음과 같이 적용 할 수 있습니다.

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

글쎄, 당신은 3D 끔찍한 벡터에 들어 가지 않고 매우 간단한 방법으로 할 수 있습니다.

예를 들어 빠른 질감을 만듭니다.

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

그런 다음 해당 텍스처를 사용하여 선을 그립니다.

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

이게 도움이 되길 바란다

그것에 대한 튜토리얼을 찾았습니다http://www.bit-101.com/blog/?p=2832

Basiceffect (셰이더)를 사용하고 내장 된 Draw 사용자 원시 XNA 4.0

도움이되는 일부 코드 샘플 :

로드 컨텐츠 방법

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

방법을 그리십시오

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

이것이 당신을 도와 주면 재미 있고 투표하십시오. 또한 내가 얻은 튜토리얼을 방문하십시오.

가장 간단한 가장 좋은 방법은 흰색 픽셀의 이미지를 얻은 다음 그 픽셀을 사각형으로 늘려 선처럼 보이는 것입니다.

나는 라인 클래스를 만들었고

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

도움이 되었기를 바랍니다

CodePlex에서 "Manders"가 발표 한 "라운드 라인"코드도 있습니다.


여기에 대한 블로그 게시물은 다음과 같습니다.

폭발로 생성 된 광선을 디버그하고 물체가 교차하는 위치를 디버깅 할 수 있도록 광선을 그리고 싶었습니다. 이것은 두 지점 사이에 단일 픽셀 얇은 선을 그립니다. 이것이 내가 한 일입니다.

간단한 광선 데이터를 저장하는 클래스. XNA 기본 광선 클래스는 작동 할 수 있지만 광선의 길이를 교차로에 저장하지는 않습니다.

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

그려야 할 광선을 저장하는 목록 :

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

basiceffect를 만들고 loadContent 메소드에서 원하는 해상도를 사용하여 "matrix.createorthographic foffcenter"투영을 전달하십시오.

그런 다음이 점이 드로우 방법으로 실행합니다.

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

따라서 내 게임에서 폭발이 발생하면 다음과 같습니다 (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);
}

그것은 매우 간단합니다 (아마도 그보다 더 복잡해 보일 수 있습니다). 다시 생각할 필요가없는 별도의 클래스에 넣기가 쉽습니다. 또한 한 번에 많은 줄을 그릴 수 있습니다.

다음은 시작 좌표, 엔드 좌표, 너비 및 색상을 지정하여 선을 만드는 데 사용하는 간단한 방법입니다.

참고 : 컨텐츠 디렉토리에 "dot"이라는 파일을 추가해야합니다 (줄은이 중 하나에서 만들어집니다).

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



    }
}

나는이 문제를 내 자신을 만나고 Linebatch라는 수업을 만들기로 결정했습니다. Linebatch는 Spritebatch 또는 Dots없이 선을 그립니다. 수업은 아래에 있습니다.

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

흰색 픽셀을 늘리십시오.

        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();
        }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top