This is a very simple question but I couldn't find anything on the internet that was helpful. Basically, I am trying to draw a rectangle but when I launch my code nothing is happening (I don't have any errors either). Here is the code:
class Buildings
{
public void test(Game1 mainGame, SpriteBatch spriteBatch)
{
var buildingrect = new Rectangle(mainGame.bufferHeight - 30, 50, 200, 50);
// (Note: mainGame.alien2 is a texture I have - this isn't the problem)
spriteBatch.Draw(mainGame.alien2, buildingrect, Color.White);
}
}
public class Game1 : Microsoft.Xna.Framework.Game
{
protected override void Draw(GameTime gameTime)
{
buildings.test(this, spriteBatch);
}
}
Thank you for your help and I apologize again for this being such a simple question - I'm still a beginner.
Unfortunately, you can not draw rectangles simple like that. You can solve it like this:
Create a texture that holds the pixelcolor for the rectangle
private Texture2D pixel;
private Rectangle rect; //your rectangle`
Initialize it with your preferred color:
pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new[] { Color.White });`
In your draw method you now draw each side of your rectangle:
int bw = 2; // Border width
//Left
spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Top, bw, rect.Height), Color.Black);
//Right
spriteBatch.Draw(pixel, new Rectangle(rect.Right, rect.Top, bw, rect.Height), Color.Black);
//Top
spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Top, rect.Width, bw), Color.Black);
//Bottom
spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Bottom, rect.Width, bw), Color.Black);
Related
Is it possible to create a form that has rounded borders and have a border color?
I have tried the following:
protected override void OnPaint(PaintEventArgs e) {
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, Color.NavajoWhite,
ButtonBorderStyle.Solid);
}
and
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
private static extern IntPtr CreateRoundRectRgn
(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // height of ellipse
int nHeightEllipse // width of ellipse
);
public Main() {
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 18, 18));
}
This is the result:
I also tried:
protected override void OnPaint(PaintEventArgs e) {
ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle, Color.White, 1, ButtonBorderStyle.Solid, Color.White, 1, ButtonBorderStyle.Solid, Color.White, 2, ButtonBorderStyle.Solid, Color.White, 2, ButtonBorderStyle.Solid);
}
This is the result:
I am so close to the 2nd one, but how can I extend the color borders on the rounded edges?
You need to draw a border for the form manually. And here is a simple demo you can refer to.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
}
public void SetWindowRegion()
{
System.Drawing.Drawing2D.GraphicsPath FormPath;
FormPath = new System.Drawing.Drawing2D.GraphicsPath();
Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
FormPath = GetRoundedRectPath(rect, 30);// 30 represents the size of the fillet angle
this.Region = new Region(FormPath);
}
private GraphicsPath GetRoundedRectPath(Rectangle rect, int radius)
{
int diameter = radius;
Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
GraphicsPath path = new GraphicsPath();
path.AddArc(arcRect, 180, 90);// top left
arcRect.X = rect.Right - diameter;//top right
path.AddArc(arcRect, 270, 90);
arcRect.Y = rect.Bottom - diameter;// buttom right
path.AddArc(arcRect, 0, 90);
arcRect.X = rect.Left;// button left
path.AddArc(arcRect, 90, 90);
path.CloseFigure();
return path;
}
private static GraphicsPath GetRoundRectangle(Rectangle rectangle, int r)
{
int l = 2 * r;
// Divide the rounded rectangle into a combination of straight lines and arcs, and add them to the path in turn
GraphicsPath gp = new GraphicsPath();
gp.AddLine(new Point(rectangle.X + r, rectangle.Y), new Point(rectangle.Right - r, rectangle.Y));
gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Y, l, l), 270F, 90F);
gp.AddLine(new Point(rectangle.Right, rectangle.Y + r), new Point(rectangle.Right, rectangle.Bottom - r));
gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Bottom - l, l, l), 0F, 90F);
gp.AddLine(new Point(rectangle.Right - r, rectangle.Bottom), new Point(rectangle.X + r, rectangle.Bottom));
gp.AddArc(new Rectangle(rectangle.X, rectangle.Bottom - l, l, l), 90F, 90F);
gp.AddLine(new Point(rectangle.X, rectangle.Bottom - r), new Point(rectangle.X, rectangle.Y + r));
gp.AddArc(new Rectangle(rectangle.X, rectangle.Y, l, l), 180F, 90F);
return gp;
}
public void FillRoundRectangle(Graphics g, Rectangle rectangle, Pen pen, int r)
{
rectangle = new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
g.DrawPath(pen, GetRoundRectangle(rectangle, r));
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.Blue, 3);
pen.DashStyle = DashStyle.Solid;
Rectangle rectangle = new Rectangle(1, 1, this.Width - 2, this.Height - 2);
FillRoundRectangle(e.Graphics, rectangle, pen, 14);
}
private void Form1_Resize(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Normal)
{
SetWindowRegion();
}
else
{
this.Region = null;
}
}
}
I made a box that I drew using Graphics.DrawLine() for each edge. But I would like the box to be able to move around the screen freely, along with changing the size of the edges. The box is created by using a middle point and width and height, then basic math to find the 4 points which the lines connect to. My question is: How can I update the position of the lines? Do I have to clear the graphics and re-draw the lines each frame? Any answers will be helpful. Thank you.
Here is the code I am using:
private void Form1_Paint(object sender, PaintEventArgs e)
{
Point box_Middle = new Point(300, 300);
int boxWidth = 100;
int boxHeight = 200;
Pen boxPen = new Pen(Color.Red, 3);
DrawBox(e, boxPen, box_Middle, boxWidth, boxHeight);
}
void DrawBox (PaintEventArgs e, Pen pen, Point middle, int width, int height)
{
graphics = e.Graphics;
graphics.TextRenderingHint = System.Drawing.
Text.TextRenderingHint.
SingleBitPerPixelGridFit;
// Draw Box
Point topLeft = new Point(middle.X - width / 2, middle.Y - height / 2);
Point topRight = new Point(topLeft.X + width, topLeft.Y);
Point bottomLeft = new Point(topLeft.X, topLeft.Y + height);
Point bottomRight = new Point(topRight.X, bottomLeft.Y);
graphics.DrawLine(pen, topLeft, topRight);
graphics.DrawLine(pen, topLeft, bottomLeft);
graphics.DrawLine(pen, bottomLeft, bottomRight);
graphics.DrawLine(pen, topRight, bottomRight);
}
I am currently trying to draw a gradient filled rounded rectangle onto a panel bar in a form.
From some research I found some code that allowed me to create a custom rectangle :
static class CustomRectangle
{
public static GraphicsPath RoundedRect(Rectangle bounds, int radius)
{
int diameter = radius * 2;
Size size = new Size(diameter, diameter);
Rectangle arc = new Rectangle(bounds.Location, size);
GraphicsPath path = new GraphicsPath();
if (radius == 0)
{
path.AddRectangle(bounds);
return path;
}
// top left arc
path.AddArc(arc, 180, 90);
// top right arc
arc.X = bounds.Right - diameter;
path.AddArc(arc, 270, 90);
// bottom right arc
arc.Y = bounds.Bottom - diameter;
path.AddArc(arc, 0, 90);
// bottom left arc
arc.X = bounds.Left;
path.AddArc(arc, 90, 90);
path.CloseFigure();
return path;
}
public static void FillRoundedRectangle(this Graphics graphics, Brush brush, Rectangle bounds, int cornerRadius)
{
if (graphics == null)
throw new ArgumentNullException("graphics");
if (brush == null)
throw new ArgumentNullException("brush");
using (GraphicsPath path = RoundedRect(bounds, cornerRadius))
{
graphics.FillPath(brush, path);
}
}
Credit to this page
Next using this custom rectangle, I have tried using the paint method for the bar panel.
private void quickMenuBar_Paint(object sender, PaintEventArgs e)
{
LinearGradientBrush myBrush = new LinearGradientBrush(new Point(20, 20), new Point(120, 520), Color.DarkBlue, Color.RoyalBlue);
System.Drawing.Graphics formGraphics = this.CreateGraphics();
CustomRectangle.FillRoundedRectangle(formGraphics, myBrush, new System.Drawing.Rectangle(20, 20, 100, 500), 25);
myBrush.Dispose();
formGraphics.Dispose();
}
But after executing this code, it only prints a rounded rectangle directly onto the form and behind the bar panel.
I have other methods that fill a panel with a standard rectangle using PaintEventArgs e:
e.Graphics.FillRectangle(myBrush , otherBar.ClientRectangle);
So obviously I need to use PaintEventArgs e in my custom rectangle method, but I do not know how or where to.
If there are better ways than this way of drawing a rounded rectnagles, please share.
You generally should never be using CreateGraphics(). Simply remove this line:
System.Drawing.Graphics formGraphics = this.CreateGraphics();
And use e.Graphics where you would previously use formGraphics. The Paint event is basically asking you to "paint something for me, here's the graphics object to paint on".
Since you're already providing a Graphics object instance to your rounded rectangle method, no changes are required there.
How do you draw shapes, such as Rectangles and Circles, in MonoGame without having to save the a predrawn shape in the Content folder?
DrawRectangle() and DrawEllipse() are for Windows Form and do not work in OpenGL, which is what I am using.
Use 3D primitives and a 2D projection
Here's a simple example with explanations
I define a 10x10 rectangle and set the world matrix to make it look like a 2D projection :
Note : the BasicEffect is what draws your primitive
protected override void LoadContent()
{
_vertexPositionColors = new[]
{
new VertexPositionColor(new Vector3(0, 0, 1), Color.White),
new VertexPositionColor(new Vector3(10, 0, 1), Color.White),
new VertexPositionColor(new Vector3(10, 10, 1), Color.White),
new VertexPositionColor(new Vector3(0, 10, 1), Color.White)
};
_basicEffect = new BasicEffect(GraphicsDevice);
_basicEffect.World = Matrix.CreateOrthographicOffCenter(
0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1);
}
Then I draw the whole thing :D
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
EffectTechnique effectTechnique = _basicEffect.Techniques[0];
EffectPassCollection effectPassCollection = effectTechnique.Passes;
foreach (EffectPass pass in effectPassCollection)
{
pass.Apply();
GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineStrip, _vertexPositionColors, 0, 4);
}
base.Draw(gameTime);
}
There you have your rectangle !
Now this is just the tip the of the iceberg,
To draw filled rectangles : draw 2 triangle primitives
For an ellipse/circle see these : Draw an Ellipse in XNA and Draw simple circle in XNA
Or as mentioned in one of the posts above you could use a shader that does it instead ...
I needed to draw a Superellipse a while ago and ended up sketching this shader :
Drawing a SuperEllipse in HLSL
As you can see in the post a Superellipse not only draws ellipse but also other shapes and maybe even circles (I did not test) so you might be interested in it.
Ultimately you will want some class/methods to hide all these details so you just have to invoke something like DrawCircle().
Tip : by posting # https://gamedev.stackexchange.com/ you will likely get more answers for Monogame-related questions
:D
If you need to create a rectangle in 2D you can just do this:
Color[] data = new Color[rectangle.Width * rectangle.Height];
Texture2D rectTexture = new Texture2D(GraphicsDevice, rectangle.Width, rectangle.Height);
for (int i = 0; i < data.Length; ++i)
data[i] = Color.White;
rectTexture.SetData(data);
var position = new Vector2(rectangle.Left, rectangle.Top);
spriteBatch.Draw(rectTexture, position, Color.White);
Might be a tad bit easier than Aybe's answer in some situations. This creates a solid rectangle.
I found a simple solution for drawing filled and non-filled shapes, I don't know if it's power consuming or not, but here it is anyway:
{
//Filled
Texture2D _texture;
_texture = new Texture2D(graphicsDevice, 1, 1);
_texture.SetData(new Color[] { Color.White });
spriteBatch.Draw(_texture, Rect, Color.White);
}
{
//Non filled
Texture2D _texture;
_texture = new Texture2D(graphicsDevice, 1, 1);
_texture.SetData(new Color[] { Color.White });
spriteBatch.Draw(_texture, new Rectangle(Rect.Left, Rect.Top, Rect.Width, 1), Color.White);
spriteBatch.Draw(_texture, new Rectangle(Rect.Right, Rect.Top, 1, Rect.Height), Color.White);
spriteBatch.Draw(_texture, new Rectangle(Rect.Left, Rect.Bottom, Rect.Width, 1), Color.White);
spriteBatch.Draw(_texture, new Rectangle(Rect.Left, Rect.Top, 1, Rect.Height), Color.White);
}
Is it possible to draw a polyline that has a linear gradient along it's stroke width? That is, if you have a gradient with black on 0 and 100% and white 50%, the black will always be on the edge of the line and the white in the middle, regardless of the angle. Think of it as some sort of 3D pipes. Of course, the line will have a stroke width of at least 10px. All the questions here ask how to fill a line between it's ends. I'm definitely not interested in that. I'm working in C# using GDI+, can be any .NET version.
I think this is what you want:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode=SmoothingMode.AntiAlias;
DrawPipe(e.Graphics, 10f, new PointF(10, 10), new PointF(250, 80), Color.White, Color.Black);
DrawPipe(e.Graphics, 10f, new PointF(15, 60), new PointF(280, 120), Color.BlueViolet, Color.Black);
}
private void DrawPipe(Graphics g, float width, PointF p1, PointF p2, Color mid_color, Color edge_color)
{
SizeF along=new SizeF(p2.X-p1.X, p2.Y-p1.Y);
float mag=(float)Math.Sqrt(along.Width*along.Width+along.Height*along.Height);
along=new SizeF(along.Width/mag, along.Height/mag);
SizeF perp=new SizeF(-along.Height, along.Width);
PointF p1L=new PointF(p1.X+width/2*perp.Width, p1.Y+width/2*perp.Height);
PointF p1R=new PointF(p1.X-width/2*perp.Width, p1.Y-width/2*perp.Height);
PointF p2L=new PointF(p2.X+width/2*perp.Width, p2.Y+width/2*perp.Height);
PointF p2R=new PointF(p2.X-width/2*perp.Width, p2.Y-width/2*perp.Height);
GraphicsPath gp=new GraphicsPath();
gp.AddLines(new PointF[] { p1L, p2L, p2R, p1R});
gp.CloseFigure();
Region region=new Region(gp);
using(LinearGradientBrush brush=new LinearGradientBrush(
p1L, p1R, Color.Black, Color.Black))
{
ColorBlend color_blend=new ColorBlend();
color_blend.Colors=new Color[] { edge_color, mid_color, edge_color };
color_blend.Positions=new float[] { 0f, 0.5f, 1f };
brush.InterpolationColors=color_blend;
g.FillRegion(brush, region);
}
}
}
Edit 1
An alternative is to use a PathGradientBrush
GraphicsPath gp = new GraphicsPath();
gp.AddLines(new PointF[] { p1, p1L, p2L, p2, p2R, p1R });
gp.CloseFigure();
Region region = new Region(gp);
using (PathGradientBrush brush = new PathGradientBrush(gp))
{
brush.CenterColor = mid_color;
brush.SurroundColors = new Color[]
{
mid_color, edge_color,edge_color,mid_color,edge_color,edge_color
};
g.FillRegion(brush, region);
}
Edit 2
To make the edges smoother use some alpha transparency:
using(LinearGradientBrush brush=new LinearGradientBrush(
p1L, p1R, Color.Black, Color.Black))
{
ColorBlend color_blend=new ColorBlend();
color_blend.Colors=new Color[] {
Color.FromArgb(0, edge_color), edge_color, mid_color,
edge_color, Color.FromArgb(0, edge_color) };
color_blend.Positions=new float[] { 0f, 0.1f, 0.5f, 0.9f, 1f };
brush.InterpolationColors=color_blend;
g.FillRegion(brush, region);
}
Edit 3
With some artifacts multiple lines are drawing, by rendering circles between then first and then the lines
private void DrawPipes(Graphics g, float width, PointF[] points, Color mid_color, Color edge_color)
{
for (int i = 0; i < points.Length; i++)
{
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddEllipse(points[i].X - width / 2, points[i].Y - width / 2, width, width);
using (PathGradientBrush brush = new PathGradientBrush(gp))
{
brush.CenterColor = mid_color;
brush.SurroundColors = new Color[] { edge_color };
brush.CenterPoint = points[i];
g.FillPath(brush, gp);
}
}
if (i > 0)
{
DrawPipe(g, width, points[i - 1], points[i], mid_color, edge_color);
}
}
}