游戏中有各种各样的拖拽需求,大到窗口,小到图标,在游戏界面操作中,点击和拖拽占据了用户操作的大部分行为,如何做好一个拖拽控件至关重要,做一个可重用的拖拽控件更加重要,我的这些实现方法可能比较另类,但只要有效就行,在这个基础上,你可以扩展很多的做法。
可能有朋友已经写了这方面的文章,但是本篇介绍的方法是一个可以一劳永逸的重用控件,只需要一个基类代码就可以完成所有的需求——图标、窗体、自定义的目标,所以,本片没有放在小技巧里而是游戏开发分类里。
最先,需要了解一下拖拽原理,即当鼠标按下做一个标识,在鼠标移动时实时修改目标坐标信息,鼠标抬起的时候,释放掉鼠标操作,当然了,为了更好的操作坐标,我们一般将父容器改成Canvas。
将围绕这个做后面的工作,请了解之前有关基类和容器的概念,这样后面看起来就容易很多,考虑它的重用性,创建一个基本控件让后面的控件继承,将一些通用逻辑写在这个基类里,让其他的类去继承重用,这也就是游戏引擎的基本做法之一。
那么,在Blend或者Visual Studio里创建一个名为MovableObject的控件,然后将控件xaml修改成下面的样子:
- <UserControl
-
- 02 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-
- 03 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-
- 04 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-
- 05 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-
- 06 mc:Ignorable="d"
-
- 07 x:Class="DragObject.MovableObject"
-
- 08 d:DesignWidth="640" d:DesignHeight="480" Width="Auto" Height="Auto">
-
- 09 <Grid x:Name="LayoutRoot">
-
- 10 <Rectangle Stroke="Black" RadiusX="5" RadiusY="5">
-
- 11 <Rectangle.Fill>
-
- 12 <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
-
- 13 <GradientStop Color="Transparent"/>
-
- 14 <GradientStop Color="Black" Offset="1"/>
-
- 15 </LinearGradientBrush>
-
- 16 </Rectangle.Fill>
-
- 17 </Rectangle>
-
- 18 <Image x:Name="ShowImage" Stretch="Fill"/>
-
- 19 <Rectangle x:Name="Sel_Rectangle" Stroke="White" StrokeThickness="2" Visibility="Collapsed" RadiusX="5" RadiusY="5"/>
-
- 20 </Grid>
-
- 21 </UserControl>
上面的表示方法分别是带了一个底,和一个要显示图像的Image,以及一个当鼠标移入时候需要表示选择标识。
那么下面就是Coding阶段,打开MovableObject类,代码设计如下:
- public partial class MovableObject : UserControl
-
- 02 {
-
- 03 //鼠标点的保存,同时还承担是否点击的判定
-
- 04 Point ? mousePoint = null;
-
- 05 public MovableObject()
-
- 06 {
-
- 07 InitializeComponent();
-
- 08 //选择框隐蔽掉
-
- 09 Sel_Rectangle.Visibility = System.Windows.Visibility.Collapsed;
-
- 10 }
-
- 11 //鼠标移动的方法重载
-
- 12 protected override void OnMouseMove(MouseEventArgs e)
-
- 13 {
-
- 14 //判定是否按下鼠标左键
-
- 15 if (mousePoint!=null)
-
- 16 {
-
- 17 //计算新的位置
-
- 18 double newTop = e.GetPosition(null).Y - mousePoint.Value.Y + Canvas.GetTop(this);
-
- 19 double newLeft = e.GetPosition(null).X - mousePoint.Value.X + Canvas.GetLeft(this);
-
- 20 Canvas.SetTop(this, newTop);
-
- 21 Canvas.SetLeft(this, newLeft);
-
- 22 mousePoint = e.GetPosition(null);
-
- 23 }
-
- 24 base.OnMouseMove(e);
-
- 25 }
-
- 26 //鼠标抬起的方法重载
-
- 27 protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
-
- 28 {
-
- 29 mousePoint = null;
-
- 30 //释放鼠标设备
-
- 31 this.ReleaseMouseCapture();
-
- 32 base.OnMouseLeftButtonDown(e);
-
- 33 }
-
- 34 //鼠标按下的方法重载
-
- 35 protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
-
- 36 {
-
- 37 mousePoint = e.GetPosition(null);
-
- 38 //捕获鼠标设备
-
- 39 this.CaptureMouse();
-
- 40 //下面三行是用来保证当前控件为最顶层的做法
-
- 41 var parent = this.Parent as Panel;
-
- 42 parent.Children.Remove(this);
-
- 43 parent.Children.Add(this);
-
- 44 base.OnMouseLeftButtonUp(e);
-
- 45 }
-
- 46 //鼠标进入的方法重载
-
- 47 protected override void OnMouseEnter(MouseEventArgs e)
-
- 48 {
-
- 49 Sel_Rectangle.Visibility = System.Windows.Visibility.Visible;
-
- 50 base.OnMouseEnter(e);
-
- 51 }
-
- 52 //鼠标移出的方法重载
-
- 53 protected override void OnMouseLeave(MouseEventArgs e)
-
- 54 {
-
- 55 Sel_Rectangle.Visibility = System.Windows.Visibility.Collapsed;
-
- 56 base.OnMouseLeave(e);
-
- 57 }
-
- 58 }
为此,我准备三种不同的目标效果——图标(MyIcon)、大图片(MyFace)、自定义控件(MyCard)
图标和图片只需要用上原有控件的Image即可,而自定义控件则是通过Blend或其他方式设计制作出来的独立控件,那么如何实现这三个效果呢?请往下看:
我们先创建三个类,他们都继承于MovableObject
public class MyIcon : MovableObject
public class MyFace : MovableObject
public class MyCard : MovableObject
下面在各自的构造函数中填入对应的操作逻辑即可,下面给出了完整代码:
- public class MyIcon : MovableObject
-
- 02 {
-
- 03 public MyIcon()
-
- 04 {
-
- 05 IconIndex = 1;
-
- 06 }
-
- 07 private int _Iconindex = -1;
-
- 08 public int IconIndex
-
- 09 {
-
- 10 get { return _Iconindex; }
-
- 11 set
-
- 12 {
-
- 13 _Iconindex = value;
-
- 14 var uri = new Uri("/DragObject;component/Res/image" + value + ".png", UriKind.Relative);
-
- 15 ShowImage.Source = new System.Windows.Media.Imaging.BitmapImage(uri);
-
- 16 }
-
- 17 }
-
- 18 }
-
- 19 public class MyFace : MovableObject
-
- 20 {
-
- 21 public MyFace()
-
- 22 {
-
- 23 var uri = new Uri("/DragObject;component/Res/nowpaper.jpg", UriKind.Relative);
-
- 24 ShowImage.Source = new System.Windows.Media.Imaging.BitmapImage(uri);
- 01 }
-
- 02 }
-
- 03 public class MyCard : MovableObject
-
- 04 {
-
- 05 public MyCard()
-
- 06 {
-
- 07 LayoutRoot.Children.Insert(LayoutRoot.Children.IndexOf(ShowImage), new Card());
-
- 08 LayoutRoot.Children.Remove(ShowImage);
-
- 09 }
-
- 10 }
好了,现在在MainPage的构造函数中编写其他的代码,但是LayoutRoot需要变成Canvas,这样才能更好的控制图像位置。
- public MainPage()
-
- 02 {
-
- 03 InitializeComponent();
-
- 04 //添加自定义的拖拽目标
-
- 05 var icon = new MyIcon();
-
- 06 LayoutRoot.Children.Add(icon);
-
- 07 Canvas.SetLeft(icon, 20);
-
- 08 Canvas.SetTop(icon, 50);
-
- 09 icon = new MyIcon() { IconIndex = 3 };
-
- 10 LayoutRoot.Children.Add(icon);
-
- 11 Canvas.SetLeft(icon, 20);
-
- 12 Canvas.SetTop(icon, 150);
-
- 13 var face = new MyFace();
-
- 14 LayoutRoot.Children.Add(face);
-
- 15 Canvas.SetLeft(face, 100);
-
- 16 Canvas.SetTop(face, 50);
-
- 17 var card = new MyCard();
-
- 18 LayoutRoot.Children.Add(card);
-
- 19 Canvas.SetLeft(card, 270);
-
- 20 Canvas.SetTop(card, 50);
-
- 21 }
本篇工程源代码下载地址如下:点击直接下载
本文转自nowpaper 51CTO博客,原文链接:http://blog.51cto.com/nowpaper/712743