我们在游戏中经常应用自定义鼠标来提升游戏的画面品质,一个好的游戏怎么能没有好看的鼠标呢,关于Silverlight的各种自定义鼠标的方法很多,而我将为大家带来的是在游戏当中的应用效果,当然了,做法更加游戏化,先看下图:

 

Silverlight C# 游戏开发:自定义鼠标(一)_自定义

我们期望达到的效果是,鼠标移入不同的对象上显示不同的鼠标效果:

Silverlight C# 游戏开发:自定义鼠标(一)_游戏开发_02

在其他的文章中曾经看到过一些做法,都是习惯将一个控件绑定到MainPage的MouseMove上,我所用做法也是一样,但是较之更加“密封”一些,比如先创建一个CursorBase类(我是喜欢直接写代码,而不是用控件老搞定^_^):

  1. public class CursorBase : Canvas  
  2. {  
  3. public CursorBase(FrameworkElement parent)  
  4. {  
  5. parent.MouseMove += new MouseEventHandler(parent_MouseMove);  
  6. parent.Cursor = Cursors.None;  
  7. Canvas.SetZIndex(this, 9999);   
  8.  
  9. }  
  10. //将父对象的鼠标移动事件增加到这里  
  11. void parent_MouseMove(object sender, MouseEventArgs e)  
  12. {  
  13. Point pt = e.GetPosition(sender as UIElement);  
  14. X = pt.X;  
  15. Y = pt.Y;  
  16. }  
  17. //一套简单的坐标控制  
  18. public double X  
  19. {  
  20. get { return Canvas.GetLeft(this); }  
  21. set { Canvas.SetLeft(this, value); }  
  22. }  
  23. public double Y  
  24. {  
  25. get { return Canvas.GetTop(this); }  
  26. set { Canvas.SetTop(this, value); }  
  27. }   
  28. }  
  29.    
  30.  
  31. 这是一个自定义鼠标的基本类,特别提一下构造函数添加的FrameworkElement,这是代表MainPage的父对象传入,当然了,也可以传入其他的元素做父对象,就要看你要将自定义鼠标应用在什么地方了。  
  32.  
  33. 但是这只是通过代码写一个控件而已,如果呈现这些图片呢,于是下面再写一个控制类:  
  34.  
  35.    
  36.  
  37. Model控制类   
  38. public class CursorControl : CursorBase  
  39. {  
  40. public CursorControl(FrameworkElement parent)  
  41. : base(parent)  
  42. {  
  43. this.CacheMode = new BitmapCache();  
  44. this.IsHitTestVisible = false;  
  45. }  
  46. //添加一个鼠标模型  
  47. public void AddCursorModel(string name, FrameworkElement model)  
  48. {  
  49. this.Children.Add(model);  
  50. if (this.Children.Count != 1)  
  51. model.Visibility = Visibility.Collapsed;  
  52. else  
  53. model.Visibility = Visibility.Visible;  
  54. model.Name = name;  
  55. }  
  56. //从图片添加鼠标模型  
  57. public void AddCursorModelFromImage(string name, Uri uri)  
  58. {  
  59. AddCursorModel(name, new Image() { Source = new BitmapImage(uri) });  
  60. }  
  61. //正在显示的模型名字  
  62. string ModelName = "默认";  
  63. //获得正在显示的模型名字  
  64. public string GetCursorModel()  
  65. {  
  66. return ModelName;  
  67. }  
  68. //设置要显示的鼠标模型  
  69. public void SetCursorModel(string name)  
  70. {  
  71. foreach (FrameworkElement item in this.Children)  
  72. {  
  73. if (item.Name == name)  
  74. {  
  75. item.Visibility = System.Windows.Visibility.Visible;  
  76. ModelName = name;  
  77. }  
  78. else  
  79. item.Visibility = System.Windows.Visibility.Collapsed;  
  80. }  
  81.  
  82. }  
  83. }  
  84.    
  85.  
这次直接操作Children集合,通过外部添加的方式设置鼠标的不同状态和样式,这个类更多意义是封装了几个方法,以方便我们达到更便捷的操作,通过AddCursorModel增加样式模型,SetCursorModel设置样式模式,在这个基础上,可以使用状态枚举等方式,但是都需要这些方法来操作样式,如果你需要Remove,那么可以简单的自己写一个:)

这里有一个特别需要提到的是关于IsHitTestVisible,是用来阻止自定义鼠标的点击测试。

下一步,将图片添加到工程当中:

Silverlight C# 游戏开发:自定义鼠标(一)_Silverlight_03

现在,我们写一个MyCursor类,构建我们所需要的样式的图片序列。

Silverlight C# 游戏开发:自定义鼠标(一)_游戏开发_04我的鼠标
  1. //我的鼠标  
  2. public class MyCursor : CursorControl  
  3. {  
  4. public MyCursor(FrameworkElement parent)  
  5. : base(parent)  
  6. {  
  7. base.AddCursorModelFromImage("默认", new Uri(@"/CustomCursor01;component/Res/Cursor/" + 0 + ".png", UriKind.Relative));  
  8. base.AddCursorModelFromImage("禁止", new Uri(@"/CustomCursor01;component/Res/Cursor/" + 1 + ".png", UriKind.Relative));  
  9. base.AddCursorModelFromImage("攻击", new Uri(@"/CustomCursor01;component/Res/Cursor/" + 2 + ".png", UriKind.Relative));  
  10. base.AddCursorModelFromImage("魔法", new Uri(@"/CustomCursor01;component/Res/Cursor/" + 3 + ".png", UriKind.Relative));  
  11. base.AddCursorModel("等待", new WaitCursor());  
  12. ThisCursor = this;  
  13. }  
  14. public static MyCursor ThisCursor = null;  
  15. }  
  16.    
  17.  
为了更加方便的控制自定义的鼠标,增加了一个ThisCursor用来保存最新的Cursor,我通常认为界面中只有一个鼠标,所以这样做法更加直接明了,除非你使用了全局的控制方法:)

WaitCursor是一个UserControl,里面加入了一些动画和效果,并不是所有的鼠标样式都是图片,而我们的方法中提供了对控件的支持,关于WaitCursor控件请下载源代码自行查看吧。

下一步就是如何控制它们,现在我需要布局元素,然后为他们起上名字分别叫Item01、Item02、Item03、Btn_ShowWait,当鼠标移入的时候就可以直接通过ThisCursor来控制。

Silverlight C# 游戏开发:自定义鼠标(一)_游戏开发_06

但是,我们怎么能够控制这些样式,怎么在正确的调用SetCursorModel呢,难点在鼠标移入到一个元素,而不知道到底是什么应该触发什么鼠标的样式,为了解决这个问题,我们需要借助Tag这个Silverlight特有的属性。下面截选自Silverlight4.0的离线文档。

Silverlight C# 游戏开发:自定义鼠标(一)_游戏开发_07

于是,我们借助了一个小小的属性来完成不可告人之目的,也有更加暴力的方法就是为每个对象都增加一个独立处理的鼠标事件,但是很不好,如果游戏中的对象过多就不好办了,所以,越精简越封装越好。

我只需将MainPage.xaml写成这样:

  1. <Canvas x:Name="LayoutRoot"> 
  2. <Image x:Name="Item01" Height="90" Canvas.Left="26" Source="Res/Item01.png" Stretch="Fill" Canvas.Top="18" Width="90"/> 
  3. <Image x:Name="Item02" Height="96" Canvas.Left="263" Source="Res/Item02.png" Stretch="Fill" Canvas.Top="12" Width="51"/> 
  4. <Image x:Name="Item03" Height="80" Canvas.Left="407" Source="Res/Item03.png" Stretch="Fill" Canvas.Top="24" Width="100"/> 
  5. <Button x:Name="Btn_ShowWait" Content="动画图标" Height="35" Canvas.Left="40" Canvas.Top="152" Width="148"/> 
  6. </Canvas> 
  7.    
  8.  
在后台的MainPage.cs添加和修改如下代码:
Silverlight C# 游戏开发:自定义鼠标(一)_C#_08MainPage.cs代码
  1. public partial class MainPage : UserControl  
  2. {  
  3. public MainPage()  
  4. {  
  5. InitializeComponent();  
  6. InitializeMyPlace();  
  7. this.CacheMode = new BitmapCache();  
  8. LayoutRoot.Children.Insert(0,new Image() { Source = new BitmapImage(new Uri(@"/CustomCursor01;component/Res/map01.jpg", UriKind.Relative)) });  
  9. LayoutRoot.Children.Add(new MyCursor(this));  
  10.  
  11. }  
  12. public void InitializeMyPlace()  
  13. {  
  14. Item01.Tag = "攻击";  
  15. Item02.Tag = "魔法";  
  16. Item03.Tag = "禁止";  
  17. Item01.MouseEnter += new MouseEventHandler(Item_MouseEnter);  
  18. Item02.MouseEnter += new MouseEventHandler(Item_MouseEnter);  
  19. Item03.MouseEnter += new MouseEventHandler(Item_MouseEnter);  
  20. Item01.MouseLeave += new MouseEventHandler(Item_MouseLeave);  
  21. Item02.MouseLeave += new MouseEventHandler(Item_MouseLeave);  
  22. Item03.MouseLeave += new MouseEventHandler(Item_MouseLeave);  
  23.  
  24. Btn_ShowWait.Click += new RoutedEventHandler(Btn_ShowWait_Click);  
  25. }  
  26.  
  27. void Btn_ShowWait_Click(object sender, RoutedEventArgs e)  
  28. {  
  29. if (MyCursor.ThisCursor.GetCursorModel() == "等待")   
  30. MyCursor.ThisCursor.SetCursorModel("默认");  
  31. else  
  32. MyCursor.ThisCursor.SetCursorModel("等待");  
  33. }  
  34. void Item_MouseEnter(object sender, MouseEventArgs e)  
  35. {  
  36. MyCursor.ThisCursor.SetCursorModel((sender as FrameworkElement).Tag as string);  
  37. }  
  38. void Item_MouseLeave(object sender, MouseEventArgs e)  
  39. {  
  40. MyCursor.ThisCursor.SetCursorModel("默认");  
  41. }  
  42. }  
还有一个WaitCursor控件,请直接看源代码吧,源代码下载如下:点击这里下载

现在运行效果看看怎么样呢,鼠标在上面移动看看: 

到此,我们可以基本上完成了游戏中的自定义鼠标的雏形开发工作,关于Tag可以使用自定义的结构体来带入相关信息,毕竟对象所需要的内容是很多的,在下个关于自定义鼠标的文章中,我们一起研究一下拾取和拖拽的制作方法。