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