Drawing lines in C# with XNA - c#

There is a similar question System.Drawing in XNA, but this may be a clearer question and thus one easier to answer.
We're trying to draw lines on the screen in C#. We are using the XNA library. This code
void DrawLine2 (Vector2 point1, Vector2 point2)
{
System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Green, 1);
Point p1 = new Point((int)point1.X, (int)point1.Y), p2 = new Point((int)point2.X, (int) point2.Y);
Graphics.DrawLine (pen, p1, p2);
}
gives the compile-time error that Graphics does not exist.
Perhaps I should be using something in XNA to draw the line rather than in System -- but if so I am not sure what. XNA has a Spritebatch drawing function, but AFAIK you give it a sprite and a center (and a rotation), rather than 2 points.

Try this handy extensions method,
public static void DrawLine(this SpriteBatch spriteBatch, Vector2 begin, Vector2 end, Color color, int width = 1)
{
Rectangle r = new Rectangle((int)begin.X, (int)begin.Y, (int)(end - begin).Length()+width, width);
Vector2 v = Vector2.Normalize(begin - end);
float angle = (float)Math.Acos(Vector2.Dot(v, -Vector2.UnitX));
if (begin.Y > end.Y) angle = MathHelper.TwoPi - angle;
spriteBatch.Draw(1X1 PIXEL TEXTURE, r, null, color, angle, Vector2.Zero, SpriteEffects.None, 0);
}

Spritebatch can be used to draw a line, as Beanish commented you can simply make a one pixel sprite and extend it between two points.
This is a great library for drawing 2D primitives in XNA that uses the technique for drawing lines, as well as other objects like arcs. I use it extensively:
http://sourceforge.net/projects/primitives2d/

Related

How Would You Draw a RectangleF with Spritebatch.Draw?

I'm trying to create a top down game where you can move in 8 directions. I've implemented Vector2 in order to move in a normalised manner. I use a spritebatch system to draw with standard rectangles (source and destination) but soon changed to RectangleF as regular rectangles use integers.
The Spritebatch does not recognise the RectangleF and hence returns the error, "Cannot convert from 'System.Drawing.RectangleF' to 'Microsoft.Xna.Framework.Vector2'?". The Color also returns ambiguous and no matter 'System.Drawing' or 'Microsoft.Xna.Framework.Color', it always returns how it cannot be converted into 'Microsoft.Xna.Framework.Rectangle'.
In this code, a Vector2 (Position) is called in and used to draw the RectangleF's position. I then use the Spritebatch.Draw to draw a texture with the Source and Destination and it is always updated to give the implication of a moving character.
public static RectangleF destinationRectangle, sourceRectangle;
public void Draw(SpriteBatch spriteBatch)
{
int width = 64;
int height = 64;
realPositionX = PlayerMovement.Position.X;
realPositionY = PlayerMovement.Position.Y;
sourceRectangle = new RectangleF(currentFrame * width, row * height, width, height);
destinationRectangle = new RectangleF(realPositionX, realPositionY, width, height);
spriteBatch.Begin();
spriteBatch.Draw(Player, destinationRectangle, sourceRectangle, Microsoft.Xna.Framework.Color.White); //Error Occurs Here
spriteBatch.End();
}
I'm confused as how I should approach this issue, is there a way of drawing a RectangleF through SpriteBatch or do I have to look at another method?
Thanks.
There is absolutely no reason to use RectangleF.
Usually you use a pixel based coordinate system in your game and therefore the Rectangle Class is what you want to go for.
Other than that it is a better approach to store the players postion in a Vector2 and using the the appropriate overload:
SpriteBatch.Draw (Texture2D, Vector2, Color)

C# XNA - Start draw from bottom-center

Normally XNA start drawing sprite from top-left, but I would like to start draw object from bottom-center, how this could be done?
You want to specify a different origin in your SpriteBatch.Draw calls. The default is 0,0 (top-left). Note that the origin is relative to the sprite, not the screen.
So if your sprite is 64x64, you want to use an origin of 32x64 for bottom center.
e.g. using this override (MSDN)
spriteBatch.Draw (
texture,
position,
sourceRectangle,
color,
rotation,
new Vector2(32, 64), // origin
scale,
effects,
layerDepth
)
You can calculate these on the fly if you wish. e.g if you're using the full texture you could specify it as new Vector2(texture.Center.X, texture.Height). Or alternatively you could base it on the sourceRectangle if you're using a sprite sheet.
You need to specify a bunch of other arguments to use these Draw overrides but you can just pass in the defaults. The defaults are:
sourceRectangle: null = full texture
color: Color.White = default color (sprite colors will be used)
rotation: 0f = no rotation
scale: 1f = default scale
efects: SpriteEffects.None = no flipping
layerDepth: 0 = default layer
Lets say you are drawing an image WidthxHeight on position XxY.
spriteBatch.Draw(texture, position, Color.White);
First let's set the bottom of the image to those coordinates by subtracting images height from position's Y coordinate (subtracting because in XNA the Y-axis is inverted, not like in your math class)
spriteBatch.Draw(texture, position + new Vector2(0, -texture.Height), Color.White);
Second, let's set the image to the left by subtracting half of the image's width from position's X coordinate.
spriteBatch.Draw(texture, position + new Vector2(-texture.Width/2, -texture.Height), Color.White);
And there you have it.
Edit: Another thought: you can create new variable called DrawPosition and use that variable when needed, instead of always substracting. That would look something like this:
private Texture2D texture;
public Vector2 position;
public Vector2 DrawPosition
{ get { return position + new Vector2(-texture.Width/2, -texture.Height); } }
public void Draw(SpriteBatch spriteBatch)
{ spriteBatch.Draw(texture, DrawPosition, Color.White); }
Or, if this new variable doesn't make sense to you, create a function that will return the DrawPosition()
public Vector2 DrawPosition()
{ return position + new Vector2(-texture.Width/2, -texture.Height); }

Why am I getting a gap when trying to draw a string using a GraphicsPath object? C#/.NET 3.5

I'm trying to draw the path of some text characters on a 3D plane for printing on a 3D printer. I'm getting gaps where the last line should be drawn. I also tried drawing a rectangle using the AddRectangle command. I ended up with a line.
Does anyone know what I might be doing wrong?
Here are are the code snippets showing what I've written:
graphics_path1.AddRectangle(new Rectangle(50,50,50,50));
graphics_path1.AddString("Test text...", new FontFamily(workingFontObject.FONT.Name), (int)workingFontObject.FONT.Style, workingFontObject.FONT.Size, new Point(8, 2), StringFormat.GenericTypographic);
RotateScaleOffsetGraphicsPath(graphics_path1, rotateAngle, RotateCenter, magnification, xyOffset);
private void RotateScaleOffsetGraphicsPath(GraphicsPath workingGraphicsPath, float RotateAngle, PointF RotateCenter, float Magnification, PointF ROIOffset)
{
float Invert = (1.0f); //invert without any other modifications
Matrix mm1 = new Matrix(); //Create a new matrix for transformations
PointF bedCenter = new PointF(bedWidth/2,bedDepth/2);
//mm1.RotateAt(RotateAngle, bedCenter, MatrixOrder.Append);//Rotate
mm1.Translate(Invert*ROIOffset.X, Invert* ROIOffset.Y, MatrixOrder.Append);//set roi offset
mm1.Scale(Magnification, Magnification, MatrixOrder.Append);//magnify, the 2 magnifications are x and y and can actually be different for a skewed growth
//apply the transformation matrix on the graphical path
workingGraphicsPath.Transform(mm1);
}
Blockquote

Make a point follow a rotating sprite

I have a rectangle with a square at its bottom. I also have code that makes the rectangle rotate around its origin which is at the top of this rectangle. Im trying to make the square at the bottom to always stay at the end of this rectangle even when its rotated. Hers a picture to illustrate my problem:
I see now that it wasn't such a good idea to make the square at the bottom white. So when i rotate the rectangle upwards to the right or upwards to the left, I want the square to keep staying at the end of this rectangle. Maybe there is a simple solution, but my knowledge isn't as good as it should be on this subject. Hope someone could point me in the right direction.
Something like this aught to get you there.
float pendulumAngle;
Vector2 origin;
Vector2 squareTLcorner;//top left corner of square
Vector2 squareOffset;
void Reset()
{
pendulumAngle = 0;
origin = new Vector2(?.?f, ?.?f);// set to whatever you need
squareTLcorner = new Vector2(?.?f, ?.?f); // set to whatever you need
squareOffset = squareTLcorner - origin;
}
void UpdatePendulum(float angleMovedSinceLastFrame)
{
pendulumAngle += angleMovedSinceLastFrame;
}
void UpdateSquarePosition()
{
squareTLcorner = Vector2.Transform(squareOffset, Matrix.CreateRotationZ(pendulumAngle) + origin;
}
void DrawSquare()
{
spriteBatch.Draw(sqTex,squareTLcorner, , ,pendulumAngle, , , , );// overload 6 of 7
}
The easiest way is passing a transformation matrix to the sprite batch.
Rectangle Black = new Rectangle(0,0, 20, 100);
Rectangle White = new Rectangle( Black.Left, Black.Bottom, Black.Width, Black.width);
Vector2 Pivot= new Vector(100,100);
vector2 Origin = new Vector2( 10,10);
Matrix transform = Matrix.CreateTranslation(-Origin.X, -Origin.Y)
* Matrix.CreateRotationZ(angle)
* Matrix.CreateTranslation(Pivot);
SpriteBatch.begin(...., transform)
SpriteBatch.Draw( Texture, Black, Color);
SpriteBatch.Draw( Texture, White, Color);
SpriteBatch.end();
Basically you are working in a different space that is rotated ans translated as you need, realize that Black rectangle location is (0,0).
Code it's not tested but should work as expected. ;)

XNA Texture2D Billboarding appears as a white block

Very odd problem, when I try and draw my billboard sprite it always appears as a white block, changing the .draw color property still draws it as white, it also doesn't matter it I use a jpeg, or transparent png.
[EDIT]
So I'm now trying to use a Viewport instead of a basic effect to just get an x and y screen coordinate, I'll fix any scaling issue later, however now the image stays in the exact same spot (on the screen, it doesn't change position based on the camera) and doesn't get any bigger or smaller based on how far away it is
My new billboard rendering function:
public void Draw(Camera camera, GraphicsDevice device, SpriteBatch spriteBatch, Texture2D Texture)
{
Viewport viewport = new Viewport(new Rectangle(0, 0, 800, 480));
Vector3 viewSpaceTextPosition = viewport.Project(this.position, camera.Projection, camera.View, camera.World);
spriteBatch.Begin();
spriteBatch.Draw(Texture, new Vector2(viewSpaceTextPosition.X, viewSpaceTextPosition.Y), null, Color.White, 0, new Vector2(Texture.Bounds.Center.X, Texture.Bounds.Center.Y), this.Scale, SpriteEffects.None, viewSpaceTextPosition.Z);
spriteBatch.End();
device.RasterizerState = RasterizerState.CullCounterClockwise;
device.BlendState = BlendState.Opaque;
device.DepthStencilState = DepthStencilState.Default;
}
So is my use of Viewport wrong or do I just need to use it's information differently in spriteBatch.Draw()?
I think this should do the trick using viewport project... taking two projection points and calculating its distance you get a value affected by depth... so if it's deeper that value will be smaller.
public void Draw(Camera camera, GraphicsDevice device, SpriteBatch spriteBatch, Texture2D Texture)
{
Vector3 pos1= device.Viewport.Project(
this.position,
camera.Projection, camera.View, camera.World);
Vector3 pos2= device.Viewport.Project(
this.position+ Vactor3.UnitY*10,
camera.Projection, camera.View, camera.World);
Vector2 pos = new Vector2(pos1.X, pos1.Y);
Vector2 origin = new Vector2(Texture.Bounds.Center.X, Texture.Bounds.Center.Y);
float Scale = Vector3.Distance(pos1, pos2) * CustomRatio;
spriteBatch.Begin();
spriteBatch.Draw(Texture, pos, null, Color.White, 0,
origin, Scale, SpriteEffects.None, 0);
spriteBatch.End();
device.RasterizerState = RasterizerState.CullCounterClockwise;
device.BlendState = BlendState.Opaque;
device.DepthStencilState = DepthStencilState.Default;
}
In other hand... your previous code seems to be extracted from a source that drinks from this article made by the guy behind Xna that explain how to use basiceffect to draw billboards in 3D with spritebatch...
http://blogs.msdn.com/b/shawnhar/archive/2011/01/12/spritebatch-billboards-in-a-3d-world.aspx
I hope it helps you
Figured it out, you have to enable textures on the effect and then set effect.Texture to the Texture2D you want to use just before calling spriteBatch.Begin() in the draw function

Categories

Resources