• Silverlight 游戏开发:可重用的拖拽控件


    游戏中有各种各样的拖拽需求,大到窗口,小到图标,在游戏界面操作中,点击和拖拽占据了用户操作的大部分行为,如何做好一个拖拽控件至关重要,做一个可重用的拖拽控件更加重要,我的这些实现方法可能比较另类,但只要有效就行,在这个基础上,你可以扩展很多的做法。

    可能有朋友已经写了这方面的文章,但是本篇介绍的方法是一个可以一劳永逸的重用控件,只需要一个基类代码就可以完成所有的需求——图标、窗体、自定义的目标,所以,本片没有放在小技巧里而是游戏开发分类里。

    最先,需要了解一下拖拽原理,即当鼠标按下做一个标识,在鼠标移动时实时修改目标坐标信息,鼠标抬起的时候,释放掉鼠标操作,当然了,为了更好的操作坐标,我们一般将父容器改成Canvas。

    1

    将围绕这个做后面的工作,请了解之前有关基类和容器的概念,这样后面看起来就容易很多,考虑它的重用性,创建一个基本控件让后面的控件继承,将一些通用逻辑写在这个基类里,让其他的类去继承重用,这也就是游戏引擎的基本做法之一。

    那么,在Blend或者Visual Studio里创建一个名为MovableObject的控件,然后将控件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.MovableObject"
    d:DesignWidth="640" d:DesignHeight="480" Width="Auto" Height="Auto">
    <Grid x:Name="LayoutRoot">
    <Rectangle Stroke="Black" RadiusX="5" RadiusY="5">
    <Rectangle.Fill>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
    <GradientStop Color="Transparent"/>
    <GradientStop Color="Black" Offset="1"/>
    </LinearGradientBrush>
    </Rectangle.Fill>
    </Rectangle>
    <Image x:Name="ShowImage" Stretch="Fill"/>
    <Rectangle x:Name="Sel_Rectangle" Stroke="White" StrokeThickness="2" Visibility="Collapsed" RadiusX="5" RadiusY="5"/>
    </Grid>
    </UserControl>

    即便使用代码实现并不难,但是为了方便理解,就直接使用XAML较为简便,浏览它的结构图就可以看到。

    2

    上面的表示方法分别是带了一个底,和一个要显示图像的Image,以及一个当鼠标移入时候需要表示选择标识。

    那么下面就是Coding阶段,打开MovableObject类,代码设计如下:

    public partial class MovableObject : UserControl
    {
    //鼠标点的保存,同时还承担是否点击的判定
    Point ? mousePoint = null;
    public MovableObject()
    {
    InitializeComponent();
    //选择框隐蔽掉
    Sel_Rectangle.Visibility = System.Windows.Visibility.Collapsed;
    }
    //鼠标移动的方法重载
    protected override void OnMouseMove(MouseEventArgs e)
    {
    //判定是否按下鼠标左键
    if (mousePoint!=null)
    {
    //计算新的位置
    double newTop = e.GetPosition(null).Y - mousePoint.Value.Y + Canvas.GetTop(this);
    double newLeft = e.GetPosition(null).X - mousePoint.Value.X + Canvas.GetLeft(this);
    Canvas.SetTop(this, newTop);
    Canvas.SetLeft(this, newLeft);
    mousePoint = e.GetPosition(null);
    }
    base.OnMouseMove(e);
    }
    //鼠标抬起的方法重载
    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
    {
    mousePoint = null;
    //释放鼠标设备
    this.ReleaseMouseCapture();
    base.OnMouseLeftButtonDown(e);
    }
    //鼠标按下的方法重载
    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
    mousePoint = e.GetPosition(null);
    //捕获鼠标设备
    this.CaptureMouse();
    //下面三行是用来保证当前控件为最顶层的做法
    var parent = this.Parent as Panel;
    parent.Children.Remove(this);
    parent.Children.Add(this);
    base.OnMouseLeftButtonUp(e);
    }
    //鼠标进入的方法重载
    protected override void OnMouseEnter(MouseEventArgs e)
    {
    Sel_Rectangle.Visibility = System.Windows.Visibility.Visible;
    base.OnMouseEnter(e);
    }
    //鼠标移出的方法重载
    protected override void OnMouseLeave(MouseEventArgs e)
    {
    Sel_Rectangle.Visibility = System.Windows.Visibility.Collapsed;
    base.OnMouseLeave(e);
    }
    }

    我做了一些注释,可以很明确的得知这个基类的作用,现在可以新建类继承于这个类,来实现扩展的目的。

    为此,我准备三种不同的目标效果——图标(MyIcon)、大图片(MyFace)、自定义控件(MyCard)

    图标和图片只需要用上原有控件的Image即可,而自定义控件则是通过Blend或其他方式设计制作出来的独立控件,那么如何实现这三个效果呢?请往下看:

    我们先创建三个类,他们都继承于MovableObject

    public class MyIcon : MovableObject

    public class MyFace : MovableObject

    public class MyCard : MovableObject

    下面在各自的构造函数中填入对应的操作逻辑即可,下面给出了完整代码:

    public class MyIcon : MovableObject
    {
    public MyIcon()
    {
    IconIndex = 1;
    }
    private int _Iconindex = -1;
    public int IconIndex
    {
    get { return _Iconindex; }
    set
    {
    _Iconindex = value;
    var uri = new Uri("/DragObject;component/Res/image" + value + ".png", UriKind.Relative);
    ShowImage.Source = new System.Windows.Media.Imaging.BitmapImage(uri);
    }
    }
    }
    public class MyFace : MovableObject
    {
    public MyFace()
    {
    var uri = new Uri("/DragObject;component/Res/nowpaper.jpg", UriKind.Relative);
    ShowImage.Source = new System.Windows.Media.Imaging.BitmapImage(uri);
     }
    }
    public class MyCard : MovableObject
    {
    public MyCard()
    {
    LayoutRoot.Children.Insert(LayoutRoot.Children.IndexOf(ShowImage), new Card());
    LayoutRoot.Children.Remove(ShowImage);
    }
    }

    MyFace是直接修改ShowImage的Source,MyIcon里写了一个索引属性,这样可以在外面控制ShowImage,显示需要显示的图片,而MyCard里new出来一个控件,并替换掉了原有的ShowImage,MyCard使用了前面制作的一个控件。

    好了,现在在MainPage的构造函数中编写其他的代码,但是LayoutRoot需要变成Canvas,这样才能更好的控制图像位置。

    public MainPage()
    {
    InitializeComponent();
    //添加自定义的拖拽目标
    var icon = new MyIcon();
    LayoutRoot.Children.Add(icon);
    Canvas.SetLeft(icon, 20);
    Canvas.SetTop(icon, 50);
    icon = new MyIcon() { IconIndex = 3 };
    LayoutRoot.Children.Add(icon);
    Canvas.SetLeft(icon, 20);
    Canvas.SetTop(icon, 150);
    var face = new MyFace();
    LayoutRoot.Children.Add(face);
    Canvas.SetLeft(face, 100);
    Canvas.SetTop(face, 50);
    var card = new MyCard();
    LayoutRoot.Children.Add(card);
    Canvas.SetLeft(card, 270);
    Canvas.SetTop(card, 50);
    }

    现在运行看看效果吧,在这个基础上,可以制作窗口或需要拖拽的物体只需要继承修改一下,在下一篇,将会制作一个窗口并使用技巧完成拖入等操作,放心吧绝对不复杂。

    本篇工程源代码下载地址如下:点击直接下载

    获取 Microsoft Silverlight

    本篇文章的作者:Nowpaper

    推荐Silverlight游戏开发博客:深蓝色右手

  • 相关阅读:
    Developer 转型记:一个开发平台的“魔力”
    实践录丨如何在鲲鹏服务器OpenEuler操作系统中快速部署OpenGauss数据库
    一图看懂华为云DevCloud如何应对敏捷开发的测试挑战
    华为云GaussDB(DWS)内存知识点,你知道吗?
    在人工智能时代追逐的“后浪”
    【华为云技术分享】DLI跨源|当DLI遇见MongoDB
    授人以渔:stm32资料查询技巧
    云小课 | IPv4枯了,IPv6来了
    揭秘淘宝平台广告策略,拆解最佳投放实践
    520了,用32做个简单的小程序
  • 原文地址:https://www.cnblogs.com/nowpaper/p/1955946.html
Copyright © 2020-2023  润新知