如何使用XNA绘制线条?

我已经阅读了一大堆涉及XNA的教程(还有各种各样的版本),在绘制图元时我还是有点困惑。 一切似乎真的很复杂。

有人可以使用代码向我们展示在屏幕上绘制一行或两行代码的最简单的XNA实现吗? 也许有一个简单的解释(包括样板)?

我不是一个游戏程序员,我有一点XNA的经验。 我的最终目标是在屏幕上绘制一些线条,最终我将通过旋转等手段进行转换。 然而,对于这第一步..我需要简单地画线! 我记得在我古老的OpenGL日子里,用几个方法调用绘制一条线就相当简单。 我应该简单地恢复使用非托pipedirectx调用?

在使用XNA的时候,一切(甚至是2d原语)都必须用3d卡可以理解的方式表示,这意味着一行只是一组顶点。

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

考虑到您将数据写入像素的方式必须与纹理的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); 

那么,你可以做一个非常简单的方法,而不会进入3D恐怖的vector东西。

只需创build一个快速的纹理,例如:

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

然后用这个纹理画一条线:

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

我希望这有帮助

find了http://www.bit-101.com/blog/?p=2832的教程;

它使用一个BasicEffect(着色器)和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); 

玩得开心,如果这对你有帮助,就投票。 也请访问我从这里得到的教程。

我认为,最简单的最好方法是获得一个白色像素的图像,然后将该像素拉伸成矩形,看起来像一条线

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

希望这可以帮助

还有“manders”在CodePlex上发布的“圆线”代码:

这里是关于它的博客文章:

  • XNA Roundline代码在CodePlex上发布

我想绘制光线,这样我就可以debugging由爆炸产生的光线以及它们相交物体的位置。 这将在两点之间绘制单个像素细线。 这就是我所做的:

存储一些简单的射线数据的类。 XNA默认的光线类可以工作,但是它不会将光线的长度存储到相交处。

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

存储要绘制的光线的列表:

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

创build一个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(); } 

所以当我的游戏发生爆炸时,它会这样做(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 } } 

我遇到了这个问题,并决定创build一个名为LineBatch的类。 LineBatch将绘制线条而不需要spriteBatch或点。 这个class级在下面。

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