上篇寫了有關可複用拖拽的基本控件,它的應用範疇非常廣泛,與之配套的就是諸如包裹、工具欄、技能條等等可以進入的目標,然而Silverlight提供的拖拽只是對於一些特定的容器有效,而且要符合麻煩的規則,可延展性在遊戲應用中非常有限,比如拖拽技能圖標的時候,是跟着鼠標一起走,而今天我將使用一個有趣的方式完成簡單的技能條系統。
本篇代碼是上篇的延展,並且涉及有關知識:Silverlight 遊戲開發:可重用的拖拽控件
翻閱過很多資料,Silverlight中這類可以放入拖拽物體的做法,都是使用DragEnter和DragLeave這類的事件處理,深藍色右手的包裹系統也是基於此類做法完成,而我在開發《窩窩世界》的時候,考慮不增加程序的大小,而沒有附加ToolKit(Toolkit裏有WarpPanel這類做包裹較好的控件),那麼就意味着必須通過其他的方式來實現拖拽Object進入目標,我使用的方法雖然暴力但是卻行之有效,使用的是VisualTreeHelper.FindElementsInHostCoordinates,在一個點或區域查找符合條件的控件集合,就是通過它可以取得技能條之類的容器,因爲Mouse的Down、Move、Up事件都可以取得鼠標的座標點,所以取得這個點上是否有容器完全可行。
現在簡單的建立一個MyPack的控件:
上面是用Blend畫的一個前臺,下面是XAML的代碼:
- <UserControl
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d"
- x:Class="DragObject.MyPack"
- d:DesignWidth="640" d:DesignHeight="480" Height="64">
- <StackPanel x:Name="LayoutRoot" Orientation="Horizontal">
- <StackPanel.Background>
- <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
- <GradientStop Color="#FF00B667" Offset="0"/>
- <GradientStop Color="#FF00FF61" Offset="1"/>
- </LinearGradientBrush>
- </StackPanel.Background>
- <TextBlock x:Name="textBlockType" TextWrapping="Wrap" Margin="5,0,0,0" Width="74" FontSize="12" HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Center"><Run Text="只放圖標"/></TextBlock>
- <Rectangle Fill="#FFF4F4F5" Stroke="Black" Width="3"/>
- </StackPanel>
- </UserControl>
- public partial class MyPack : UserControl
- {
- public MyPack()
- {
- InitializeComponent();
- }
- public void AddObj(UIElement uielement)
- {
- LayoutRoot.Children.Add(uielement);
- }
- public void ClearIcon()
- {
- for (int i = LayoutRoot.Children.Count - 1; i > 1; i--)
- {
- LayoutRoot.Children.RemoveAt(i);
- }
- }
- }
實現的功能比較明瞭,一個是添加,一個是清理,而清理則是倒序,爲了把第1個和第2個留下,如果你有其他的邏輯,可以自行添加,比如數量之類的。
下面就是寫拖拽的邏輯,本篇這個程序中,只有MyIcon的控件可以拖入技能條裏,而其他的Face、Card都不行,因此,將代碼寫在MyIcon中,重建對應的功能操作:
- bool isLocked = false;
- protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
- {
- base.OnMouseLeftButtonUp(e);
- var findlist = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), this.Parent as FrameworkElement);
- foreach (var item in findlist)
- {
- if (item is MyPack)
- {
- (this.Parent as Panel).Children.Remove(this);
- (item as MyPack).AddObj(this);
- isLocked = true;
- break;
- }
- }
- }
- protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
- {
- if (isLocked)
- return;
- base.OnMouseLeftButtonDown(e);
- }
後面可以依照自己的需要進行改造,比如做類型判斷和其他的功能開發,比如說下面呢,爲了增加趣味,我擴展了MyIcon的類,通過一個繼承類增加了圖標切換動畫,這個類名叫MyIcon2
- public class MyIcon2 :MyIcon
- {
- public MyIcon2()
- {
- DispatcherTimer selfLoop = new DispatcherTimer();
- selfLoop.Interval = TimeSpan.FromMilliseconds(300);
- selfLoop.Tick += new EventHandler(selfLoop_Tick);
- selfLoop.Start();
- }
- int iframe = 1;
- void selfLoop_Tick(object sender, EventArgs e)
- {
- base.IconIndex = iframe;
- iframe += 1;
- if (iframe > 10)
- iframe = 1;
- }
- }
很簡單,在構造函數中創建了一個計時器DispatcherTimer ,起名爲selfLoop(自身循環),在循環Tick事件中加入了索引變更,這樣就會出現一個切換動畫。
好了,在MainPage裏寫一些邏輯,或者直接在Blend裏面繪製,在這裏我就不再做代碼講述,可以直接看最終的效果以及下載代碼研究,在左上角加入一個重來的按鈕,功能爲清理條中的ICON,並隨機生成5個在界面上:
本篇工程源代碼下載地址如下:點擊直接下載