用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;
}
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;
}
相关文章推荐
- 用WPF和D3D开发游戏编辑器简介(3)
- 用WPF和D3D开发游戏编辑器简介(1)
- 用WPF和D3D开发游戏编辑器简介(1)
- 用WPF和D3D开发游戏编辑器简介(2)
- 用WPF和D3D开发游戏编辑器简介(2)
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(三十五)地图编辑器的初步使用
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(三十五)地图编辑器的初步使用
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(三十四)地图编辑器诞生啦!
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(三十四)地图编辑器诞生啦!
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(三十四)地图编辑器诞生啦!
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(三十四)地图编辑器诞生啦!
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(三十五)地图编辑器的初步使用
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(三十五)地图编辑器的初步使用
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十)向Silverlight移植②
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十九) 落雷!治疗!陷阱!连锁闪电!多段群伤!魔法之终极五重奏②
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(二)让物体动起来②
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(七)传说中的A*寻径算法
- 死亡21点 游戏开发 1st —— 游戏简介
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(十)斜度α地图的构造及算法
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(三十) 大法师 – 华丽经典之轮回