首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 開發 WPF/Silverlight 動畫與遊戲系列教程(四十二):自訂 ChildWindow 控件與迷你尋路地圖

     編輯:關於C#

前言

前幾章節的物件頭像面板、迷你雷達地圖等視窗位置固定,處理方式簡單。但在 RPG、SLG、養成類遊戲中,大量使用可自由拖曳的懸浮視窗:背包、裝備、屬性、技能、系統設定等。這要求我們打造一個通用、易用、高自由度的 ChildWindow 控件。本節將實作包含可拖曳標題列、關閉按鈕、內容主體三大部件的自訂 ChildWindow,並用它實作迷你尋路地圖。

需求分析

  • 佈局:標題列、關閉按鈕、內容主體,皆可由任意物件實現,支援高度擴充。
  • 功能:可在遊戲視窗任意拖曳;多實例間具備協調的層級關係(Z-Index 管理)。
  • 結構:能與遊戲物件輕鬆互動,且不干擾其他物件活動。

三種實作路徑比較

  1. 底層繼承:繼承 Control 或 ContentControl,程式碼佈局與事件處理。傳統但 WPF/Silverlight 中易用性差,因 XAML 介入,且需深厚底層控件開發經驗。
  2. 模板化控件:Silverlight 範本控件,配合 Generic.xaml 定義樣板。國外開發者常用,但中文支援不佳、OnApplyTemplate 重載不靈活,擴充與開發難度非最理想。
  3. 使用者控件:繼承 UserControl,結構簡單卻蘊含高度靈活性。本節採用此法。

QXChildWindow 使用者控件實作

XAML 結構極簡:

<UserControl x:Class="QXGameEngine.Control.QXChildWindow"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  MouseLeftButtonDown="UserControl_MouseLeftButtonDown">
  <Canvas>
    <Canvas x:Name="Head" MouseLeftButtonUp="Head_MouseLeftButtonUp" MouseMove="Head_MouseMove">
      <ContentPresenter x:Name="HeadPresenter" />
      <Rectangle x:Name="CloseButton">
        <ToolTipService.ToolTip>
          <TextBlock x:Name="Tip" Text="關閉" />
        </ToolTipService.ToolTip>
      </Rectangle>
    </Canvas>
    <Canvas x:Name="Body">
      <ContentPresenter x:Name="BodyPresenter" />
    </Canvas>
  </Canvas>
</UserControl>

結構示意圖:

靈活性解析:

  • Head 為 Canvas,背景可設為任意 Brush(漸層、圖片、影片)。內含 HeadPresenter (ContentPresenter),後台可指派任意物件(矩形、圖片、畫布、甚至另一個 QXChildWindow),佈局完全自由。
  • Body 同理,透過 BodyPresenter 實現內容任意置換。

定義 CLR 屬性賦值,並透過路由事件 MouseLeftButtonDown、MouseLeftButtonUp、MouseMove 實現拖曳、關閉、層級管理等功能。

實作迷你尋路地圖

註冊鍵盤事件(Ctrl+Tab)顯示視窗:

private void UserControl_KeyDown(object sender, KeyEventArgs e) {
    if (e.Key == Key.Tab && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) {
        // 顯示尋路地圖邏輯
    }
}

建立 QXChildWindow 實例並設定參數:

wayfindingWindow = new QXChildWindow() {
    Left = 105, Top = 40,
    HeadLeft = 0, HeadTop = 0, HeadWidth = 604, HeadHeight = 37,
    HeadBackground = new ImageBrush() { ImageSource = Super.GetImage("/Image/Plate/WayfindingMapHead.png") },
    BodyLeft = 0, BodyTop = 37, BodyWidth = 604, BodyHeight = 479,
    BodyBackground = new ImageBrush() { ImageSource = Super.GetImage("/Image/Plate/WayfindingMapBody.png") },
    CloseButtonLeft = 582, CloseButtonTop = 0, CloseButtonWidth = 22, CloseButtonHeight = 22,
    CloseButtonFill = new ImageBrush() { ImageSource = Super.GetImage("/Image/Icon/11.png") }
};
Root.Children.Add(wayfindingWindow);

面板內的地圖名稱、地圖畫布等可透過 HeadPresenter、BodyPresenter 輕鬆注入。主角位置每 500ms 於背景執行緒更新(僅顯示時才運算),節省效能。主角圖示為朝北三角形,依 Angle = Leader.Direction * 45 旋轉;另加一條釣魚線連接主角與點擊目標點,模仿《劍俠世界》設計,便於把握距離。

執行成果

已知問題:Silverlight 渲染機制導致 MouseMove 拖曳效能非最佳;且 MouseMove、MouseDown、MouseUp 雖為路由事件,卻無法 e.Handled,造成命中測試穿透 ChildWindow 層。期待未來版本改善。

原始碼下載:目錄中;線上演示:https://silverfuture.cn

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved