XNA Creators Club Online
Page 1 of 1 (3 items)
Sort Posts: Previous Next

A good way to embed the game class in a form (solution)

Last post 27/11/2007 14:43 by NightMarez. 2 replies.
  • 26/11/2007 19:35

    A good way to embed the game class in a form (solution)

    I often see many posts on here from people that want to put the game's window inside a form.  This is useful for editor applications, and so is the game class, which is why combining these two is a great idea (sometimes).

    This is the form load method for one of the forms in my application, it creates the game class:

            public RenderWindow()
    {
    InitializeComponent();

    // create the game
    game = new PGEGame();
    game.IsMouseVisible = true;

    // force the game to run in a window
    IGraphicsDeviceManager graphicsDeviceManager = game.GetService<IGraphicsDeviceManager>();
    graphicsDeviceManager.CreateDevice();

    // beginDraw() relies on this
    game.GetType().BaseType.GetField("graphicsDeviceManager",
    System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(game, graphicsDeviceManager);

    // embed the render window into this form
    Form form = game.Form;
    form.FormBorderStyle = FormBorderStyle.None;
    form.Dock = DockStyle.Fill;
    form.TopLevel = false;
    form.Parent = this;
    form.Visible = true;
    Controls.Add(form);

    // handle resize event for render window
    game.Window.ClientSizeChanged += new EventHandler(Window_ClientSizeChanged);

    // handle Application events
    System.Windows.Forms.Application.Idle += new EventHandler(Application_Idle);

    // NOTE: you could create components here...

    // call Initialize and BeginRun
    game.GetType().BaseType.GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(game, null);
    game.GetType().BaseType.GetMethod("BeginRun", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(game, null);

    // get the gametime and call the first update
    GameTime gt = game.GetType().BaseType.GetField("gameTime",
    System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(game) as GameTime;
    game.GetType().BaseType.GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(game, new Object[] { gt });

    // set doneFirstUpdate to true
    game.GetType().BaseType.GetField("doneFirstUpdate",
    System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(game, true);
    }

    PGEGame has the following member that is important here:

    #if !(XBOX360)

    public Form Form
    {
    get { return Form.FromHandle(Window.Handle) as Form; }
    }

    #endif

    Which returns the GameWindow as a Form.  You also need the following methods in the Form that contains the game:

            protected override void Dispose(bool disposing)
    {
    base.Dispose(disposing);

    System.Windows.Forms.Application.Idle -= Application_Idle;
    }

    void Application_Idle(object sender, EventArgs e)
    {
    while (AppStillIdle())
    game.Tick();
    }

    private bool AppStillIdle()
    {
    NativeMethods.Message msg;
    return !(NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0));
    }

    void Window_ClientSizeChanged(object sender, EventArgs e)
    {
    GameWindow window = game.Window;
    if (game.Window.ClientBounds.Width != 0 && game.Window.ClientBounds.Height != 0)
    game.SetAspectRatio(game.Window.ClientBounds);
    }


    And you need the following structure to examine messages:

        static class NativeMethods
    {
    [StructLayout(LayoutKind.Sequential)]
    public struct Message
    {
    public IntPtr hWnd;
    public UInt32 msg;
    public IntPtr wParam;
    public IntPtr lParam;
    public UInt32 time;
    public Point p;
    }

    [SuppressUnmanagedCodeSecurity] // We won't use this maliciously
    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);
    }

    The form should implement IDisposable so it can release its event handler for Application.Idle.  This is essentially creating the game and not calling run, letting the application render the game when it's not busy.  It performs good enough for me, I have not tested it for speed and since this is usually for editing applications, speed is not the primary focus.  The above sample is primarily based on code posted by not_a_commie @ http://forums.xna.com/post/10166.aspx
  • 27/11/2007 14:08 In reply to

    Re: A good way to embed the game class in a form (solution)

    About time we FAQd this winform stuff - started list here http://forums.xna.com/thread/34180.aspx
    Play Kissy Poo - a game for 4 year olds on Xbox and windows
    The ZBuffer
    News and information for XNA
      Follow The Zman on twitter, Email me
        Please read the forum FAQs - Bug/Feature reporting
          Don't forget to mark good answers and good playtest feedback when you see it!!!
  • 27/11/2007 14:43 In reply to

    Re: A good way to embed the game class in a form (solution)

    cant get this to work xD im stupid i think :)

    Knowledge is power, power corrupts. Study hard, be evil.!
Page 1 of 1 (3 items) Previous Next