0
\$\begingroup\$

I have three projects in one solution:

  • a form with some tool (see it as a level-editor), in which there is PictureBox where I want to redirect drawing of the game.
  • My game, with some methods and its Update/Draw methods:
  • A launcher (where I can start the game or start the level-editor)
 protected override void Update(GameTime gameTime) {...}
 protected override void Draw(GameTime gameTime) {...}

This is the launcher's "Open game in editor mode" button code:

private void cmdEditorMode_Click(object sender, EventArgs e)
{
    using (Game1 game_instance = new Game1(true))
    {
        using (MapEditor form = new MapEditor())
        {
            form.Show();
            form.game_wrapper = new GameWrapperForLevelEditor(
                game_instance,
                form.pctSurface.Handle,
                form,
                form.pctSurface);
            game_instance.Run();
        }
    }
}

Note that:

  • true in Game1 constructor is just a bool used to tell the game to open it in editor mode.
  • GameWrapperForLevelEditor is another class used to make the form of the level editor and the Game itself in relation.

In particular (to draw inside the pictureBox drawSurface):

 public GameWrapperForLevelEditor(
            Game1 game,
            IntPtr drawSurface,
            System.Windows.Forms.Form parentForm,
            System.Windows.Forms.PictureBox surfacePictureBox)
        {
            graphics = new GraphicsDeviceManager(this);
            //...
            //...other things
            //...
            graphics.PreparingDeviceSettings +=
                new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);
        }

and:

 void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
 {
    e.GraphicsDeviceInformation.PresentationParameters.DeviceWindowHandle = drawSurface;
 }

This is the launcher's Main code:

using System;
namespace Launcher
{
#if WINDOWS || XBOX
    static class MAIN
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main(string[] args)
        {
            using (Launcher_form form = new Launcher_form())
            {
                form.Show();
                //Creo un'istanza del picture_box_render all'interno del form
                form.picture_box_render = new launcher_picture_render(form.pctLauncher.Handle);
                form.picture_box_render.Run();
            }
        }
    }
#endif
}

Note that:

  • I use here another game (picture_box_render) because in my launcher's form I put a picture box where I want to run an animation that is rendered as another game loop.

Finally the draw part:

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.Black);

    spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
    spriteBatch.Draw(game.LastRender, Vector2.Zero, Color.White);
    spriteBatch.End();

    base.Draw(gameTime);
}

My problems are:

  • game_instance.Run(); (up) gives me this error (translated from italian, so sorry):

Starting a second message loop on a single thread is not valid operation Use Form.ShowDialog.

  • game.LastRender is Always empty because the game never run. game.LastRender is just a RenderTarget2D where Game1 draw method draws the game.

As a solution, I thought that I may don't game_instance.Run();, but just use game.Update(...) and game.Draw(...) inside my wrapper class. The problem is that these two methods are protected, and if I try to set them public it says me that I can't.

What am I doing wrong?

\$\endgroup\$
1
\$\begingroup\$

You should use the official sample. It demonstrates exactly how to get XNA to output inside WinForms.

Any other method for doing this is almost certainly wrong and will either fail outright, or fail unexpectedly in certain circumstances.


To use the official sample, you will have to extricate your existing code from the Game class. This means you must implement your own Draw and Update methods, your own timing mechanism (you can use System.Diagnostics.Stopwatch), and possibly a replacement for GameComponent (if you use it).

I find it helps to separate your game into three projects: A shared "engine" XNA library, a "game" XNA project, and an "editor" WinForms project.

Then use the "game" and "editor" simply as thin wrappers for setting up the graphics device and calling your own Update and Draw methods on your own class in your "engine" project.

If you want a launcher, it's probably best to create a fourth project to contain it. I'd simply have it invoke the selected executable.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks a lot! A last question: inside another project, what's the instruction to invoke an executable? \$\endgroup\$ – Francesco Bonizzi Dec 8 '13 at 21:56
  • 1
    \$\begingroup\$ System.Diagnostics.Process.Start. \$\endgroup\$ – Andrew Russell Dec 9 '13 at 4:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.