找回密码
 立即注册
首页 业界区 业界 游戏人生Silverlight(4) - 连连看

游戏人生Silverlight(4) - 连连看

汹萃热 2025-5-30 01:11:18
[索引页]
[源码下载]



游戏人生Silverlight(4) - 连连看[Silverlight 2.0(c#)]

作者:webabcd


介绍
使用 Silverlight 2.0(c#) 开发一个连连看游戏


玩法
用鼠标左键选中卡片,如果选中的两卡片间的连线不多于 3 根直线,则选中的两卡片可消除


在线DEMO
1.png



思路
1、卡片初始排列算法:已知容器容量为 x, 不重复的卡片数量为 y, x >= y && x % 2 == 0, 首先在容器内随机排列卡片,然后取出容器内相同的卡片个数为奇数的集合(集合内成员数量必为偶数个),最后将该集合一刀切,将集合右半部分的卡片的依次复制到集合左半部分。以上算法保证了在一定随机率的基础上,不会出现相同的卡片个数为奇数的情况
2、无解算法和重排算法:在容器内存在的卡片中,两两计算是否存在可消路径,如果没有就是无解,需要重排。重排时,需要得到现存的卡片集合和卡片位置集合,在卡片集合中随机取卡片(取出一个,原集合就要移除这一个),然后依次放到卡片位置集合内,从而达到将现存卡片重新排列的目的
3、两点消去路径的算法以及取最优消去路径的算法:取玩家选的第一点的 x 轴方向和 y 轴方向上的所有无占位符的坐标集合(包括自己),名称分别为 x1s, y1s;取玩家选的第二点的 x 轴方向和 y 轴方向上的所有无占位符的坐标集合(包括自己),名称分别为 x2s, y2s。先在 x1s 和 x2s 中找 x 坐标相等的两点,然后找出该两点与玩家选的两点可组成一条连续的直线的集合,该集合就是可消路径的集合,之后同理再在 y1s 和 y2s 中找到可消路径的集合。两集合合并就是玩家选中的两点间的所有可消路径的集合,该集合为空则两点不可消,该集合内的最短路径则为最优消去路径,集合内的 4 点连接线则为消去路径的连接线
4、游戏使用MVVM(Model - View - ViewModel)模式开发


关键代码
Core.cs
2.gif
using System;
3.gif
using System.Net;
4.gif
using System.Windows;
5.gif
using System.Windows.Controls;
6.gif
using System.Windows.Documents;
7.gif
using System.Windows.Ink;
8.gif
using System.Windows.Input;
9.gif
using System.Windows.Media;
10.gif
using System.Windows.Media.Animation;
11.gif
using System.Windows.Shapes;
12.gif

13.gif
using YYMatch.Models;
14.gif
using System.Collections.ObjectModel;
15.gif
using System.Linq;
16.gif
using System.Collections.Generic;
17.gif
using System.ComponentModel;
18.gif
using System.Threading;
19.gif

20.gif
namespace YYMatch.ViewModels
21.gif
22.gif
23.png
{
24.gif
25.gif
    /**//// 
26.gif
    /// 连连看核心模块
27.gif
    /// 
28.gif
    public class Core : INotifyPropertyChanged
29.gif
30.gif
    
31.png
{
32.gif
        ObservableCollection _cards = null;
33.gif
        int _rows = 0;
34.gif
        int _columns = 0;
35.gif
        SynchronizationContext _syncContext = null;
36.gif

37.gif
        public Core()
38.gif
39.gif
        
40.png
{
41.gif
            // 在容器上布满空的卡片
42.gif
            _cards = new ObservableCollection();
43.gif
            for (int i = 0; i  new 
44.png
{ ImageName = p.Key, Count = p.Count() })
45.gif
                .Where(p => p.Count % 2 > 0)
46.gif
                .ToList();
47.gif

48.gif
            // 如果 oddImages 集合的成员为奇数个(保证容器容量为偶数个则不可能出现这种情况)
49.gif
            if (oddImages.Count() % 2 > 0)
50.gif
51.gif
            
52.png
{
53.gif
                throw new Exception("无法初始化程序");
54.gif
            }
55.gif
            else
56.gif
57.gif
            
58.png
{
59.gif
                // 在集合中将所有的个数为奇数的卡片各自取出一个放到 temp 中
60.gif
                // 将 temp 一刀切,使其右半部分的卡片的 ImageName 依次赋值为左半部分的卡片的 ImageName
61.gif
                // 由此保证相同的卡片均为偶数个
62.gif
                List tempCards = new List();
63.gif
                for (int i = 0; i  p.ImageName == oddImages.ElementAt(i).ImageName);
64.gif
                        _cards[tempCard.Position].ImageName = tempCards[i - oddImages.Count() / 2].ImageName;
65.gif
                    }
66.gif
                }
67.gif
            }
68.gif

69.gif
            if (!IsActive())
70.gif
                Replace();
71.gif

72.gif
            return _cards;
73.gif
        }
74.gif

75.gif
76.gif
        /**//// 
77.gif
        /// 判断两卡片是否可消
78.gif
        /// 
79.gif
        public bool Match(CardModel c1, CardModel c2, bool removeCard)
80.gif
81.gif
        
82.png
{
83.gif
            bool result = false;
84.gif

85.gif
            if (c1.ImageName != c2.ImageName
86.gif
                || c1.ImageName == Global.EmptyImageName
87.gif
                || c2.ImageName == Global.EmptyImageName
88.gif
                || c1.Position == c2.Position)
89.gif
                return false;
90.gif

91.gif
            // 如果可消的话,则 point1, point2, point3, point4 会组成消去两卡片的路径(共4个点)
92.gif
            CardPoint point1 = new CardPoint(0);
93.gif
            CardPoint point2 = new CardPoint(0);
94.gif
            CardPoint point3 = new CardPoint(0);
95.gif
            CardPoint point4 = new CardPoint(0);
96.gif
            // 最小路径长度
97.gif
            int minLength = int.MaxValue;
98.gif

99.gif
            CardPoint p1 = new CardPoint(c1.Position);
100.gif
            CardPoint p2 = new CardPoint(c2.Position);
101.gif

102.gif
            var p1xs = GetXPositions(p1);
103.gif
            var p1ys = GetYPositions(p1);
104.gif
            var p2xs = GetXPositions(p2);
105.gif
            var p2ys = GetYPositions(p2);
106.gif

107.gif
            // 在两点各自的 X 轴方向上找可消点(两个可消点的 X 坐标相等)
108.gif
            var pxs = from p1x in p1xs
109.gif
                      join p2x in p2xs
110.gif
                      on p1x.X equals p2x.X
111.gif
112.gif
                      select new 
113.png
{ p1x, p2x };
114.gif
            foreach (var px in pxs)
115.gif
116.gif
            
117.png
{
118.gif
                if (MatchLine(p1, px.p1x) && MatchLine(px.p1x, px.p2x) && MatchLine(px.p2x, p2))
119.gif
120.gif
                
121.png
{
122.gif
                    int length = Math.Abs(p1.X - px.p1x.X) + Math.Abs(px.p1x.Y - px.p2x.Y) + Math.Abs(px.p2x.X - p2.X);
123.gif

124.gif
                    // 查找最短连接路径
125.gif
                    if (length  Math.Min(p1.Position, p2.Position)
126.gif
                && p.Position  (p.Position - p1.Position) % Global.ContainerColumns == 0);
127.gif
            };
128.gif

129.gif
            if (range.Count() == 0 || range.All(p => p.ImageName == Global.EmptyImageName))
130.gif
                return true;
131.gif

132.gif
            return false;
133.gif
        }
134.gif

135.gif
136.gif
        /**//// 
137.gif
        /// 获取指定的 CardPoint 的 X 轴方向上的所有 ImageName 为 Global.EmptyImageName 的 CardPoint 集合
138.gif
        /// 
139.gif
        private List GetXPositions(CardPoint p)
140.gif
141.gif
        
142.png
{
143.gif
144.gif
            var result = new List() 
145.png
{ p };
146.gif
            for (int i = 0; i 
147.gif
148.gif
                        
149.png
{
150.gif
                            Points.Clear();
151.gif
                        },
152.gif
                        null
153.gif
                    );
154.gif
                }
155.gif
            );
156.gif
            thread.Start();
157.gif
        }
158.gif

159.gif
160.gif
        /**//// 
161.gif
        /// CardPoint 转换成坐标位置 Point
162.gif
        /// 
163.gif
        private Point CardPoint2Point(CardPoint cardPoint)
164.gif
165.gif
        
166.png
{
167.gif
            // 38 - 每个正方形卡片的边长
168.gif
            // 19 - 边长 / 2
169.gif
            // cardPoint.X * 2 - 卡片的 Padding 为 1 ,所以卡片间的间距为 2
170.gif
            var x = cardPoint.X * 38 + 19 + cardPoint.X * 2;
171.gif
            var y = cardPoint.Y * 38 + 19 + cardPoint.Y * 2;
172.gif

173.gif
            return new Point(x, y);
174.gif
        }
175.gif

176.gif
177.gif
        /**//// 
178.gif
        /// 检查当前是否仍然有可消除的卡片
179.gif
        /// 
180.gif
        public bool IsActive()
181.gif
182.gif
        
183.png
{
184.gif
            var currentCards = _cards.Where(p => p.ImageName != Global.EmptyImageName).ToList();
185.gif

186.gif
            for (int i = 0; i  p.ImageName).ToList();
187.gif
            var targetPositions = currentCards.Select(p => p.Position).ToList();
188.gif

189.gif
            for (int i = 0; i  p.ImageName != Global.EmptyImageName).Count(); }
190.gif
        }
191.gif

192.gif
193.gif
        /**//// 
194.gif
        /// 连连看的卡片集合
195.gif
        /// 
196.gif
        public ObservableCollection Cards
197.gif
198.gif
        
199.png
{
200.gif
201.gif
            get 
202.png
{ return _cards; }
203.gif
        }
204.gif

205.gif
        private PointCollection _points;
206.gif
207.gif
        /**//// 
208.gif
        /// 可消两卡片的连接路径上的 4 个点的集合
209.gif
        /// 
210.gif
        public PointCollection Points
211.gif
212.gif
        
213.png
{
214.gif
            get
215.gif
216.gif
            
217.png
{
218.gif
                if (_points == null)
219.gif
                    _points = new PointCollection();
220.gif

221.gif
                return _points;
222.gif
            }
223.gif
            set
224.gif
225.gif
            
226.png
{
227.gif
                _points = value;
228.gif
                if (PropertyChanged != null)
229.gif
                    PropertyChanged(this, new PropertyChangedEventArgs("oints"));
230.gif
            }
231.gif
        }
232.gif

233.gif
        public event PropertyChangedEventHandler PropertyChanged;
234.gif
    }
235.gif
}
236.gif

237.gif


OK
[源码下载]

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册