<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Dylan Black &#187; WinForms</title>
	<atom:link href="http://www.dylanblack.com/category/winforms/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dylanblack.com</link>
	<description></description>
	<lastBuildDate>Sat, 16 Jan 2010 23:22:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Displaying image thumbnails in the level editor</title>
		<link>http://www.dylanblack.com/2010/01/17/displaying-image-thumbnails-in-the-level-editor/</link>
		<comments>http://www.dylanblack.com/2010/01/17/displaying-image-thumbnails-in-the-level-editor/#comments</comments>
		<pubDate>Sat, 16 Jan 2010 22:35:59 +0000</pubDate>
		<dc:creator>dylan</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Game]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[WinForms]]></category>
		<category><![CDATA[XNA]]></category>

		<guid isPermaLink="false">http://www.dylanblack.com/?p=47</guid>
		<description><![CDATA[To display the sprite thumbnails in my level editor application, I wrote a couple of simple custom controls. The first control extends from the .NET PictureBox control, and just has an additional property to track whether it’s been selected. Then, &#8230; <a href="http://www.dylanblack.com/2010/01/17/displaying-image-thumbnails-in-the-level-editor/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>To display the sprite thumbnails in my level editor application, I wrote a couple of simple custom controls.</p>
<p>The first control extends from the .NET PictureBox control, and just has an additional property to track whether it’s been selected. Then, in the OnPaint method, if the SelectablePictureBox is selected, then I draw a border over the top of it.</p>
<p>The second control extends from the .NET FlowLayoutPanel control, and has an event that is raised when any child SelectablePictureBox is clicked, and then some code to handle Ctrl-clicking and Shift-clicking to select and deselect individual SelectablePictureBox child controls.</p>
<p>The source code for both controls is below. Feel free to use it if you want to, but note that it’s pretty simple and inflexible, so the SelectableImageFlowLayoutPanel will only work with the SelectablePictureBox.</p>
<p>Let me know if you have any questions about it.</p>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace Editor
{
    public class SelectablePictureBox : PictureBox
    {
        private bool _selected = false;

        public bool Selected
        {
            get { return _selected; }
            set
            {
                _selected = value;
            }
        }

        public SelectablePictureBox()
            : base()
        {
            this.SizeMode = PictureBoxSizeMode.Zoom;
            this.BorderStyle = BorderStyle.FixedSingle;
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            if (_selected)
            {
                this.BorderStyle = BorderStyle.None;
            }
            else
            {
                this.BorderStyle = BorderStyle.FixedSingle;
            }

            base.OnPaint(pe);

            if (_selected)
            {
                this.BorderStyle = BorderStyle.None;
                Pen pen = new Pen(System.Drawing.Color.CornflowerBlue, 6.0f);
                int penWidth = (int)pen.Width;
                Point[] points = new Point[5] { new Point(pe.ClipRectangle.Left, pe.ClipRectangle.Top),
                    new Point(pe.ClipRectangle.Right, pe.ClipRectangle.Top),
                    new Point(pe.ClipRectangle.Right, pe.ClipRectangle.Bottom),
                    new Point(pe.ClipRectangle.Left, pe.ClipRectangle.Bottom),
                    new Point(pe.ClipRectangle.Left, pe.ClipRectangle.Top )};
                pe.Graphics.DrawLines(pen, points);
            }
        }
    }
}</pre>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace Editor
{
    public class SelectableImageFlowLayoutPanel : FlowLayoutPanel
    {
        public delegate void OnSelectedIndexChanged();
        public event OnSelectedIndexChanged SelectedIndexChanged;

        public SelectableImageFlowLayoutPanel()
            : base()
        {
        }

        protected override void OnControlAdded(ControlEventArgs e)
        {
            base.OnControlAdded(e);

            if (e.Control.GetType() == typeof(SelectablePictureBox))
            {
                e.Control.Click += new EventHandler(SelectablePictureBox_Click);
            }
        }

        public int SelectedIndex
        {
            get
            {
                int i = 0;
                bool found = false; ;
                foreach (Control c in Controls)
                {
                    if (((SelectablePictureBox)c).Selected)
                    {
                        found = true;
                        break;
                    }
                    i++;
                }

                if (found)
                {
                    return i;
                }
                else
                {
                    return -1;
                }
            }
            set
            {
                int i = 0;
                foreach (Control c in Controls)
                {
                    if (i == value)
                    {
                        // select controls
                        ((SelectablePictureBox)c).Selected = true;
                        // force a redraw
                        c.Invalidate();
                        break;
                    }
                    else
                    {
                        // deselect controls
                        ((SelectablePictureBox)c).Selected = false;
                        // force a redraw
                        c.Invalidate();
                    }
                    i++;
                }
            }
        }

        public List&lt;SelectablePictureBox&gt; SelectedItems
        {
            get
            {
                List&lt;SelectablePictureBox&gt; selectedItems = new List&lt;SelectablePictureBox&gt;();

                foreach (Control c in Controls)
                {
                    if (((SelectablePictureBox)c).Selected)
                    {
                        selectedItems.Add(((SelectablePictureBox)c));
                    }
                }
                return selectedItems;
            }
        }

        public List&lt;SelectablePictureBox&gt; Items
        {
            get
            {
                List&lt;SelectablePictureBox&gt; items = new List&lt;SelectablePictureBox&gt;();

                foreach (Control c in Controls)
                {
                    items.Add(((SelectablePictureBox)c));
                }
                return items;
            }
        }

        void SelectablePictureBox_Click(object sender, EventArgs e)
        {
            if (InputHelper.IsKeyDown(Keys.ControlKey))
            {
                ((SelectablePictureBox)sender).Selected = true;
                // force a redraw
                ((SelectablePictureBox)sender).Invalidate();
            }
            else if (InputHelper.IsKeyDown(Keys.ShiftKey))
            {
                int startIdx = 0, endIdx = 0;
                bool foundStart = false;

                endIdx = Controls.IndexOf(((SelectablePictureBox)sender));

                foreach (Control c in Controls)
                {
                    if (!foundStart &amp;&amp; ((SelectablePictureBox)c).Selected)
                    {
                        foundStart = true;
                        startIdx = Controls.IndexOf(c);
                    }
                    else
                    {
                        // deselect controls
                        ((SelectablePictureBox)c).Selected = false;
                        // force a redraw
                        c.Invalidate();
                    }
                }

                if (!foundStart)
                {
                    startIdx = endIdx;
                }

                for (int i = startIdx; i &lt;= endIdx; i++)
                {
                    // select the controls in range
                    ((SelectablePictureBox)Controls[i]).Selected = true;
                    // force a redraw
                    Controls[i].Invalidate();
                }
            }
            else
            {
                foreach (Control c in Controls)
                {
                    if (c == sender)
                    {
                        ((SelectablePictureBox)c).Selected = true;
                    }
                    else
                    {
                        ((SelectablePictureBox)c).Selected = false;
                    }
                    // force a redraw
                    c.Invalidate();
                }
            }

            if (SelectedIndexChanged != null)
            {
                SelectedIndexChanged();
            }
        }
    }
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.dylanblack.com/2010/01/17/displaying-image-thumbnails-in-the-level-editor/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>XNA Level Editor</title>
		<link>http://www.dylanblack.com/2008/07/02/xna-level-editor/</link>
		<comments>http://www.dylanblack.com/2008/07/02/xna-level-editor/#comments</comments>
		<pubDate>Wed, 02 Jul 2008 02:25:07 +0000</pubDate>
		<dc:creator>dylan</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Game]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[WinForms]]></category>
		<category><![CDATA[XNA]]></category>

		<guid isPermaLink="false">http://www.dylanblack.com/?p=13</guid>
		<description><![CDATA[I&#8217;m working on a level editor for creating XNA games. At the moment, it only supports the 2D game engine I&#8217;m working on, but I&#8217;m planning to extend both the engine and editor to support 3D graphics (but keeping it &#8230; <a href="http://www.dylanblack.com/2008/07/02/xna-level-editor/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m working on a level editor for creating XNA games.</p>
<p>At the moment, it only supports the 2D game engine I&#8217;m working on, but I&#8217;m planning to extend both the engine and editor to support 3D graphics (but keeping it to 2D logic for the time-being).</p>
<p>This is what the editor looks like when it loads:    <br /><a href="http://www.dylanblack.com/wp-content/uploads/2008/07/level-editor1.png" target="_blank"><img alt="Level Editor" src="http://www.dylanblack.com/wp-content/uploads/2008/07/level-editor-thumb1.png" width="540" height="407" /></a>     <br />The grid can be turned on or off, and the grid size will be editable in the application settings.</p>
<p>From here, you can load your images, and place them in the level: <a href="http://www.dylanblack.com/wp-content/uploads/2008/07/level-editor-images1.png" target="_blank"><img alt="Level Editor Images" src="http://www.dylanblack.com/wp-content/uploads/2008/07/level-editor-images-thumb1.png" width="540" height="407" /></a> Note: game sprites are from <a title="Lost Garden" href="http://lostgarden.com" target="_blank">Lost Garden</a>.</p>
<div id='extendedEntryBreak' name='extendedEntryBreak'></div>
<p> The engine supports the <a title="Farseer Physics" href="http://www.codeplex.com/FarseerPhysics" target="_blank">Farseer Physics</a> engine for XNA, and the editor supports drawing polygon and rectangle collision objects (visible as magenta lines):   <br /><a href="http://www.dylanblack.com/wp-content/uploads/2008/07/level-editor-collisions1.png" target="_blank"><img alt="Level Editor Collisions" src="http://www.dylanblack.com/wp-content/uploads/2008/07/level-editor-collisions-thumb1.png" width="540" height="407" /></a>
</p>
<p>I wrote a custom processor to get the level into the game engine, so I only have to save the level in the editor and add it to the Content project in XNA Game Studio, along with the images that I&#8217;ve used:    <br /><a href="http://www.dylanblack.com/wp-content/uploads/2008/07/level-content-processor1.png" target="_blank"><img alt="Level Content Processor" src="http://www.dylanblack.com/wp-content/uploads/2008/07/level-content-processor-thumb1.png" width="123" height="480" /></a></p>
<p>Then I just need to add some code to the LoadContent method to load the images and create the collision objects in Farseer:</p>
<pre class="brush: c-sharp;">foreach (PolygonCollisionEntity poly in level.PolygonCollisionEntities)
{
    Body polyBody = BodyFactory.Instance.CreatePolygonBody(new Vertices(poly.Vertices), poly.Mass);
    polyBody.IsStatic = true;
    Geom polyGeom = GeomFactory.Instance.CreatePolygonGeom(physicsSimulator, polyBody, new Vertices(poly.Vertices), 1.0f);
} 

foreach (RectangleCollisionEntity rect in level.RectangleCollisionEntities)
{
    Body rectBody = BodyFactory.Instance.CreateRectangleBody(rect.Width, rect.Height, rect.Mass);
    rectBody.IsStatic = true;
    rectBody.Position = rect.Position;
    Geom polyGeom = GeomFactory.Instance.CreateRectangleGeom(physicsSimulator, rectBody, rect.Width, rect.Height);
} 

foreach (string textureName in level.TextureResources)
{
    Texture2D texture = Content.Load&lt;Texture2D&gt;(textureName);
    level.Textures.Add(textureName, texture);
}</pre>
<p>Then I can run the level:</p>
<p><a href="http://www.dylanblack.com/wp-content/uploads/2008/07/level-in-game1.png" target="_blank"><img alt="Level In Game" src="http://www.dylanblack.com/wp-content/uploads/2008/07/level-in-game-thumb1.png" width="501" height="480" /></a> </p>
<p>The collision objects are visible as dark green lines, and the green and white boxes form a chain, implemented in Farseer, interacting with the level.</p>
<p>Next up I plan on implementing the following features:</p>
<ul>
<li>Modify level content processor to load textures automatically, so that they don&#8217;t need to be added manually </li>
<li>Implement a camera system to be able to create larger levels and move around them </li>
<li>Add functionality to the level editor to be able to edit objects once they have been placed </li>
<li>Implement the Properties tab using the .NET Property Grid control to be able to edit the properties of selected objects </li>
</ul>
<p>Once that&#8217;s done, it&#8217;s on to the game itself!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dylanblack.com/2008/07/02/xna-level-editor/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>
