2008-11-06 141 views
43

我讀過一堆涉及XNA的教程(以及它的各種版本),我仍然對繪製原語有點困惑。一切似乎都非常複雜。如何使用XNA繪製線條?

有人能告訴我,使用代碼,最簡單的XNA實現在屏幕上繪製一行或兩行代碼嗎?也許有一個簡短的解釋(包括樣板)?

我不是一名遊戲程序員,而且我有很少的XNA經驗。我的最終目標是在屏幕上繪製一些線條,我最終將通過旋轉等手段進行轉換。然而,對於這第一步..我需要簡單地畫線!我記得在我古老的OpenGL日子裏,用幾個方法調用繪製一條線就相當簡單。我應該簡單回覆使用非託管directx呼叫嗎?

回答

19

使用XNA時,一切(甚至2d原語)都必須以3d卡可以理解的方式表示,這意味着一行只是一組頂點。

MSDN有一個很好的演練在這裏:

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

你會發現,它需要更多的代碼來渲染一種原始的線比它會採取只設置一個紋理四和旋轉,由於從本質上講,你在渲染一條線時做同樣的事情。

+1

@Jonathan Holland,感謝您的鏈接和解釋。 – mmcdole 2008-11-12 01:23:29

6

那麼,你可以做一個非常簡單的方法,而不會進入3D恐怖的矢量東西。

只需創建一個快速的質感,例如:

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

我希望這有助於

+1

當然,只適用於水平線和垂直線。 OP想旋轉它們,所以這可能不會幫助他。 – 2013-05-30 22:54:48

16

以下:

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

,然後使用該紋理只畫一條線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); 

要考慮到你將數據寫入像素的方式必須與紋理的SurfaceFormat一致。該示例的作用是因爲紋理被格式化爲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); 
+3

將像素數據編輯爲十六進制值比使用Color作爲紋理數據更簡單。像這樣: var txPixel = new Texture2D(GraphicsDevice,1,1); txPixel.SetData (new Color [1] {Color.White}); – krolth 2011-08-08 06:39:26

+3

甚至更​​好:`txPixel.SetData (new [] {Color.White});` – 2012-11-03 14:43:16

6

發現一個教程對於 http://www.bit-101.com/blog/?p=2832

其使用BasicEffect(着色)

和XNA 4.0

內置的拉伸用戶原始

一些代碼樣品I找到有用的:

負載的內容的方法

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

有樂趣,投票了,如果這有助於你。還請訪問我從這裏得到的教程。

4

最簡單最好的辦法,我認爲,就是要得到的只是一個白色像素的圖像,然後伸展該像素在矩形看起來像一條線

我做了一個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; 
    } 

希望這有助於

0

這裏是我使用通過指定起始座標,使線條簡單的方式,最終的座標,寬度,並將它們的顏色:

注:必須將一個名爲「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 



    } 
} 
0

我遇到了這個問題,我自己決定做一個名爲LineBatch的類。 LineBatch將繪製線條而不需要spriteBatch或點。 該課程如下。

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

只是拉伸白色像素。

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

我想繪製光線,這樣我就可以調試由爆炸創建的光線以及它們與物體相交的位置。這將在兩點之間繪製單個像素細線。這是我做的:

類存儲一些簡單的射線數據。 XNA默認光線類可以工作,但它不會將光線的長度存儲到相交處。

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

列表來存儲要繪製的射線:

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

創建一個BasicEffect,並在LoadContent方法所需的分辨率傳遞給它一個「Matrix.CreateOrthographicOffCenter」投影。所以當爆炸在我的遊戲,會發生

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

它這樣做(僞代碼):

然後在抽籤方法運行此

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

這是很簡單的(它可能看起來方式更比它複雜),並且很容易將它放入一個單獨的課程中,您再也不必考慮。它還可以讓你一次繪製大量的線條。