XNA游戏编辑器教程1:Form,Render Control

本章我们将开始制作编辑器。首先在解决方案中添加一个新项目。不过,这次我们添加的是“Windows Forms”项目。这会自动创建使用Windows窗体时必要的引用。这些窗体几乎是所有的Windows应用程序的基础。他们拥有一些窗口大小,标题,工具栏按钮等属性,一个窗体是诸如按钮,滑动条,文本框等对象的容器,这些对象被称为“控件”,而自定义控件可以从“Control”继承。

现在创建了你的项目,进入解决方案资源管理器然后单击Form1,你应该会在设计窗口看到这个窗体,并可以编辑您的窗体和控件。窗体中的控件不会回应点击,输入等,但你可以通过点击并打开属性窗口建立自己的处理程序。控件能够提供的事件也可以通过点击属性列表上方工具栏中的“闪电”使用。要处理事件句柄,只需双击事件名称这样就会切换到代码窗口,在那你可以编写窗体或控件的代码,这一步也可以通过右击“查看代码”实现。而代码视图中也有“设计视图”选项。关于属性编辑器的一个重要的提示:在设计视图窗口中设置的属性和添加的控件会自动生成代码。如果您按一下解决方案资源管理器中该文件旁边的[ + ],你会发现实际上有两个文件:一个是你可以编辑的代码文件:“ClassName.cs”,另一个是自动生成的,该文件的名称是“ClassName.Designer.cs”。

看一下第一个文件,您会看到控件是一个“partial”类,这仅意味着这个类是分开放在多个文件中的。如果看一下自动生成的代码,你会看到大多数设置属性的和创建实例的工作是在“InitializeComponent()”方法中。看一下自己输入的代码,当你创建一个窗体时(在项目创建时发生)一部分代码已近自动生成了,默认Form1类的构造函数调用了InitializeComponent()方法。你通常应该让这个方法第一个被调用,否则窗体控件可能不会正确地被创建。您不应该改变自动生成的代码,它会在属性改变或添加控件时自动重建。如果你编辑这个文件往往会将设计窗体弄得一团糟,因为建立设计窗体依赖于这个文件。总之,只编辑你的自己编写的文件。

设计器的最后部分是工具箱。如果您看不到它,可从“查看”菜单打开。如果您打开这个窗口会看到一个Microsoft所提供的所有标准控件的列表。您可以通过右击并选择“选择项...”添加更多的控件,只要将其拖放到正在编辑的窗体或控件上,程序就会自动添加并生成代码。添加控件也可以在手写文件中进行,与我们以前在类中声明的方式相同。要改变名称只需改变“Name”属性。现在您应该知道如何使用设计器了。接下来的第一件事是让窗体变得大一些。移动光标到窗口的右下方并调整到一个合理的尺寸,至少1024×768。你可以在属性窗口看到现在的尺寸。通过更改“Text”属性将默认的“Form1”改成其他名称。这将是游戏编辑器的主窗口,我命名为“Innovation Engine Editor”。

现在,我们的窗体已经建立了,我们需要将XNA渲染到我们的窗体。首先添加以下引用(References>Add Reference):Microsoft.Xna.Framework, Microsoft.Xna.Framework.Game,并找到:InnovationEngine.dll。现在我们可以渲染控件了。但XNA仁慈地将这种做法变得相当困难(说笑而已),所以我们必须先做一些事情。

我们需要建立绘制XNA所需的图形设备及相关服务,因为这里我们不能使用Game类。幸运的是,在http://creators.xna.com/en-US/sample/winforms_series1有一个示例展示了如何做。下面大部分代码将借鉴这个范例,但我们必须使我们的控件能够绘制表面,并处理GameTime和GraphicsDevice。下面是微软编写的文件,将其添加到项目中。

GraphicsDeviceControl&GraphicsDeviceService.rar

现在我们将创建一个新的控件:添加>“新建项目”>用户控件,命名为RenderControl。代码如下所示:

using System.Diagnostics;
using System.Windows.Forms;
using Innovation;
using Microsoft.Xna.Framework;

namespace InnovationEditor
{
    public partial class RenderControl : GraphicsDeviceControl
    {
        // Simulate the GameTime ourselves because we don't have Game
        GameTime gameTime;

        // Elapsed and total time for the GameTime
        Stopwatch elapsedTime = new Stopwatch();
        Stopwatch totalTime = new Stopwatch();

        // Timer to keep track of refreshes
        Timer timer;

        // Camera, Keyboard, and Mouse will be handled here. They are
        // public and static so they can be used anywhere
        public static FPSCamera Camera;
        public static KeyboardDevice Keyboard;
        public static MouseDevice Mouse;

        public RenderControl()
        {
            // Run pre-generated control code
            InitializeComponent();

            // Start the timer keeping track of total elapsed time
            totalTime.Start();

            // Hook the mouse down event for the mousedevice, so the control
            // will be selected when clicked on. This avoids problems with
            // mouse and keyboard camera commands affecting other controls on
            // the form
            this.MouseDown += new MouseEventHandler(RenderControl_MouseDown);
        }

        // Select control on mouse down
        void RenderControl_MouseDown(object sender, MouseEventArgs e)
        {
            this.Select();
        }

        // Initialize the Control
        protected override void Initialize()
        {
            // Set up the engine
            Engine.SetupEngine(this.GraphicsServices);

            // Set up the frame update timer
            timer = new Timer();

            // Lock framerate to 40 so we can keep performance up
            timer.Interval = (int)((1f / 40f) * 1000);

            // Hook timer's tick so we can refresh the view on cue
            timer.Tick += new System.EventHandler(timer_Tick);
            timer.Start();

            // Setup the camera and move it to a good position, and make it a service
            Camera = new FPSCamera();
            Camera.RotateTranslate(new Vector3(0, 0, 0), new Vector3(128, 15, 300));
            Engine.Services.AddService(typeof(Camera), Camera);

            // Setup the keyboard and mouse, and allow the cursor to move
            Keyboard = new KeyboardDevice();
            Mouse = new MouseDevice();
            Mouse.ResetMouseAfterUpdate = false;
        }

        // Timer's tick causes the view to refresh
        void timer_Tick(object sender, System.EventArgs e)
        {
            // Invalidate everything so the whole control refreshes
            this.Invalidate();

            // Force the view update
            this.Update();
        }

        // Draw the scene
        protected override void Draw()
        {
            // Update GameTime and update the engine
            UpdateGameTime();
            Engine.Update(gameTime);

            // Update GameTime again and draw the scene
            UpdateGameTime();
            Engine.Draw(gameTime, ComponentType.All);
        }

        // Updates the GameTime object instead of relying on Game
        void UpdateGameTime()
        {
            // Recreate the GameTime with the current values
            gameTime = new GameTime(totalTime.Elapsed, totalTime.Elapsed, 
elapsedTime.Elapsed, elapsedTime.Elapsed);

            // Restart the elapsed timer that keeps track of time between frames
            elapsedTime.Reset();
            elapsedTime.Start();
        }
    }
}

现在,只需回到主窗体,并从工具箱中拖动一个新的RenderControl到panel中。如果看不到RenderControl控件,您可能需要再次编译该项目。现在运行项目,您会看到熟悉的XNA游戏初始状态,一个空白的蓝色屏幕。没有其他东西,但至少工作正常!

如果您想测试,可以在构造函数中创建一些组件,您可以看到游戏引擎像一个普通游戏一样正常运行。


发布时间:2009/3/27 下午3:25:54  阅读次数:12880

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号