[C#:XNA] Implementing XNA into form?

Started by G_G, January 01, 2011, 08:29:13 pm

Previous topic - Next topic

G_G

Hey guys. Another XNA question. I'm getting to the point where I need to start making my editors for GreGoR. I want to start with the map editor, its probably the most annoying to deal with, where everything else, can just be made in C# using forms and what not. Now I've tried making a map editor using a picturebox as the canvas, and using the Graphics class to crop tiles and paint them. Too slow. Way too slow.

So basically, I'm curious to how (if possible) to implement an xna game into a form. Thanks in advance.

winkio

Haha, I've been working on the same exact thing, although I have a few weeks head start.

I'll work on compiling everything I've got together, probably post it tomorrow.  I've got a fully functional game working now, so it should save you lots of trouble.

G_G


winkio

Using XNA in a Windows Forms Application

So, running an XNA game on it's own is easy, using the Game class.  Now we want to run it in a Windows Forms environment, perhaps as the graphical component to a larger application.  The first instinct may be to find some way to insert a Game Class into a Form.  Besides being completely impractical (although possible, I actually found somebody who did it), this is the wrong idea.  The Game class is meant as a standalone - it would be completely independent of any other controls on the form, which defeats the purpose of using it in the first place.  So, we have to build our own XNA environment.  Difficult, but not too difficult.



Step 1: Foundations

The main component any XNA environment needs is a Graphics Device.  The easiest and most useful place to create this is in a Control, which will fit nicely into the Forms framework.  Lucky for us, the code for this has already been provided in this sample project: http://create.msdn.com/en-US/education/catalog/sample/winforms_series_1.

Download the code, and copy ServiceContainer, GraphicsDeviceService, and GraphicsDeviceControl over to your project, making sure to edit their namespace to match your project.  Now, you have GraphicsDeviceControl, a control class that provides a GraphicsDevice for XNA to use.



Step 2: Content
Another key part of XNA is it's ability to load content.  If you have static content that you want to include with the program, just create a content project and reference it in the forms application.  However, if you are using a Forms application, chances are that you want to load content on the fly.  Now we have another sample project: http://create.msdn.com/en-US/education/catalog/sample/winforms_series_2.

This time, you just need ContentBuilder and Error Logger, although it may be useful to keep ModelViewerControl as a reference.  ContentBuilder has additional instructions in case you want to add pipeline assemblies for custom formats.  That takes care of dynamically loading content.



Step 3: Time
We seem to be so close, but we are so far away.  We don't have an Update function to work with, and we don't have a GameTime object to give us time.  Clearly, these are big problems.

Thankfully, we have the System.Diagnostics.Stopwatch class.  It keeps time in Ticks, which are 100 nanosecond intervals, but you don't really need to know that.  All that matters is that we have something that keeps time, so now we can have an update function that gets called at specific intervals.  To do this processing, we will use a function inside the top level control (the outermost one, called form1 by default) named MainLoop:

        /// <summary>
       /// Performs main processing for the form, maintaining a certain FPS.
       /// </summary>
       public void MainLoop()
       {
           //FPS set up
           double FPS = 30.0;
           long ticks1 = 0;
           long ticks2 = 0;
           double interval = (double)Stopwatch.Frequency / FPS;

           while (!this.IsDisposed)
           {
               Application.DoEvents();

               ticks2 = Stopwatch.GetTimestamp();
               if (ticks2 >= ticks1 + interval)
               {
                   // Insert timekeeper code here

                   // ---------------------------
                   ticks1 = Stopwatch.GetTimestamp();

                   UpdateXNA();
               }
           }
       }


This code uses the Stopwatch class to call a method named UpdateXNA() on precise intervals.  Now you just need to create your own UpdateXNA() method, and you have fully functioning XNA...

Except you are still missing a replacement for GameTime.  You need to know how much time has passed since the last update.  There are two solutions, but we will try the obvious one first.  Two lines before we call UpdateXNA(), where we see space to insert timekeeper code, we can store information in a float variable.  All frame-by-frame processing can be based off of this float value, which is measured in seconds.  You could simply pass it to UpdateXNA, or keep it as a public variable.  Here is the code:
float elapsedTime = ((float)(ticks2 - ticks1)) / Stopwatch.Frequency;


That is all good if you are starting from scratch, but if you are transferring code from a standalone project, you may need an instance of GameTime, as all your methods require it.  Again, this instance would be passed to your UpdateXNA function, to be passed around in your game.  In the timekeeper code area, we must instead insert different code:
GameTime g = new GameTime(new TimeSpan(ticks2), new TimeSpan(ticks2 - ticks1));


Now, for the finishing touch: you want this MainLoop to be running at all times.  There is a simple solution using only a bool variable and an Activate event:

        protected bool running;
       /// <summary>
       /// Start processing.
       /// </summary>
       private void MainForm_Activated(object sender, EventArgs e)
       {
           if (!running)
           {
               running = true;
               MainLoop(); //start the animation first time window appears
           }
       }


Just link the event in the forms editor, and everything should be running smoothly.  Congratulations, you just created an XNA environment.



Step 4: Working with Controls
Alright, the environment is set, let's get into it.  The first thing to do is to create a control to house your game.  The declaration could look like:
public class GameControl : GraphicsDeviceControl

simply give your class an UpdateXNA() function, possibly requiring either a float or a GameTime, and take it from there.

To place your control on the main form, open up the windows forms toolbox and scroll all the way up.  It should be sitting under a group named after your project.  Simply drag and drop, and resize as needed.  Of course, you can also add it using code, just like any other control.



Step 5: Interaction between XNA and Forms
Hey, wouldn't it be cool if other controls could interact with XNA?  Maybe a toolbar that loads savegames, or dynamic color changing panels.  In any case, you can give any custom control an UpdateXNA() function, which will link it to the same timing as the XNA environment.  You can also use this to have multiple XNA environments that are synchronized.



Author's Notes
Yeah, that was fun.  A week's worth or research summarized in a few pages.  Hopefully, this gives you enough options to allow you to implement whatever you want in XNA, whether it be a game, and rendering environment, or some other project.  There's a lot more to be said about manipulating 2D and 3D environments, but I'll save that for a little later when I've worked out a few more issues.

G_G

Like I once said to Blizz. If I were a hot blonde chick, I would be doing you right now. (:V?)

Thanks a ton winkio. This'll definitely help.

tSwitch

I'm thinking you wouldn't need to interact with XNA in all honesty.
You just need something that creates input that your XNA game expects.

However your map works, let's say a tile system with a .dat file that contains a matrix of numbers.
The numbers correspond to tiles.

You just need a GUI to create the tile map, which will export the .dat file that XNA uses.

Not to make Winkio's post any less useful if you get something from it, anyway.


FCF3a A+ C- D H- M P+ R T W- Z- Sf RLCT a cmn+++ d++ e++ f h+++ iw+++ j+ p sf+
Follow my project: MBlok | Find me on: tSwitch.us | Twitter | Tumblr

Ryex

the thing is that intra grating XNA into a form is probably the best way to create a GUI that can edit a map. the normal GDI+ drawing of a C# form is just way to slow. hence why I'm intra grating pygame into a wxpython form to display the map.
I no longer keep up with posts in the forum very well. If you have a question or comment, about my work, or in general I welcome PM's. if you make a post in one of my threads and I don't reply with in a day or two feel free to PM me and point it out to me.<br /><br />DropBox, the best free file syncing service there is.<br />

G_G

Quote from: NAMKCOR on January 13, 2011, 01:24:48 am
I'm thinking you wouldn't need to interact with XNA in all honesty.
You just need something that creates input that your XNA game expects.

However your map works, let's say a tile system with a .dat file that contains a matrix of numbers.
The numbers correspond to tiles.

You just need a GUI to create the tile map, which will export the .dat file that XNA uses.

Not to make Winkio's post any less useful if you get something from it, anyway.


Tried. C# is way too slow for that. ._. And with some success I got XNA implemented and I started on the map editor. I can scroll around the map. Thats basically it, haven't had much time to work on it.

Ryex

careful it's not C# thats too slow but the GDI and GDI+ (the basic windows drawing interface) it uses to draw that's too slow
I no longer keep up with posts in the forum very well. If you have a question or comment, about my work, or in general I welcome PM's. if you make a post in one of my threads and I don't reply with in a day or two feel free to PM me and point it out to me.<br /><br />DropBox, the best free file syncing service there is.<br />

aerobeast89

November 23, 2012, 06:14:16 am #9 Last Edit: November 23, 2012, 06:28:03 am by Blizzard
Hello,

I have been going this post "Using XNA in a Windows Forms Application" for the past few nights now, trying to get xna 4.0 working in a c# windows form application. I managed to get my content loaded and my control dragged on to my form, but I cant seem to get the UpdateXNA() to work.

I would really appreciate some help on this, I am really stuck. Do you have an example of a working UpdateXNA() method  with the standard xna Draw()?, or perhaps I am not doing this right:

Here is my code, following your example and the simple xna sprite movement example by microsoft:

Here is my main form (form 1):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna;


namespace testDynamicXNA2
{
 


   public partial class Form1 : Form
   {


   
     
       public Form1()
       {
           InitializeComponent();
           

       }

     
        public void MainLoop()
       {
           //FPS set up
           double FPS = 30.0;
           long ticks1 = 0;
           long ticks2 = 0;
           double interval = (double)Stopwatch.Frequency / FPS;

           while (!this.IsDisposed)
           {
               Application.DoEvents();

               ticks2 = Stopwatch.GetTimestamp();
               if (ticks2 >= ticks1 + interval)
               {
                   // Insert timekeeper code here
                   GameTime g = new GameTime(new TimeSpan(ticks2), new TimeSpan(ticks2 - ticks1));
                   // ---------------------------
                   ticks1 = Stopwatch.GetTimestamp();

                   testControl4.UpdateXNA(g);
               }
           }
       }

        protected bool running;
        private void Form1_Activated(object sender, EventArgs e)
        {
            if (!running)
            {
                running = true;
                MainLoop(); //start the animation first time window appears
            }
        }

   

   }
}



and here is my xna control that is dragged onto the form:

#region Using Statements
using System.Diagnostics;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;

using System.Linq;
using System.Text;


using Microsoft.Xna;


#endregion

namespace testDynamicXNA2
{
 
   class testControl : GraphicsDeviceControl
   {
       ContentManager content;
       SpriteBatch spriteBatch;

       // This is a texture we can render.
       Texture2D myTexture;

       // Set the coordinates to draw the sprite at.
       Vector2 spritePosition = new Vector2(23, 23);

       // Store some information about the sprite's motion.
       Vector2 spriteSpeed = new Vector2(50.0f, 50.0f);




   

       /// <summary>
       /// Initializes the control, creating the ContentManager
       /// and using it to load a SpriteFont.
       /// </summary>
       protected override void Initialize()
       {
           content = new ContentManager(Services, "Content");

           spriteBatch = new SpriteBatch(GraphicsDevice);

       
           myTexture = content.Load<Texture2D>("Horizon1");

       }




      public  void UpdateXNA(GameTime gameTime)
       {
           spritePosition +=
               spriteSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;

           int MaxX =
               GraphicsDevice.Viewport.Width - myTexture.Width;
           int MinX = 0;
           int MaxY =
               GraphicsDevice.Viewport.Height - myTexture.Height;
           int MinY = 0;

           // Check for bounce.
           if (spritePosition.X > MaxX)
           {
               spriteSpeed.X *= -1;
               spritePosition.X = MaxX;
           }

           else if (spritePosition.X < MinX)
           {
               spriteSpeed.X *= -1;
               spritePosition.X = MinX;
           }

           if (spritePosition.Y > MaxY)
           {
               spriteSpeed.Y *= -1;
               spritePosition.Y = MaxY;
           }

           else if (spritePosition.Y < MinY)
           {
               spriteSpeed.Y *= -1;
               spritePosition.Y = MinY;
           }

         
       
       }


     
   

       /// <summary>
       /// Draws the control, using SpriteBatch and SpriteFont.
       /// </summary>
       protected override void Draw( )
       {


           GraphicsDevice.Clear(Color.CornflowerBlue);
           spriteBatch.Begin();
           spriteBatch.Draw(myTexture, spritePosition, Color.White);
           spriteBatch.End();
       
       }
   }
}


Am I doing this right?

Thanks,

Brien

Blizzard

Please use [code] tags for code. *fixes*
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

G_G


winkio

November 23, 2012, 06:07:25 pm #12 Last Edit: November 25, 2012, 08:02:11 pm by winkio
@aerobeast89: I replied to your pm.  Code looks right, but I wonder if you didn't set the event in the forms designer.

EDIT: problem was resolved, needed an Invalidate() call in the UpdateXNA method.  I forgot that I made something this useful, I think I'll work on making a small demo to go with it and put it in the database.

Cmason9260

I know this is an older topic, but has anyone got this to work with 3D? I can draw sprites and fonts. But when I try and do a camera and a model, It doesn't work. I just get an empty frame. Just curious if any one has done this, and of so, do you have any suggestions.

Thanks in advance.

winkio

Yes, 3D works exactly the same in forms as in standard XNA.  I'm pretty sure there is 3D graphics in the official XNA in WinForms demo if you want to use it as a reference.

Cmason9260

Thanks. I actually just figured out my issue. It was just a simple typo  :facepalm:

Moving along great now.