关闭

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

标签: wpf游戏objecttimerresources引擎
1443人阅读 评论(1) 收藏 举报
分类:

下面简单介绍一下重新设计过的编辑器结构,从功能和层次上分主要是这样的:


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

 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:18829次
    • 积分:321
    • 等级:
    • 排名:千里之外
    • 原创:12篇
    • 转载:0篇
    • 译文:0篇
    • 评论:12条
    文章分类
    最新评论