您好我正在尝试使用本教程在我的项目中嵌入一个XNA模块,这是一个Windows窗体应用程序: http://create.msdn.com/en-US/education/catalog/sample/winforms_series_1。 我想这是最简单的练习教程,所以我决定跟上它。
当我需要GameTime时出现问题,在他们的XNA控件的实现中,GameTime不存在。我试图在谷歌寻找一个快速的解决方案,并试图找到一个解释如何在常规XNA游戏中实现GameTime,但我发现的信息越来越多,我变得更加困惑...... 以下是问题:
在常规XNA游戏GameTime.ElapsedGameTime中,描述说明“自上次更新以来经过的游戏时间。” - 那是什么意思?它是否给出了经过的毫秒数?但这没有任何意义,因为图纸和更新之间有一个恒定的时间跨度,它每16毫秒或多或少发生..对我来说似乎毫无意义,我想在这里做一点解释。我知道ElapsedGameTime在使用线性插值平滑运动方面发挥了重要作用,但如果它的最大值大约是16ms则没有任何意义
在XNA控件中是否有完全GameTime的实现?如果没有,那么在Windows窗体中模拟GameTime的最佳做法是什么?
很抱歉,如果我之前已经提出过我的问题,那对我来说真的很重要,并且已经尝试根据Google搜索获得答案,但未能获得任何明确的答案
答案 0 :(得分:1)
GameTime
提供自上次更新以来经过的固定或可变时间,自游戏开始以来的总时间以及与目标效果相关的IsRunningSlowly
标记。
这是一篇关于WinForms中游戏计时器的好文章:When WinForms met Game Loop
答案 1 :(得分:0)
如果您选择使用可变时间步,则GameTime
结构更相关。默认情况下,XNA运行固定的时间步长(因此在正常情况下所有更新都会定期发生)。
我猜你需要一个GameTime
,因为你想要不仅根据用户输入刷新控件(比如游戏,即使用户没有碰到任何东西,也会发生事情)。
在这种情况下,一种简单的方法是在表单上设置一个定时器控件,简单地调用更新/渲染函数。您将计时器的间隔传递给您的功能。您可以使用XNA中的函数通常接受GameTime
只接受double或float等。或者您可以根据间隔自己创建GameTime
。
另一种选择是创建另一个尝试尽可能快地更新的线程(可能达到一个点)。然后,这将在UI线程上引发回调,这将进行更新/呈现。处理GameTime
将与上述相似,因为您可以记录上次运行的时间,并将当时和现在之间的差异作为时间增量传递。
答案 2 :(得分:0)
GameTime。ElapsedGameTime为您提供了一个TimeSpan对象,您可以在其中检索您想要的任何时间单位,包括(但不限于){{3}的毫秒数属性。
TimeSpan始终相同的原因是因为默认情况下XNA使用固定的时间步长。您可以通过设置TotalMiliseconds属性来更改此项,因为Dmitry在评论中指出了这一点。关于此问题Game.IsFixedTimeStep中的时间步长以及实现它们的一些代码,我们进行了很好的讨论。
答案 3 :(得分:0)
这段代码效果很好,唯一的区别是游戏类中的构造函数,其余的就像是一个普通的xna游戏。
这是我用于此editor for 2D sprites and skeletal animations
的代码<强> Program.cs的强>
namespace SpriteEditor
{
#if WINDOWS
static class Program
{
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles( );
Application.SetCompatibleTextRenderingDefault( false );
XnaControlGame.CreateAndShow<SkeletonManagerDialog, SkeletonXnaGame>( );
}
}
#endif
<强>表格强>
public partial class SkeletonManagerDialog : Form, IXnaFormContainer
{
public Control XnaControl { get { return spriteBoneEditor1.XnaPicture; } }
public XnaControlGame Game { get; set; }
....
}
XnaGame
public partial class SkeletonXnaGame : XnaControlGame
{
public SkeletonXnaGame( IntPtr ptr, Form form, Control control )
: base( ptr, form, control ) { }
//--------------------------------------------------------------------------
protected override void Update( GameTime gameTime )
{
float Seconds = ( float ) gameTime.ElapsedGameTime.TotalSeconds;
HandleMouse( );
if ( TryHandleCamera( ) ) return;
if ( MouseIsInsideViewport) HandleLeftClick( Seconds );
if ( SkeletonManager.SelectedBone != null ) UpdateSelectedBone( Seconds );
if ( SkeletonManager.SelectedShape != null ) UpdateSelectedShape( Seconds );
if ( SkeletonManager.CurrentSequence != null ) SkeletonManager.CurrentSequence.Update( Seconds );
base.Update( gameTime );
}
....
}
<强> XnaControlGame.cs 强>
using System;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace SpriteEditor
{
public interface IXnaFormContainer
{
Control XnaControl { get; }
XnaControlGame Game { get; set; }
}
public abstract class XnaControlGame : Microsoft.Xna.Framework.Game
{
public Control Parent { get; private set; }
public static void CreateAndShow<T, Q>( )
where T : Form, IXnaFormContainer, new( )
where Q : XnaControlGame
{
using ( T form = new T( ) )
{
form.Show( );
using ( Q game = ( Q ) Activator.CreateInstance( typeof( Q ), new object[] { form.XnaControl.Handle, form, form.XnaControl } ) )
{
form.Game = game;
game.Parent = form.XnaControl;
game.Run( );
}
}
}
#region Private Vars to Build Embedded Xna Control
IntPtr _XnaDrawingSurface;
GraphicsDeviceManager graphics;
System.Windows.Forms.Form parentForm;
System.Windows.Forms.Control controlXna;
System.Windows.Forms.Control gameForm;
#endregion
#region Constructor
public XnaControlGame( IntPtr handle,
System.Windows.Forms.Form parentForm,
System.Windows.Forms.Control surfaceControl )
{
graphics = new GraphicsDeviceManager( this );
graphics.GraphicsProfile = GraphicsProfile.Reach;
Content.RootDirectory = "Content";
this.parentForm = parentForm;
this.controlXna = surfaceControl;
gameForm = System.Windows.Forms.Control.FromHandle( this.Window.Handle );
gameForm.VisibleChanged += new EventHandler( gameForm_VisibleChanged );
controlXna.SizeChanged += new EventHandler( pictureBox_SizeChanged );
// preparing device settings handler.
_XnaDrawingSurface = handle;
Mouse.WindowHandle = handle;
graphics.PreparingDeviceSettings += OnPreparingDeviceSettings;
graphics.PreferredBackBufferWidth = (controlXna.Width > 0) ? controlXna.Width : 50;
graphics.PreferredBackBufferHeight = (controlXna.Height > 0) ? controlXna.Height : 50;
parentForm.FormClosed += delegate( object sender, System.Windows.Forms.FormClosedEventArgs e )
{
this.Exit( );
Application.Exit( );
};
}
#endregion
#region Events
private void OnPreparingDeviceSettings( object sender, PreparingDeviceSettingsEventArgs e )
{
e.GraphicsDeviceInformation.PresentationParameters.DeviceWindowHandle = _XnaDrawingSurface;
}
private void gameForm_VisibleChanged( object sender, EventArgs e )
{
if ( gameForm.Visible == true )
gameForm.Visible = false;
}
void pictureBox_SizeChanged( object sender, EventArgs e )
{
if ( parentForm.WindowState !=
System.Windows.Forms.FormWindowState.Minimized )
{
graphics.PreferredBackBufferWidth = controlXna.Width;
graphics.PreferredBackBufferHeight = controlXna.Height;
graphics.ApplyChanges( );
OnSizeChanged( );
}
}
protected virtual void OnSizeChanged( ) { }
#endregion
}
}
答案 4 :(得分:0)
在幕后,Xna提供了将时间步长固定为大约60 FPS的功能。除非您将该功能写入winforms应用程序,否则您将无法使用它。但是使用可变时间步而不是固定时间步是一个很好的选择。
我通过使用从GraphicsDeviveControl派生的类中的秒表来解决这个问题。
然后,在Draw()方法中,将变量设置为它的经过时间,然后重置它。这是一个例子:
public class XnaControl : GraphicsDeviceControl
{
Stopwatch timer;
之后,在draw方法中
protected override void Draw()
{
float elapsed = (float)timer.Elapsed.TotalSeconds;
timer.Restart();
systemBase.UpdateSimulation(elapsed);
systemBase.DrawSimulation(elapsed);
}
现在,通过发送'elapsed'以及Update&amp;绘制时,您可以像任何可变时间步骤游戏/应用程序一样以插值方式计算事物。