• Advertisement
Sign in to follow this  

[.net] Gametime class in a windows app

This topic is 4039 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi online, Im trying to develop a level designer for my xna project. Obviously this has to be done in windows. Unfortunately most of my classes use the Gametime class that is sent to the Draw and Update functions of the Game class. Since im doing a Windows project, I dont have any Gametime to work with, because Im not using a Game class. I tried creating a new Gametime object but it does not update, and I dont know how to get it to update. Can anyone give me some suggestions? Thanks

Share this post


Link to post
Share on other sites
Advertisement
Hmm, that brings up a good question ... I thought for sure that GameTime would either be a struct, or allow you to update it's methods. However, a little bit of casual inspection of the meta data shows that it is in fact a class (Reference type), and the only way to set it's values are to call the constructor.

So that suggests to me that one is being new'd up every frame? that's crazy talk.

Share this post


Link to post
Share on other sites
Yeah I know. I really dont want to write a new timer when there is already one that we should use anyway built into XNA.

Share this post


Link to post
Share on other sites
The GameTime is used by Game to handle the timing of the loop. So you can't use GameTime without having Game in the project. What I am wondering is why you are not using Game? Yes there is some extra over head but I think that you could use it to make things a bit simpler.

My idea; Create a standard window's app. Create a new thread for the Game object. Let the Game object run over there taking care of your drawing and all the XNA world. Have the main thread for your Level designer.

theTroll

Share this post


Link to post
Share on other sites
How exactly do you do that? Because the game class does not have a normal windows form. So how do you tell it to render (in my case anyway) to a panel inside a windows form?
Thanks again for any help.

Share this post


Link to post
Share on other sites
SavyCat - do you actually need your objects Updating in the editor? It seems like in that context, an all-zeros GameTime would work fine because in the editor its sorta always time index 0. Things should draw fine - they'll just be inert.

But if you want a nice timer, you can swipe the one in the Sample Frameworks source code. (DX SDK Install Dir)\Samples\Managed\Common\dxmutmisc.cs Then you can drive it with a regular old Timer control. The raft of calcs you have to make to get the constructor params set up are a bit of a chore. I wrote the code once, a while back but I don't know if I still have it - I changed my plumbing around to decouple my model from XNA. I'll take a look around and will post if I find it.

On the other hand, why not just make the editor a Game just like the actual game. I don't know if you have to put some sort of Do Events in the game's pump functions so that the Windows.Forms objects can process their messages. I've never done this myself but I've heard other people mention doing it.

Quote:
Original post by joelmartinez
So that suggests to me that one is being new'd up every frame? that's crazy talk.


It must have "internal" members back inside the XNA assemblies. I just checked and its the same instance being provided each call:


private GameTime lastGameTime = null;

protected override void Update(GameTime gameTime)
{
if (lastGameTime == null)
lastGameTime = gameTime;
else
{
if (object.ReferenceEquals(lastGameTime, gameTime))
{
// it stops on a break point set here
int wtf = 4;
}
}

base.Update(gameTime);
}


[Edited by - dalep on January 28, 2007 11:45:16 AM]

Share this post


Link to post
Share on other sites
Got a possible solution for you. This will allow your XNA Game window to be fully active while having complete access to the editor at the same time.


#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace XNACore
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
ContentManager content;

private System.Windows.Forms.Form form;
private Microsoft.Xna.Framework.Graphics.Viewport xnaViewport1;
private System.Windows.Forms.Panel panelLeft;
private System.Windows.Forms.Panel panelRightBottom;

private System.Windows.Forms.Button button1;


public Game1()
{
graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);

}


/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here

base.Initialize();

xnaViewport1 = new Viewport();
xnaViewport1.X = this.Window.ClientBounds.Width/2;
xnaViewport1.Y = 0;
xnaViewport1.Width = this.Window.ClientBounds.Width / 2;
xnaViewport1.Height = this.Window.ClientBounds.Height / 2;

this.graphics.GraphicsDevice.Viewport = xnaViewport1;


IntPtr ptr = this.Window.Handle;
form = (System.Windows.Forms.Form)System.Windows.Forms.Control.FromHandle(ptr);

panelLeft = new System.Windows.Forms.Panel();
panelLeft.Width = this.Window.ClientBounds.Width / 2;
panelLeft.Height = this.Window.ClientBounds.Height;
panelLeft.Top = 0;
panelLeft.Left = 0;

form.Controls.Add(panelLeft);

panelRightBottom = new System.Windows.Forms.Panel();
panelRightBottom.Width = this.Window.ClientBounds.Width / 2;
panelRightBottom.Height = this.Window.ClientBounds.Height / 2;
panelRightBottom.Top = this.Window.ClientBounds.Height / 2;
panelRightBottom.Left = this.Window.ClientBounds.Width / 2;

form.Controls.Add(panelRightBottom);

button1 = new System.Windows.Forms.Button();
button1.Text = "It works!!!";
button1.Top = 20;
button1.Left = 20;

panelLeft.Controls.Add(button1);




}


/// <summary>
/// Load your graphics content. If loadAllContent is true, you should
/// load content from both ResourceManagementMode pools. Otherwise, just
/// load ResourceManagementMode.Manual content.
/// </summary>
/// <param name="loadAllContent">Which type of content to load.</param>
protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
// TODO: Load any ResourceManagementMode.Automatic content
}

// TODO: Load any ResourceManagementMode.Manual content
}


/// <summary>
/// Unload your graphics content. If unloadAllContent is true, you should
/// unload content from both ResourceManagementMode pools. Otherwise, just
/// unload ResourceManagementMode.Manual content. Manual content will get
/// Disposed by the GraphicsDevice during a Reset.
/// </summary>
/// <param name="unloadAllContent">Which type of content to unload.</param>
protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent == true)
{
content.Unload();
}
}


/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the default game to exit on Xbox 360 and Windows
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

// TODO: Add your update logic here

base.Update(gameTime);
}


/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.Blue);

// TODO: Add your drawing code here






base.Draw(gameTime);
}
}
}




I have tested it and everything seems to work just great.

theTroll

Share this post


Link to post
Share on other sites
Decided to clean up the code a bit and make it a bit more organize and easier to use. If you have any questions let me know.



#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace XNACore
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
ContentManager content;

private System.Windows.Forms.Form form;
private Microsoft.Xna.Framework.Graphics.Viewport xnaViewport;

#region Left Panel Controls
private System.Windows.Forms.Panel panelLeft;
private System.Windows.Forms.Button button1;

#endregion

#region Right Bottom Panel Controls
private System.Windows.Forms.Panel panelRightBottom;

#endregion


public Game1()
{
graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);

}


/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here

base.Initialize();

Init_Viewport();

Init_Windows_Controls();

}


/// <summary>
/// Load your graphics content. If loadAllContent is true, you should
/// load content from both ResourceManagementMode pools. Otherwise, just
/// load ResourceManagementMode.Manual content.
/// </summary>
/// <param name="loadAllContent">Which type of content to load.</param>
protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
// TODO: Load any ResourceManagementMode.Automatic content
}

// TODO: Load any ResourceManagementMode.Manual content
}


/// <summary>
/// Unload your graphics content. If unloadAllContent is true, you should
/// unload content from both ResourceManagementMode pools. Otherwise, just
/// unload ResourceManagementMode.Manual content. Manual content will get
/// Disposed by the GraphicsDevice during a Reset.
/// </summary>
/// <param name="unloadAllContent">Which type of content to unload.</param>
protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent == true)
{
content.Unload();
}
}


/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the default game to exit on Xbox 360 and Windows
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

// TODO: Add your update logic here

base.Update(gameTime);
}


/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.Blue);

// TODO: Add your drawing code here






base.Draw(gameTime);
}

private void Init_Viewport()
{
xnaViewport = new Viewport();
xnaViewport.X = this.Window.ClientBounds.Width / 2;
xnaViewport.Y = 0;
xnaViewport.Width = this.Window.ClientBounds.Width / 2;
xnaViewport.Height = this.Window.ClientBounds.Height / 2;

this.graphics.GraphicsDevice.Viewport = xnaViewport;
}


private void Init_Windows_Controls()
{
// Get the windows form based on the Game Window
IntPtr ptr = this.Window.Handle;
form = (System.Windows.Forms.Form)System.Windows.Forms.Control.FromHandle(ptr);

#region Left Panel Init
panelLeft = new System.Windows.Forms.Panel();
panelLeft.Width = this.Window.ClientBounds.Width / 2;
panelLeft.Height = this.Window.ClientBounds.Height;
panelLeft.Top = 0;
panelLeft.Left = 0;

form.Controls.Add(panelLeft);
#endregion

#region Left Panel Controls Init
button1 = new System.Windows.Forms.Button();
button1.Text = "It works!!!";
button1.Top = 20;
button1.Left = 20;

panelLeft.Controls.Add(button1);


#endregion

#region Left Panel Controls Event Handlers
button1.Click += new EventHandler(button1_Click);
#endregion

#region Right Bottom Panel Init
panelRightBottom = new System.Windows.Forms.Panel();
panelRightBottom.Width = this.Window.ClientBounds.Width / 2;
panelRightBottom.Height = this.Window.ClientBounds.Height / 2;
panelRightBottom.Top = this.Window.ClientBounds.Height / 2;
panelRightBottom.Left = this.Window.ClientBounds.Width / 2;

form.Controls.Add(panelRightBottom);
#endregion

#region Right Bottom Panel Control Init

#endregion

#region Right Bottom Panel Controls Event Handlers

#endregion
}

void button1_Click(object obj, EventArgs ea)
{
System.Windows.Forms.MessageBox.Show("See, told you it works");
}
}
}




Not sure if it is what you wanted, but I tried. :)

Anyone's comments on this idea are much appriciated.

theTroll

Share this post


Link to post
Share on other sites
Don't mean to be the moralizing party-pooper, but Shawn Hargreaves blogged about this last week and he recommended not using the Game class for rendering into Windows Form controls:

Quote:
Just say no! If you want to render into a custom window, don't use the Game class. It will be much easier and more reliable to directly create your own GraphicsDevice object.


He goes on to point out some source code on how to create your own IGraphiscDeviceService to bind your content manager to and how to set up your own render loop. I've followed these easy instructions and with a bit of tinkering you can set up a framework that should allow your game to run both in your Windows Forms editor as well as through the Game class without any recoding. One thing to change in the example code is dropping the Timer based render loop and use the good ol' AppStillIdle loop instead to make better use of your CPU resources.

Unfortunately neither Shawn nor the sample code go into fetching the GameTime for your updates, but I've worked around this by setting up 2 System.Diagnostics.Stopwatch objects as timers. One will never be stopped and measures the real time part of the GameTime. The other timer will be paused as the game is paused, which makes up the actual game time part of the GameTime object. In case anyone's wondering, the Stopwatch mimics the DirectX framework timer (using QueryPerformanceCounter) and hence has a better time resolution than the system TickCount.

The only thing I'm worrying about is that with this approach you will need to create a new GameTime object every frame, since the class does not seem to expose methods or properties for updating the existing object. Ideally I'd like to keep a single GameTime object around to update every frame and pass on into the underlying components. I've thought about just passing in the timespans (or just seconds as floats), but I'd like to stick as close to the original XNA way of doing things as possible.


Edit: just checked with Reflector and the setter for the GameTime properties are indeed internal. I've created a MS Connect feedback item to have these changed to 'protected internal', so we could create our own updatable GameTime subclass, without exposing the undesirable behavior of being able to change normal GameTime object. Please vote for the report here if you agree [smile]

[Edited by - remigius on January 29, 2007 3:48:23 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by remigius
Don't mean to be the moralizing party-pooper, but Shawn Hargreaves blogged about this last week and he recommended not using the Game class for rendering into Windows Form controls:

Quote:
Just say no! If you want to render into a custom window, don't use the Game class. It will be much easier and more reliable to directly create your own GraphicsDevice object.


He goes on to point out some source code on how to create your own IGraphiscDeviceService to bind your content manager to and how to set up your own render loop. I've followed these easy instructions and with a bit of tinkering you can set up a framework that should allow your game to run both in your Windows Forms editor as well as through the Game class without any recoding. One thing to change in the example code is dropping the Timer based render loop and use the good ol' AppStillIdle loop instead to make better use of your CPU resources.

Unfortunately neither Shawn nor the sample code go into fetching the GameTime for your updates, but I've worked around this by setting up 2 System.Diagnostics.Stopwatch objects as timers. One will never be stopped and measures the real time part of the GameTime. The other timer will be paused as the game is paused, which makes up the actual game time part of the GameTime object. In case anyone's wondering, the Stopwatch mimics the DirectX framework timer (using QueryPerformanceCounter) and hence has a better time resolution than the system TickCount.

The only thing I'm worrying about is that with this approach you will need to create a new GameTime object every frame, since the class does not seem to expose methods or properties for updating the existing object. Ideally I'd like to keep a single GameTime object around to update every frame and pass on into the underlying components. I've thought about just passing in the timespans (or just seconds as floats), but I'd like to stick as close to the original XNA way of doing things as possible.


Edit: just checked with Reflector and the setter for the GameTime properties are indeed internal. I've created a MS Connect feedback item to have these changed to 'protected internal', so we could create our own updatable GameTime subclass, without exposing the undesirable behavior of being able to change normal GameTime object. Please vote for the report here if you agree [smile]



remigius, I am guessing you either didn't read my code or you didn't understand what I did. I am NOT using the Game class for rendering into Windows Form controls. But wait you said you are using the Game class and windows controls together? Well yes I did. I first went to add the Game class and GameWindow to a standard windows application and fairly quickly realized that would be a very bad idea. So I started playing around with some ideas trying to figure out an easy way to build a game designer. I realized instead of putting a Game class into a windows app we could use windows controls onto a GameWindow. We keep all the functionality of the Game class, without any hacks and add the ease of using windows controls. I don't have to create my own gameloop, I don't have to create a new GameTime every frame and I don't have to create my own IGraphiscDeviceService. Now there might be a major down side to this that I am missing but so far I have not seen it.

theTroll

Share this post


Link to post
Share on other sites
I'm just working on a custom XNA render control myself so I thought I'd chime in. Perhaps I was a bit overzealous though, for which I apologize.

Anyway, I did realize you were reusing the existing Form that's constructed by the Game class, but I think Shawn's advice applies here as well. With your solution you are getting the correct rendering size, but I think (please correct me if I'm wrong) you're losing quite some performance since the backbuffer is still set to the full size of the Form. You also don't have too much control over your form, device creation and render loop, which was a downside for me.

Obviously this all doesn't need to be a huge problem, but since the alternative is easy enough I went with that. With one of the XNA platform programmers advocating it, it can't be too much of a hack. The only thing that's indeed a bit of a problem is the GameTime thingy... So please vote [smile]

Share this post


Link to post
Share on other sites
I was not offended but thanks for the appology anyway. :)

I see your point about the backbuffer, but I thought that by using a viewport that issue would be avoided, I could be completely wrong on that. So I was thinking about what you said and decided that I really didn't know enough to make the decission on if this is a good idea or not.

So I sent Shawn Hargreaves an email, telling him my idea and asking what were the problems with doing it this way. I will let you know if/when I get a response.

theTroll

Share this post


Link to post
Share on other sites
Just got a response from Shawn. He said the way that I am doing it is quite feasable. Now with that being said, he said, by not using the GraphicsDevice and writing my own loop I will be limiting some of what is possible doing it the other way. I specifically asked about performace issues and he never said that there would be any doing it this way.

Just wanted to update folks on what he said.

theTroll

Share this post


Link to post
Share on other sites
Odd, I recall reading a discussion that did mention some performance issues. Ah well, there's no arguing with Shawn [smile] Thanks for sharing the feedback!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement