C# Windows窗体环境中XNA控件的游戏时类替换

C# Windows窗体环境中XNA控件的游戏时类替换,c#,winforms,time,xna,C#,Winforms,Time,Xna,您好,我正在尝试使用本教程将XNA模块嵌入到我的项目中,该项目是一个Windows窗体应用程序: . 我想这是最容易练习的教程了,所以我决定继续学习 当我需要游戏时间时,问题就出现了,在XNA控件的实现中,游戏时间并不存在。我试着在谷歌上寻找一个快速的解决方案,并试图找到一个解释游戏时间是如何在一个普通的XNA游戏中实现的,但我发现的信息越多,我就越困惑。。。 以下是问题: 在常规XNA游戏GameTime.ElapsedGameTime中,描述中显示“自上次更新以来经过的游戏时间。”-这是什

您好,我正在尝试使用本教程将XNA模块嵌入到我的项目中,该项目是一个Windows窗体应用程序: . 我想这是最容易练习的教程了,所以我决定继续学习

当我需要游戏时间时,问题就出现了,在XNA控件的实现中,游戏时间并不存在。我试着在谷歌上寻找一个快速的解决方案,并试图找到一个解释游戏时间是如何在一个普通的XNA游戏中实现的,但我发现的信息越多,我就越困惑。。。 以下是问题:

  • 在常规XNA游戏GameTime.ElapsedGameTime中,描述中显示“自上次更新以来经过的游戏时间。”-这是什么意思?它是否给出了经过的毫秒数?但这没有任何意义,因为在绘图和更新之间有一个恒定的时间跨度,并且差不多每16毫秒发生一次。。这对我来说似乎毫无意义,我想在这里得到一点解释。我知道ElapsedGameTime在使用线性插值平滑运动方面起着重要作用,但如果其最大值在16ms左右,则没有任何意义

  • XNA控件中是否实现了精确的游戏时间?如果不是,那么在Windows窗体中模拟游戏时间的最佳实践是什么


抱歉,如果以前有人问过我的问题,那么现在对我来说非常重要,我已经尝试过基于谷歌搜索得到答案,但是没有得到任何明确的答案

如果您选择使用可变时间步长,
GameTime
结构更相关。默认情况下,XNA运行固定的时间步长(因此在正常情况下,所有更新都以固定的间隔进行)

我猜您需要一个
GameTime
,因为您希望刷新控件,而不仅仅是基于用户输入(例如,像游戏一样,即使用户不碰任何东西也会发生事情)

在这种情况下,一种简单的方法是在表单上有一个计时器控件,它只调用更新/渲染函数。你可以把计时器的时间间隔传递给你的函数。您可以使用XNA中通常接受
GameTime
的函数,只接受double或float等。或者您可以根据时间间隔自己创建
GameTime


另一个选择是创建另一个线程,该线程将尝试以尽可能快的速度更新(可能在一定程度上)。这将在UI线程上引发回调,从而执行更新/呈现。处理
GameTime
与上述类似,您可以记录上次运行的时间,并将当时与现在的差值作为时间增量传递。

GameTime
提供自上次更新以来经过的固定或可变时间,游戏开始后的总时间,以及与目标性能相关的
isrunningslowy
标志

这是一篇关于WinForms中游戏计时器的好文章:

。为您提供一个对象,您可以在其中检索任意时间单位,包括(但不限于)通过属性的毫秒数


TimeSpan总是相同的原因是XNA默认使用固定的时间步长。您可以通过设置Dmitry在注释中指出的属性来更改此设置。在这个问题中,有一个关于时间步的极好的讨论,以及一些实现它们的代码。

这段代码工作得很好,唯一的区别是game类中的构造函数,其余的类似于windows的普通xna游戏

这是我用于此的代码

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
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         
    }      
}
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

namespace SpriteEditor
{
#if WINDOWS
    static class Program
    {
        [STAThread]
        static void Main(string[] args)
        {               
            Application.EnableVisualStyles( );
            Application.SetCompatibleTextRenderingDefault( false );
            XnaControlGame.CreateAndShow<SkeletonManagerDialog, SkeletonXnaGame>( );           
        }
    }
#endif
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         
    }      
}
使用系统;
使用System.Windows.Forms;
使用Microsoft.Xna.Framework;
使用Microsoft.Xna.Framework.Graphics;
使用Microsoft.Xna.Framework.Input;
命名空间SpriteEditor
{
公共接口IXnaFormContainer
{
控件XnaControl{get;}
XnaControlGame游戏{get;set;}
}
公共抽象类XnaControlGame:Microsoft.Xna.Framework.Game
{
公共控件父项{get;private set;}
公共静态void CreateAndShow()
其中T:Form,IXnaFormContainer,new()
Q:XnaControlGame在哪里
{
使用(T form=newt())
{
form.Show();
使用(Q game=(Q)Activator.CreateInstance(typeof(Q),新对象[]{form.XnaControl.Handle,form,form.XnaControl}))
{
形式。游戏=游戏;
game.Parent=form.XnaControl;
game.Run();
}
}
}
#用于构建嵌入式Xna控件的区域专用变量
INTPTRu XnaDrawingSurface;
图形管理器图形;
System.Windows.Forms.Form父窗体;
System.Windows.Forms.controlcontrolxna;
System.Windows.Forms.Control游戏窗体;
#端区
#区域构造函数
公共XnaControlGame(IntPtr手柄,
System.Windows.Forms.Form父窗体,
System.Windows.Forms.Control surfaceControl)
{
graphics=新的GraphicsDeviceManager(此);
graphics.GraphicsProfile=GraphicsProfile.Reach;
Content.RootDirectory=“Content”;
this.parentForm=parentForm;
this.controlXna=表面控制;
gameForm=System.Windows.Forms.Control.FromHandle(this.Window.Handle);
gameForm.VisibleChanged+=新事件处理程序(gameForm\u VisibleChanged);
controlXna.SizeChanged+=新事件处理程序(pictureBox_SizeChanged);
//正在准备设备设置处理程序。
_XnaDrawingSurface=手柄;
Mouse.WindowHandle=句柄;
graphics.PreparingDeviceSettings+=OnPreparingDeviceSetting
    protected override void Draw()
    {
        float elapsed = (float)timer.Elapsed.TotalSeconds;
        timer.Restart();
        systemBase.UpdateSimulation(elapsed);
        systemBase.DrawSimulation(elapsed);
    }