March 25, 2009

XNA Game Editor Tutorial #1: Form, Render Control

In this chapter, we are going to get started on our editor. To get started, add a new project to your solution. However, this time we will make it a “Windows Forms” project. This will create a project with the necessary references to use windows forms in your project. These forms are the basis of (almost) all windows applications. They have a number of properties regarding size, title, toolbar buttons, etc. A form is basically a container for objects like buttons, sliders, textboxes, etc. These objects are called “controls”, and custom controls can be created by inheriting from “Control”.

Now that your project is created, go into the solution explorer and click Form1. You should see your form appear in the design window. This window is used for editing your forms and controls. Controls in the forms here won’t respond to clicks, input, etc, but they do give you access to all their properties by clicking on them and opening the Properties window. Events provided by the control are also available here by clicking the lighting bolt icon in the toolbar at the top of the property list. To add a handler to an event, just double click in the box by the events name and it will take you to the code window. This window is what you are used to, where you can edit the code of your Form or Control class. This is also available by right clicking and clicking on “View Code”. This works the other way around too, “View Design” is available in the code window. An important note about the property editor: the properties you set and controls you add to the form in the design window are all set via code that is automatically generated. If you click the [+] next to the form’s file in the solution explorer, you will see that there are actually two files here: one is the code file you should edit: “ClassName.cs”, the other is the automatically generated one. This file has the modified name “ClassName.Designer.cs”.

If you look at the first file, you will see that the Control is actually a “partial” class, which only means that its definition is split across multiple files. If you analyze the generated code, you will see that most of the work setting properties and creating instances of objects is done in the “InitializeComponent()” method. You can see that in the manually written file, part of which was written for you when you created the form (which happened when the project was created), the default constructor of the Form1 class calls this method. You should generally leave this as the first call, or your form’s controls will not be ready and set up properly. You should not change the code in the generated code file, as it will be rebuilt every time a property is changed or a control is added. You could even mess up the design window by editing this file, because it relies on it to setup the design window. In short, do all your editing in the manually written file.

The final part of the designer is the Toolbox. If you can’t see it, open it from the “View” menu. If you open this window you will see a list of all the standard controls provided by Microsoft. You can add more item to this box by right clicking and choosing “Choose Items…”. To add one of the items, just drag it onto the form or control you are editing and the code generator will take care of everything else. The controls added to the control can be accessed from the manual file just like it was declared in the class like we are used to. To change the name you access it from, change its “Name” property. You should now know most of what you need to know to use the designer. The first thing we are going to do is make our form a little bigger. Move the cursor over the bottom right of the window and resize it to a reasonable size, probably at least 1024×768-ish. You can see the current size in the Properties window. Change the “Text” property to something other than Form1. This will be the main form for the editor, so I just named mine “Innovation Engine Editor”.

Now that our form is set up, we need to get XNA rendering into our window. First add the following references (References>Add Reference): .Net: Microsoft.Xna.Framework, Microsoft.Xna.Framework.Game, Browse: InnovationEngine.dll. Now we can get to the render control. XNA has kindly made this rather difficult for us ( :) just kidding) so we have a few things to do.

We need to set up the graphics device and related services XNA needs to draw, because we can’t use the Game class here. Luckily, there is a sample on the Creators Club Website that demonstrates this. Most of the code will be borrowed from this sample, but we will need to make our control that will be the render surface, and take care of things like GameTime and the GraphicsDevice. So, here are the files Microsoft has written, add them to your project.

GraphicsDeviceControl.cs
GraphicsDeviceService.cs

Now we will create a new control: Add>New Item>User Control, and call it something like RenderControl. The code is below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
using System.Diagnostics;
using System.Windows.Forms;
using Innovation;
using Microsoft.Xna.Framework;
 
namespace InnovationEditor
{
    public partial class RenderControl : GraphicsDeviceControl
    {
        // Simulate the GameTime ourselves because we don't have Game
        GameTime gameTime;
 
        // Elapsed and total time for the GameTime
        Stopwatch elapsedTime = new Stopwatch();
        Stopwatch totalTime = new Stopwatch();
 
        // Timer to keep track of refreshes
        Timer timer;
 
        // Camera, Keyboard, and Mouse will be handled here. They are
        // public and static so they can be used anywhere
        public static FPSCamera Camera;
        public static KeyboardDevice Keyboard;
        public static MouseDevice Mouse;
 
        public RenderControl()
        {
            // Run pre-generated control code
            InitializeComponent();
 
            // Start the timer keeping track of total elapsed time
            totalTime.Start();
 
            // Hook the mouse down event for the mousedevice, so the control
            // will be selected when clicked on. This avoids problems with
            // mouse and keyboard camera commands affecting other controls on
            // the form
            this.MouseDown += new MouseEventHandler(RenderControl_MouseDown);
        }
 
        // Select control on mouse down
        void RenderControl_MouseDown(object sender, MouseEventArgs e)
        {
            this.Select();
        }
 
        // Initialize the Control
        protected override void Initialize()
        {
            // Set up the engine
            Engine.SetupEngine(this.GraphicsServices);
 
            // Set up the frame update timer
            timer = new Timer();
 
            // Lock framerate to 40 so we can keep performance up
            timer.Interval = (int)((1f / 40f) * 1000);
 
            // Hook timer's tick so we can refresh the view on cue
            timer.Tick += new System.EventHandler(timer_Tick);
            timer.Start();
 
            // Setup the camera and move it to a good position, and make it a service
            Camera = new FPSCamera();
            Camera.RotateTranslate(new Vector3(0, 0, 0), new Vector3(128, 15, 300));
            Engine.Services.AddService(typeof(Camera), Camera);
 
            // Setup the keyboard and mouse, and allow the cursor to move
            Keyboard = new KeyboardDevice();
            Mouse = new MouseDevice();
            Mouse.ResetMouseAfterUpdate = false;
        }
 
        // Timer's tick causes the view to refresh
        void timer_Tick(object sender, System.EventArgs e)
        {
            // Invalidate everything so the whole control refreshes
            this.Invalidate();
 
            // Force the view update
            this.Update();
        }
 
        // Draw the scene
        protected override void Draw()
        {
            // Update GameTime and update the engine
            UpdateGameTime();
            Engine.Update(gameTime);
 
            // Update GameTime again and draw the scene
            UpdateGameTime();
            Engine.Draw(gameTime, ComponentType.All);
        }
 
        // Updates the GameTime object instead of relying on Game
        void UpdateGameTime()
        {
            // Recreate the GameTime with the current values
            gameTime = new GameTime(totalTime.Elapsed, totalTime.Elapsed, elapsedTime.Elapsed, elapsedTime.Elapsed);
 
            // Restart the elapsed timer that keeps track of time between frames
            elapsedTime.Reset();
            elapsedTime.Start();
        }
    }
}

Now, just go back to the main form, and drag a new RenderControl from the toolbox into our panel with the black border. If you can’t see RenderControl in the toolbox, you may need to build the project again. If you run the project now, you will see the familiar starting state of an XNA Game, the blank CornflowerBlue screen. It doesn’t look like much, but at least it’s working!

If you want to test this out, create some components in the constructor, and you should see that the engine operates the same way as it does in a normal game.



24 Responses to “XNA Game Editor Tutorial #1: Form, Render Control”

  1.   Dave1005 Says:
      March 26, 2009 at 4:33 pm

    Thanks for posting this before you left! Will give us something to work with while you’re on vacation.
    I’m having a problem though. What is the InitializeComponent() supposed to be calling. Should it be calling the Initialize() method later in the file or some external method?
    Second, where did the GraphicsService in the Initialize() method get created? I’m not sure if it should, by default, be created because RenderControl is a GraphicsDeviceControl.
    Third (I swear this is the last one), my RenderControl does not show up in the toolbox. Any ideas?
    Thanks again, and I hope you have fun in Peru. Look forward to the next tutorial.

    Dave1005

  2.   Dave1005 Says:
      March 26, 2009 at 4:35 pm

    Nevermind about the toolbox. Went back and re-read the beginning of the tutorial. Been doing this in pieces for the last two hours. Kinda forgot :)

  3.   Dave1005 Says:
      March 26, 2009 at 4:41 pm

    Alright, I’m really sorry to triple post, but forget that last comment. I still can’t get the toolbox to accept RenderControl…

  4.   ionine_ Says:
      March 26, 2009 at 6:10 pm

    I think you forgot to make the upload.innovativegames.net subdomain, ’cause keep getting a domain-not-found error. :(

    Great tutorial though, thanks again!

  5.   Chris Harshman Says:
      March 26, 2009 at 6:16 pm

    Can’t wait til you get back, only 4 months.

  6.   Sean Says:
      March 26, 2009 at 6:40 pm

    Sorry, I meant April, not August. 2 weeks, not 4 months… :)

  7.   Sean Says:
      March 26, 2009 at 6:51 pm

    Uploads are fixed.

  8.   Eibach06 Says:
      March 26, 2009 at 7:21 pm

    Hey thanks for posting this before you leave. Mine also does not show up in the toolbox and it says GraphicsDeviceControl cannont be built when i try to view the designer for RenderControl. It says it cannot be build because it is abstract…. any ideas?

    thanks again

  9.   Eibach06 Says:
      March 26, 2009 at 7:43 pm

    sorry, but also when you build the project, RenderControl.Designer.cs comes up with an error saying

    ‘TestApp_TestEnviornment.RenderControl’ does not contain a definition for ‘AutoScaleMode’ and no extension method ‘AutoScaleMode’ accepting a first argument of type ‘TestApp_TestEnviornment.RenderControl’ could be found (are you missing a using directive or an assembly reference?)

  10.   Eibach06 Says:
      April 1, 2009 at 3:55 pm

    Hey i think i figured it out you have to switch this option to true then it will show up in the tool box =)

    Tools > Options > Windows Forms Designer > General : AutoToolboxPopulate

  11.   David Says:
      April 11, 2009 at 6:35 am

    where I can get the source files for this tutorial?

  12.   Vonpoker.com Says:
      April 17, 2009 at 1:57 am

    Ok, did not follow you all the way there but I guess it’s good.

  13.   Sam Says:
      May 1, 2009 at 3:07 pm

    I’m getting the same “AutoScaleMode” error!

  14.   Clay Says:
      May 8, 2009 at 5:20 pm

    To get rid of the AutoScaleMode error, go into RenderControl.Designer.cs code file, and comment out the line:

    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

    Fixed the problem for me, not sure if it will cause any issues later though.

  15.   Eibach06 Says:
      May 9, 2009 at 8:04 pm

    Clay i did the same thing, seems to be fine.

    Also for anyone who is not being able to render try changing the project properties under the build tab to run on Platform: x86 and that should make it work =)

  16.   Dave1005 Says:
      May 10, 2009 at 6:06 pm

    I did everything everyone suggested: switched to x86, I update to the newest DirectX, commented out the line, but I am still getting the red X. Any more ideas? I am still getting the error about GraphicsDeviceControl being abstract. How did you get past it Eibach?

  17.   Clay Says:
      May 12, 2009 at 7:29 pm

    Hi Dave,

    Are you getting any exceptions when you run or stop the program?

    I am really curious how you can get the program to run if there is some problem with the GraphicsDeviceControl having an issue. Or maybe I mis-understand what you mean by the red X.

  18.   Dave1005 Says:
      May 13, 2009 at 11:56 am

    I am receiving a red x where I placed the RenderControl on the form. The error only appears if I close the form. If I stop debugging, then I do not receive an error.

  19.   Clay Says:
      May 23, 2009 at 5:10 am

    I am stumped actually. The only way I can get it to fail like that is if I run it in 64 bit mode, but you say you switched to x86. Sorry I can’t help ya.

  20.   Bob_Charming Says:
      June 7, 2009 at 3:18 am

    “Browse: InnovationEngine.dll”

    Where is this .dll?

  21.   Chris Harshman Says:
      June 11, 2009 at 11:58 am

    Has anyone come up with a fix yet for the red X over the render control?

  22.   mocode Says:
      June 17, 2009 at 6:47 pm

    I’ve got the same question as Bob. Where is the InnovationEngine.dll?

  23.   Iñaki Gauna Says:
      June 18, 2009 at 2:43 am

    Hi,
    In order to avoid the “AutoScaleMode” error, do this change in “GraphicsDeviceControl.cs”:
    // Control that draws to a windows form
    abstract public class GraphicsDeviceControl : UserControl //Control

    Regards!.
    Iñaki gauna.

  24.   Alex Says:
      October 21, 2009 at 9:01 am

    It may be a bit late for most people, but if anybody happens to have the red X problem (when running in debug mode the RenderControl appears as a red X), make sure you have x86 selected as the platform.

    NOTE: When I selected x86 it still didn’t work. Instead I had to go into the Configuration Manager (right-click on the solution) and make sure all projects are x86 (the editor project was Any CPU for me).

    And for anyone who is getting a “Could not load assembly error” on closing, this should solve it too.

    Also, the InnovationEngine.dll is in ..InnovationEngine\bin\x86\debug

comment Leave a Reply