I'm going to describe a method of scaling your objects so they fit correctly on your screen no matter what size of canvas you're drawing them on. This is going to be a fairly simple, starter approach that will hopefully spark your imagination and get you started. This is really a general graphics approach, but I'm going to do it in WinForms with GDI+ for simplicity sake. You can apply the same principles to XNA or DirectX if you like.
Ok, lets get started. We need something to draw first, so lets create a simple object hierarchy that we can use. I'll start with three objects... an interface class, IDrawableObject, then two other classes, DrawableRectangle and DrawableCircle that both inherit from this interface.
Expand|Select|Wrap|Line Numbers
- public interface IDrawableObject
- {
- void Draw(Graphics g);
- }
- public class DrawableRectangle : IDrawableObject
- {
- #region Private Members
- private Point m_location = new Point();
- private Size m_size = new Size();
- private Color m_drawColor;
- #endregion
- #region Public Properties
- public Color Color
- {
- get { return m_drawColor; }
- set { m_drawColor = value; }
- }
- public Point Location
- {
- get { return m_location; }
- set { m_location = value; }
- }
- public Size Size
- {
- get { return m_size; }
- set { m_size = value; }
- }
- public int X
- {
- get { return m_location.X; }
- set { m_location.X = value; }
- }
- public int Y
- {
- get { return m_location.Y; }
- set { m_location.Y = value; }
- }
- public int Width
- {
- get { return m_size.Width; }
- set { m_size.Height = value; }
- }
- public int Height
- {
- get { return m_size.Height; }
- set { m_size.Height = value; }
- }
- #endregion
- #region Constructors
- public DrawableRectangle() { }
- public DrawableRectangle(Point location, Size size)
- : this()
- {
- m_location = location;
- m_size = size;
- }
- public DrawableRectangle(int x, int y, int width, int height)
- : this(new Point(x, y), new Size(width, height))
- {
- }
- public DrawableRectangle(Point location, Size size, Color color)
- : this(location, size)
- {
- m_drawColor = color;
- }
- public DrawableRectangle(int x, int y, int width, int height, Color color)
- : this(new Point(x, y), new Size(width, height), color)
- {
- }
- #endregion
- #region IDrawableObject
- public void Draw(Graphics g)
- {
- if (g != null)
- {
- g.DrawRectangle(new Pen(m_drawColor), m_location.X, m_location.Y, m_size.Width, m_size.Height);
- }
- }
- #endregion
- }
- public class DrawableCircle : IDrawableObject
- {
- #region Private Members
- private Point m_location;
- private int m_radius;
- private Color m_drawColor;
- #endregion
- #region Public Properties
- public Color Color
- {
- get { return m_drawColor; }
- set { m_drawColor = value; }
- }
- public Point Location
- {
- get { return m_location; }
- set { m_location = value; }
- }
- public int X
- {
- get { return m_location.X; }
- set { m_location.X = value; }
- }
- public int Y
- {
- get { return m_location.Y; }
- set { m_location.Y = value; }
- }
- public int Radius
- {
- get { return m_radius; }
- set { m_radius = value; }
- }
- #endregion
- #region Constructors
- public DrawableCircle() { }
- public DrawableCircle(Point location, int radius)
- : this()
- {
- m_location = location;
- m_radius = radius;
- }
- public DrawableCircle(int x, int y, int radius)
- : this(new Point(x, y), radius)
- {
- }
- public DrawableCircle(Point location, int radius, Color color)
- : this(location, radius)
- {
- m_drawColor = color;
- }
- public DrawableCircle(int x, int y, int radius, Color color)
- : this(new Point(x, y), radius, color)
- {
- }
- #endregion
- #region IDrawableObject
- public void Draw(Graphics g)
- {
- if (g != null)
- {
- g.DrawEllipse(new Pen(m_drawColor), m_location.X - m_radius, m_location.Y - m_radius, m_radius * 2, m_radius * 2);
- }
- }
- #endregion
- }
Expand|Select|Wrap|Line Numbers
- public partial class Form1 : Form
- {
- private List<IDrawableObject> m_drawList = new List<IDrawableObject>();
- private Size m_baseSize;
- public Form1()
- {
- InitializeComponent();
- m_baseSize = new Size(320, 200);
- this.Size = new Size(m_baseSize.Width, m_baseSize.Height);
- DrawableCircle c = new DrawableCircle(m_baseSize.Width / 2, m_baseSize.Height / 2, 50, Color.Red);
- DrawableRectangle r = new DrawableRectangle(c.X - 50, c.Y - 100, 100, 50, Color.Blue);
- m_drawList.Add(c);
- m_drawList.Add(r);
- }
- protected override void OnPaint(PaintEventArgs e)
- {
- base.OnPaint(e);
- foreach (IDrawableObject obj in m_drawList)
- {
- obj.Draw(e.Graphics);
- }
- }
- }
Expand|Select|Wrap|Line Numbers
- private PointF m_scale;
Expand|Select|Wrap|Line Numbers
- private PointF CalculateScale(float baseX, float baseY, float newX, float newY)
- {
- return new PointF(newX / baseX, newY / baseY);
- }
Expand|Select|Wrap|Line Numbers
- m_scale = CalculateScale((float)m_baseSize.Width, (float)m_baseSize.Height, this.Size.Width, this.Size.Height);
Expand|Select|Wrap|Line Numbers
- this.Size = new Size(m_baseSize.Width * 2, m_baseSize.Height * 2);
Expand|Select|Wrap|Line Numbers
- public interface IDrawableObject
- {
- void Draw(Graphics g);
- void DrawScaled(Graphics g, PointF scale);
- }
Expand|Select|Wrap|Line Numbers
- public void DrawScaled(Graphics g, PointF scale)
- {
- if (g != null)
- {
- g.DrawEllipse
- (
- new Pen(m_drawColor),
- (m_location.X - m_radius) * scale.X,
- (m_location.Y - m_radius) * scale.Y,
- (m_radius * 2) * scale.X,
- (m_radius * 2) * scale.Y
- );
- }
- }
Expand|Select|Wrap|Line Numbers
- public void DrawScaled(Graphics g, PointF scale)
- {
- if (g != null)
- {
- g.DrawRectangle
- (
- new Pen(m_drawColor),
- m_location.X * scale.X,
- m_location.Y * scale.Y,
- m_size.Width * scale.X,
- m_size.Height * scale.Y
- );
- }
- }
To demonstrate this, lets add an event listener to the resize event on the form. All we'll need to do is recalculate the scale and invalidate the form to force a repaint.
In the constructor...
Expand|Select|Wrap|Line Numbers
- this.Resize += new EventHandler(Form1_Resize);
Expand|Select|Wrap|Line Numbers
- void Form1_Resize(object sender, EventArgs e)
- {
- m_scale = CalculateScale(m_baseSize.Width, m_baseSize.Height, this.Width, this.Height);
- this.Invalidate();
- }
Here is the complete code for this, I hope folks have found it useful :)
Expand|Select|Wrap|Line Numbers
- public partial class Form1 : Form
- {
- private List<IDrawableObject> m_drawList = new List<IDrawableObject>();
- private PointF m_scale;
- private Size m_baseSize;
- public Form1()
- {
- InitializeComponent();
- m_baseSize = new Size(320, 200);
- this.Size = new Size(640, 480);
- this.Resize += new EventHandler(Form1_Resize);
- m_scale = CalculateScale((float)m_baseSize.Width, (float)m_baseSize.Height, this.Size.Width, this.Size.Height);
- DrawableCircle c = new DrawableCircle(m_baseSize.Width / 2, m_baseSize.Height / 2, 50, Color.Red);
- DrawableRectangle r = new DrawableRectangle(c.X - 50, c.Y - 100, 100, 50, Color.Blue);
- m_drawList.Add(c);
- m_drawList.Add(r);
- }
- void Form1_Resize(object sender, EventArgs e)
- {
- m_scale = CalculateScale(m_baseSize.Width, m_baseSize.Height, this.Width, this.Height);
- this.Invalidate();
- }
- private PointF CalculateScale(float baseX, float baseY, float newX, float newY)
- {
- return new PointF(newX / baseX, newY / baseY);
- }
- protected override void OnPaint(PaintEventArgs e)
- {
- base.OnPaint(e);
- foreach (IDrawableObject obj in m_drawList)
- {
- obj.DrawScaled(e.Graphics, m_scale);
- }
- }
- }
- #region Drawable Objects
- public interface IDrawableObject
- {
- void Draw(Graphics g);
- void DrawScaled(Graphics g, PointF scale);
- }
- public class DrawableRectangle : IDrawableObject
- {
- #region Private Members
- private Point m_location = new Point();
- private Size m_size = new Size();
- private Color m_drawColor;
- #endregion
- #region Public Properties
- public Color Color
- {
- get { return m_drawColor; }
- set { m_drawColor = value; }
- }
- public Point Location
- {
- get { return m_location; }
- set { m_location = value; }
- }
- public Size Size
- {
- get { return m_size; }
- set { m_size = value; }
- }
- public int X
- {
- get { return m_location.X; }
- set { m_location.X = value; }
- }
- public int Y
- {
- get { return m_location.Y; }
- set { m_location.Y = value; }
- }
- public int Width
- {
- get { return m_size.Width; }
- set { m_size.Height = value; }
- }
- public int Height
- {
- get { return m_size.Height; }
- set { m_size.Height = value; }
- }
- #endregion
- #region Constructors
- public DrawableRectangle() { }
- public DrawableRectangle(Point location, Size size)
- : this()
- {
- m_location = location;
- m_size = size;
- }
- public DrawableRectangle(int x, int y, int width, int height)
- : this(new Point(x, y), new Size(width, height))
- {
- }
- public DrawableRectangle(Point location, Size size, Color color)
- : this(location, size)
- {
- m_drawColor = color;
- }
- public DrawableRectangle(int x, int y, int width, int height, Color color)
- : this(new Point(x, y), new Size(width, height), color)
- {
- }
- #endregion
- #region IDrawableObject
- public void Draw(Graphics g)
- {
- if (g != null)
- {
- g.DrawRectangle(new Pen(m_drawColor), m_location.X, m_location.Y, m_size.Width, m_size.Height);
- }
- }
- public void DrawScaled(Graphics g, PointF scale)
- {
- if (g != null)
- {
- g.DrawRectangle
- (
- new Pen(m_drawColor),
- m_location.X * scale.X,
- m_location.Y * scale.Y,
- m_size.Width * scale.X,
- m_size.Height * scale.Y
- );
- }
- }
- #endregion
- }
- public class DrawableCircle : IDrawableObject
- {
- #region Private Members
- private Point m_location;
- private int m_radius;
- private Color m_drawColor;
- #endregion
- #region Public Properties
- public Color Color
- {
- get { return m_drawColor; }
- set { m_drawColor = value; }
- }
- public Point Location
- {
- get { return m_location; }
- set { m_location = value; }
- }
- public int X
- {
- get { return m_location.X; }
- set { m_location.X = value; }
- }
- public int Y
- {
- get { return m_location.Y; }
- set { m_location.Y = value; }
- }
- public int Radius
- {
- get { return m_radius; }
- set { m_radius = value; }
- }
- #endregion
- #region Constructors
- public DrawableCircle() { }
- public DrawableCircle(Point location, int radius)
- : this()
- {
- m_location = location;
- m_radius = radius;
- }
- public DrawableCircle(int x, int y, int radius)
- : this(new Point(x, y), radius)
- {
- }
- public DrawableCircle(Point location, int radius, Color color)
- : this(location, radius)
- {
- m_drawColor = color;
- }
- public DrawableCircle(int x, int y, int radius, Color color)
- : this(new Point(x, y), radius, color)
- {
- }
- #endregion
- #region IDrawableObject
- public void Draw(Graphics g)
- {
- if (g != null)
- {
- g.DrawEllipse(new Pen(m_drawColor), m_location.X - m_radius, m_location.Y - m_radius, m_radius * 2, m_radius * 2);
- }
- }
- public void DrawScaled(Graphics g, PointF scale)
- {
- if (g != null)
- {
- g.DrawEllipse
- (
- new Pen(m_drawColor),
- (m_location.X - m_radius) * scale.X,
- (m_location.Y - m_radius) * scale.Y,
- (m_radius * 2) * scale.X,
- (m_radius * 2) * scale.Y
- );
- }
- }
- #endregion
- }
- #endregion