你的位置:首页 > ASP.net教程

[ASP.net教程]WPF学习系列 游戏


今天要学习一个拼图项目。

目标是传入一张图片,然后将它分成9份,去掉一份,鼠标点击进行拼图。

源文件结构很简单

第一步、新建项目

这一步没什么好说的,新建一个项目就跟源文件结构一样了

 第二步、页面布局(.xaml文件)

看下源文件

控件有 DockPanel Grid Button三个然后设置了Grid有三列和三行。DockPannel暂时不知道有什么用,所以我先不忙加。然后我就报错了

原来 xaml是用的

第二步、编写点击按钮选图片的功能

 这个帖子上周就开始写了,但是做了一半又去研究c++了。c++研究了一段时间,忽然明白我为什么要编程了。我编程不是对计算机有兴趣,不是为了0和1。我学计算机和程序只是为了做东西。所以又回过头来继续写这个系列,之后的内容我不会再抓细节,有些东西,能看懂就行了。记不住也没关系,要用的时候再查就是了。将项目做出来之后,我还要将它做成我喜欢的样子,而不是做成跟源代码一样。

 点击按钮要做两件事

1、弹出文件选择对话框,选择图片。

2、选择图片后生成拼图

下面是选择图片的代码

OpenFileDialog ofd = new OpenFileDialog();                          // 需要引用Microsoft.Win32.ofd.Filter      = "Image Files(*.BMP;*.JPG;*.GIF;*.PNG)|*.BMP;*.JPG;*.GIF;*.PNG"; //支持的图片格式ofd.Multiselect   = false;                                   //不允许多选if (ofd.ShowDialog()!=true)                                   //ofd.ShowDialog()可能有三个值 true flase null{  return;}try{  BitmapImage image = new BitmapImage(new Uri(ofd.FileName, UriKind.RelativeOrAbsolute));  Image img = new Image { Source = image };   //这里写创建拼图的代码 }catch { MessageBox.Show("Couldnt load the image file " + ofd.FileName); }

选择图片

 

  

生成拼图 第一步是把图片分成9块,并填充相应区域的图像

这个有点复杂,源码用了很多方法,我习惯拆出来作为一个类单独写。

   /// <summary>  /// 拼图生成类  /// 传入一张图片 生成一个9*9的图片集合  /// </summary>  public class PuzzleForImage  {    BitmapImage   _image;                         //原图片    public List<Rectangle> initialUnallocatedParts = new List<Rectangle>();//要返回的拼图集合    /// <summary>    /// 新建对象时传入原图片    /// </summary>    /// <param name="image"></param>    public PuzzleForImage(BitmapImage image)    {      _image = image;
       //创建拼图 }  }

第一步:写个子方法,根据起点和图片宽高绘制矩形。然后调用9次,得到整个拼图集合

第二步:将9张中的8张拼图随机排列,这里选前八张

第三步:再添加块空白的拼图

第四步:添加鼠标点击移动事件

到这一步,源码部分就结束了,自己添加了个判断成功的代码 在方块中的点击事件中执行。

下面是我的代码。

/// <summary>  /// MainWindow.xaml 的交互逻辑  /// </summary>  public partial class MainWindow : Window  {    public MainWindow()    {      InitializeComponent();    }    /// <summary>    /// 挑选图片生成拼图    /// </summary>    private void BtnPickImg_Click(object sender, RoutedEventArgs e)    {      OpenFileDialog ofd = new OpenFileDialog();      ofd.Filter     = "Image Files(*.BMP;*.JPG;*.GIF;*.PNG)|*.BMP;*.JPG;*.GIF;*.PNG";//支持的图片格式      ofd.Multiselect  = false;//不允许多选      if (ofd.ShowDialog() != true)      {        return;      }      try      {        BitmapImage  image = new BitmapImage(new Uri(ofd.FileName, UriKind.RelativeOrAbsolute));        //Image img = new Image { Source = image };        PuzzleForImage puzzle = new PuzzleForImage(image);//创建拼图        puzzle.SetGrid(GridImg);      }      catch      {        MessageBox.Show("不支持该文件: " + ofd.FileName);      }    }  }

MainWindow.xaml.cs
  /// <summary>  /// 拼图生成类  /// 传入一张图片 生成一个9*9的图片集合  /// </summary>  public class PuzzleForImage  {    BitmapImage      _image;                     //原图片    List<Rectangle>    initialUnallocatedParts = new List<Rectangle>();//要返回拼图集合    public List<Rectangle> allocatedParts = new List<Rectangle>();     //被打乱后的图片    int[] map = new int[9];                        //游戏地图 判断是否成功    /// <summary>    /// 新建对象时传入原图片    /// </summary>    /// <param name="image"></param>    public PuzzleForImage(BitmapImage image)    {      _image = image;      CreatePuzzleForImage();    }    /// <summary>    /// 将拼图放到UI中    /// </summary>    /// <param name="GridImg"></param>    public void SetGrid(Grid GridImg)    {      GridImg.Children.Clear();      GridImg.Height = _image.Height / _image.Width * GridImg.Width;      int index = 0;      for (int i = 0; i < 3; i++)      {        for (int j = 0; j < 3; j++)        {          allocatedParts[index].SetValue(  Grid.RowProperty, i);          allocatedParts[index].SetValue(Grid.ColumnProperty, j);          GridImg.Children.Add(allocatedParts[index]);          index++;        }      }    }    /// <summary>    /// 创建拼图    /// </summary>    private void CreatePuzzleForImage()    {      #region 拼图容器初始化      initialUnallocatedParts.Clear();      allocatedParts.Clear();      #endregion      #region 创建前8个拼图      double width = 1.0 / 3;//每个拼图的宽度      double height = 1.0 / 3;//每个拼图的高度      //row0      CreateImagePart(     0,     0, width, height);      CreateImagePart(   width,     0, width, height);      CreateImagePart( 2 * width,     0, width, height);      //row1      CreateImagePart(     0,   height, width, height);      CreateImagePart(   width,   height, width, height);      CreateImagePart( 2 * width,   height, width, height);      //row2      CreateImagePart(     0, 2 * height, width, height);      CreateImagePart(   width, 2 * height, width, height);      //CreateImagePart( 2 * width, 2 * height, width, height);      #endregion            //随机排列      RandomizeTiles();      //创建白色方块      CreateBlankRect();    }    /// <summary>    /// 绘制一个矩形    /// 创建一个图像画刷使用X / Y /宽度/高度参数创建时,只显示图像的一部分。这是ImageBrush用来填充矩形,添加到未分配的矩形的内部表    /// </summary>    /// <param name="x">起点x</param>    /// <param name="y">起点y</param>    /// <param name="width">宽</param>    /// <param name="height">高</param>    private void CreateImagePart(double x, double y, double width, double height)    {      #region 定义笔刷      ImageBrush ib  = new ImageBrush();      //ib.Stretch = Stretch.UniformToFill;         //裁剪已适应屏幕 这个不能要,会造成图片不拉伸对不上      ib.ImageSource = _image;      ib.Viewbox   = new Rect(x, y, width, height);      ib.ViewboxUnits = BrushMappingMode.RelativeToBoundingBox; //按百分比设置宽高      ib.TileMode   = TileMode.None;             //按百分比应该不会出现 image小于要切的值的情况      #endregion      #region 定义矩形      Rectangle rectPart      = new Rectangle();      rectPart.Fill        = ib;      rectPart.Margin       = new Thickness(0);      rectPart.HorizontalAlignment = HorizontalAlignment.Stretch;      rectPart.VerticalAlignment  = VerticalAlignment.Stretch;      rectPart.MouseDown     += new MouseButtonEventHandler(rectPart_MouseDown);//添加矩形点击事件      #endregion      initialUnallocatedParts.Add(rectPart);                     //将矩形添加到拼图集合    }    /// <summary>    /// 将 图片打乱    /// </summary>    private void RandomizeTiles()    {      Random rand = new Random();      for (int i = 0; i < 8; i++)      {        int index = 0;        //if (initialUnallocatedParts.Count > 1)        //{        //  index = (int)(rand.NextDouble() * initialUnallocatedParts.Count);        //}        index = (int)(rand.NextDouble() * initialUnallocatedParts.Count);        while(initialUnallocatedParts[index] == null)        {          index = (int)(rand.NextDouble() * initialUnallocatedParts.Count);        }        allocatedParts.Add(initialUnallocatedParts[index]);        //initialUnallocatedParts.RemoveAt(index); // 移除图片        initialUnallocatedParts[index] = null;        map[i] = index;             // 添加地图      }    }    /// <summary>    /// 再创建一个空白矩形    /// </summary>    private void CreateBlankRect()    {      Rectangle rectPart      = new Rectangle();      rectPart.Fill        = new SolidColorBrush(Colors.White);      rectPart.Margin       = new Thickness(0);      rectPart.HorizontalAlignment = HorizontalAlignment.Stretch;      rectPart.VerticalAlignment  = VerticalAlignment.Stretch;      allocatedParts.Add(rectPart);      map[8] = 8;    }    /// <summary>    /// 方块点击事件    /// </summary>    private void rectPart_MouseDown(object sender, MouseButtonEventArgs e)    {      //get the source Rectangle, and the blank Rectangle      //NOTE : Blank Rectangle never moves, its always the last Rectangle      //in the allocatedParts List, but it gets re-allocated to       //different Gri Row/Column      Rectangle rectCurrent = sender as Rectangle;            //当前方块      Rectangle rectBlank  = allocatedParts[allocatedParts.Count - 1];  //缺省方块      //得到白块和缺省方块的位置      int currentTileRow = (int)rectCurrent.GetValue(Grid.RowProperty);      int currentTileCol = (int)rectCurrent.GetValue(Grid.ColumnProperty);      int currentBlankRow = (int)rectBlank.GetValue(Grid.RowProperty);      int currentBlankCol = (int)rectBlank.GetValue(Grid.ColumnProperty);      //白块能移动的四个位置      List<PossiblePositions> posibilities = new List<PossiblePositions>();      posibilities.Add(new PossiblePositions { Row = currentBlankRow - 1, Col = currentBlankCol });      posibilities.Add(new PossiblePositions { Row = currentBlankRow + 1, Col = currentBlankCol });      posibilities.Add(new PossiblePositions { Row = currentBlankRow, Col = currentBlankCol - 1 });      posibilities.Add(new PossiblePositions { Row = currentBlankRow, Col = currentBlankCol + 1 });      //检查该方块是否能点击(白块能移动到当前方块的位置)      bool validMove = false;      foreach (PossiblePositions position in posibilities)        if (currentTileRow == position.Row && currentTileCol == position.Col)          validMove = true;      //only allow valid move      if (validMove)      {        //交换位置        rectCurrent.SetValue(  Grid.RowProperty, currentBlankRow);        rectCurrent.SetValue(Grid.ColumnProperty, currentBlankCol);        rectBlank .SetValue(  Grid.RowProperty, currentTileRow);        rectBlank .SetValue(Grid.ColumnProperty, currentTileCol);        //更新地图        int indexCur  = currentTileRow * 3 + currentTileCol;        int indexBlank = currentBlankRow * 3 + currentBlankCol;        int temp = map[indexCur];        map[indexCur] = map[indexBlank];        map[indexBlank] = temp;        //判断是否成功        if (isSuccess())        {          MessageBox.Show("成功了,好棒啊!");        }      }    }    /// <summary>    /// 验证是否游戏成功    /// </summary>    /// <returns></returns>    private bool isSuccess()    {      for (int i = 0; i < 9; i++)      {        if(map[i]!=i)        {          return false;        }      }      return true;    }  }  /// <summary>  /// Simply struct to store Row/Column data  /// </summary>  struct PossiblePositions  {    public int Row { get; set; }    public int Col { get; set; }  }

PuzzleForImage.cs

运行效果:

还存在的问题:

1、现在图片会被拉伸,暂时没想到好的办法。

2、会随机一些拼不出来的拼图