您的位置:首页 > 其它

用WPF和D3D开发游戏编辑器简介(3)

2012-03-31 00:53 375 查看
下面简单介绍一下重新设计过的编辑器结构,从功能和层次上分主要是这样的:

App, MainWindow: 入口和主界面

Controls:使用的各种控件和自定义界面

Data:数据层,填充控件的数据信息,这里主要是魔兽世界的物品和npc等信息

Services:服务层,编辑器用到的功能由每个模块作为服务提供,比如场景服务维护编辑器中的场景结点等

Commands:命令,响应编辑器的各种命令,独立于界面

Resources:资源,包括主题,图像资源和程序中统一的界面元素,如上面程序的各种颜色边框

Application定义了程序的资源,主题,也是程序的入口,通常在启动主窗口之前,也是设置和获取使用的配置信息的地方,启动代码如下:

protected override void OnStartup(StartupEventArgs e)

{

base.OnStartup(e);

window = new MainWindow();

// Restore the window size when the values are valid.

if (Settings.Default.Left >= 0 && Settings.Default.Top >= 0 && Settings.Default.Width > 0 && Settings.Default.Height > 0

&& Settings.Default.Left + Settings.Default.Width <= SystemParameters.VirtualScreenWidth

&& Settings.Default.Top + Settings.Default.Height <= SystemParameters.VirtualScreenHeight)

{

window.Left = Settings.Default.Left;

window.Top = Settings.Default.Top;

window.Height = Settings.Default.Height;

window.Width = Settings.Default.Width;

}

window.IsMaximized = Settings.Default.IsMaximized;

Resources["EdgeBorderBrush"] = new SolidColorBrush(Settings.Default.EdgeBorderColor);

//init

new ShellService(window);

new EngineService();

new SceneService();

new EditorService();

//run

window.Show();

}



首先创建主窗口,通常在主窗口创建时完成引擎的初始化工作,然后读取配置信息,比如上次程序窗口的大小等信息,然后初始化各种服务,显示。

主窗口的设计界面如下图:



如图所示,窗口的界面主要分为菜单栏和左右底三个DockContent,这里需要控件AvalonDock,界面的主要代码如下:

<DockPanel LastChildFill="true" >

<!-- menu -->

<control:MenuControl DockPanel.Dock="Top"/>

<!-- docking manager -->

<ad:DockingManager x:Name="_dockManager" IsAnimationEnabled="True">

<ad:ResizingPanel FocusManager.IsFocusScope="True" Orientation="Horizontal">

<ad:DockablePane x:Name="_leftDockablePane" ad:ResizingPanel.ResizeWidth="0">

<v:MapContent x:Name="_mapContent"/>

<v:SpellVisualEffectContent x:Name="_spellVisualEffectContent" />

<v:NpcContent x:Name="_npcContent"/>

<v:CharacterContent x:Name="_characterContent"/>

</ad:DockablePane>

<ad:ResizingPanel FocusManager.IsFocusScope="True" Orientation="Vertical">

<!-- Main Content -->

<ad:DocumentPane Name="_documentPane" ShowHeader="False">

<ad:DocumentContent IsCloseable="false">

<Border Name="_controlHostElement" />

</ad:DocumentContent>

</ad:DocumentPane>

<ad:DockablePane x:Name="_bottomDockablePane" ad:ResizingPanel.ResizeHeight="0">

<v:AnimationContent x:Name="_animationContent"/>

</ad:DockablePane>

</ad:ResizingPanel>

<ad:DockablePane x:Name="_rightDockablePane" ad:ResizingPanel.ResizeWidth="0">

<v:ClothesContent x:Name="_clothesContent"/>

<v:WeaponContent x:Name="_weaponContent"/>

<v:SetContent x:Name="_setContent"/>

</ad:DockablePane>

</ad:ResizingPanel>

</ad:DockingManager>

</DockPanel>

WPF的界面部分非常简单,在设计阶段可以直接写几个简单的元素占位。

下面是比较复杂的初始化部分,流程大致是这样的:

1. 初始化引擎,把引擎窗口放到主界面中间,借助HwndHost。并设置resize和mouse消息处理。

2. 读取需要的数据表。

3. 读取命令绑定,初始化界面控件大小,激活窗口,启动timer准备渲染。

这三个步骤可以用一个Splash窗口来提示进度,总的代码如下:



private readonly DispatcherTimer timer;

private readonly WindowHost windowhost;

private bool isKeyFocus;

public MainWindow()

{

InitializeComponent();

Loaded += new RoutedEventHandler(MainWindow_Loaded);

Closing += new CancelEventHandler(MainWindow_Closing);

StateChanged += new EventHandler(MainWindow_StateChanged);

this.LostKeyboardFocus += delegate { isKeyFocus = false; };

windowhost = new WindowHost();

timer = new DispatcherTimer(DispatcherPriority.ApplicationIdle, windowhost.Dispatcher);

timer.Interval = new System.TimeSpan(0, 0, 0, 0, 1);

timer.Tick += new EventHandler(timer_Tick);

}



private void MainWindow_Loaded(object sender, RoutedEventArgs e)

{

this.Loaded -= MainWindow_Loaded;

SplashWindow _splash = new SplashWindow();

_splash.Show();

this.IsEnabled = false;

MessageListener.Instance.StartWork("第1/3步: 初始化引擎...", new DispatcherOperationCallback(InitStage0));

Thread.Sleep(1);

MessageListener.Instance.StartWork("第2/3步: 读取数据...", new DispatcherOperationCallback(InitStage1));

Thread.Sleep(1);

MessageListener.Instance.StartWork("第3/3步: 准备界面...", new DispatcherOperationCallback(InitStage2));

Thread.Sleep(1);

this.IsEnabled = true;

_splash.Close();

}



private object InitStage0(object frame)

{

windowhost.HwndHost = EngineService.Instance.InitilalizeEngine();

SceneService.Instance.Initialize();

windowhost.WmResize += new ResizeEventHandler(windowHost_WmResize);

windowhost.WmMouse += new MouseMessageHandler(windowHost_WmMouse);

((DispatcherFrame)frame).Continue = false;

return null;

}



private object InitStage1(object frame)

{

EngineService.Instance.RetrieveWowData();

((DispatcherFrame)frame).Continue = false;

return null;

}

private object InitStage2(object frame)

{

InitCommandBindings();

_characterContent.Initialize();

_npcContent.Initialize();

_spellVisualEffectContent.Initialize();

_mapContent.Initialize();

_clothesContent.Initialize();

_weaponContent.Initialize();

_setContent.Initialize();

_animationContent.Initialize();

if (windowhost.HwndHost != IntPtr.Zero)

{

_controlHostElement.Child = windowhost;

}

_leftDockablePane.SetValue(ResizingPanel.ResizeWidthProperty, new GridLength(180));

_rightDockablePane.SetValue(ResizingPanel.ResizeWidthProperty, new GridLength(180));

_bottomDockablePane.SetValue(ResizingPanel.ResizeHeightProperty, new GridLength(150));

this.Activate();

timer.Start();

((DispatcherFrame)frame).Continue = false;

return null;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐