现在的位置: 首页 > 综合 > 正文

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

2012年05月18日 ⁄ 综合 ⁄ 共 6678字 ⁄ 字号 评论关闭

[索引页]
[源码下载]

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

作者:webabcd

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

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

在线DEMO

Get Microsoft Silverlight

思路
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

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using YYMatch.Models;
using System.Collections.ObjectModel;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;

namespace YYMatch.ViewModels
{
    
/// <summary>
    
/// 连连看核心模块
    
/// </summary>

    public class Core : INotifyPropertyChanged
    
{
        ObservableCollection
<CardModel> _cards = null;
        
int _rows = 0;
        
int _columns = 0;
        SynchronizationContext _syncContext 
= null;

        
public Core()
        
{
            
// 在容器上布满空的卡片
            _cards = new ObservableCollection<CardModel>();
            
for (int i = 0; i < Global.ContainerColumns * Global.ContainerRows; i++)
            
{
                _cards.Add(
new CardModel("00", i));
            }


            _syncContext 
= SynchronizationContext.Current;
        }


        
public void Start(int rows, int columns)
        
{
            _rows 
= rows;
            _columns 
= columns;

            InitCard();
        }


        
private ObservableCollection<CardModel> InitCard()
        
{
            Random r 
= new Random();
            
// 卡片集合在容器内的范围
            int minX = (Global.ContainerColumns - _columns) / 2;
            
int maxX = minX + _columns - 1;
            
int minY = (Global.ContainerRows - _rows) / 2;
            
int maxY = minY + _rows - 1;

            
for (int x = 0; x < Global.ContainerColumns; x++)
            
{
                
for (int y = 0; y < Global.ContainerRows; y++)
                
{
                    
// 18 张图随机排列
                    string imageName = r.Next(1, Global.ImageCount + 1).ToString().PadLeft(2'0');
                    var cardPoint 
= new CardPoint(x, y);

                    
if (x >= minX && x <= maxX && y >= minY && y <= maxY)
                    
{
                        _cards[cardPoint.Position] 
= new CardModel(imageName, cardPoint.Position);
                    }

                }

            }


            
// 相同的卡片个数为奇数的集合
            var oddImages = _cards.Where(p => p.ImageName != Global.EmptyImageName)
                .GroupBy(p 
=> p.ImageName)
                .Select(p 
=> new { ImageName = p.Key, Count = p.Count() })
                .Where(p 
=> p.Count % 2 > 0)
                .ToList();

            
// 如果 oddImages 集合的成员为奇数个(保证容器容量为偶数个则不可能出现这种情况)
            if (oddImages.Count() % 2 > 0)
            
{
                
throw new Exception("无法初始化程序");
            }

            
else
            
{
                
// 在集合中将所有的个数为奇数的卡片各自取出一个放到 temp 中
                
// 将 temp 一刀切,使其右半部分的卡片的 ImageName 依次赋值为左半部分的卡片的 ImageName
                
// 由此保证相同的卡片均为偶数个
                List<CardModel> tempCards = new List<CardModel>();
                
for (int i = 0; i < oddImages.Count(); i++)
                
{
                    
if (i < oddImages.Count() / 2)
                    
{
                        var tempCard 
= _cards.Last(p => p.ImageName == oddImages.ElementAt(i).ImageName);
                        tempCards.Add(tempCard);
                    }

                    
else
                    
{
                        var tempCard 
= _cards.Last(p => p.ImageName == oddImages.ElementAt(i).ImageName);
                        _cards[tempCard.Position].ImageName 
= tempCards[i - oddImages.Count() / 2].ImageName;
                    }

                }

            }


            
if (!IsActive())
                Replace();

            
return _cards;
        }


        
/// <summary>
        
/// 判断两卡片是否可消
        
/// </summary>

        public bool Match(CardModel c1, CardModel c2, bool removeCard)
        
{
            
bool result = false;

            
if (c1.ImageName != c2.ImageName
                
|| c1.ImageName == Global.EmptyImageName
                
|| c2.ImageName == Global.EmptyImageName
                
|| c1.Position == c2.Position)
                
return false;

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

            CardPoint p1 
= new CardPoint(c1.Position);
            CardPoint p2 
= new CardPoint(c2.Position);

            var p1xs 
= GetXPositions(p1);
            var p1ys 
= GetYPositions(p1);
            var p2xs 
= GetXPositions(p2);
            var p2ys 
= GetYPositions(p2);

            
// 在两点各自的 X 轴方向上找可消点(两个可消点的 X 坐标相等)
            var pxs = from p1x in p1xs
                      join p2x 
in p2xs
                      on p1x.X equals p2x.X
                      select 
new { p1x, p2x };
            
foreach (var px in pxs)
            
{
                
if (MatchLine(p1, px.p1x) && MatchLine(px.p1x, px.p2x) && MatchLine(px.p2x, p2))
                
{
                    
int length = Math.Abs(p1.X - px.p1x.X) + Math.Abs(px.p1x.Y - px.p2x.Y) + Math.Abs(px.p2x.X - p2.X);

                    
// 查找最短连接路径
                    if (length < minLength)
                    
{
                        minLength 
= length;
                        point1 
= p1;
                        point2 
= px.p1x;
                        point3 
= px.p2x;
                        point4 
= p2;
                    }

                    result 
= true;
                }

            }


            
// 在两点各自的 Y 轴方向上找可消点(两个可消点的 Y 坐标相等)
            var pys = from p1y in p1ys
                      join p2y 
in p2ys
                      on p1y.Y equals p2y.Y
                      select 
new { p1y, p2y };
            
foreach (var py in pys)
            
{
                
if (MatchLine(p1, py.p1y) && MatchLine(py.p1y, py.p2y) && MatchLine(py.p2y, p2))
                
{
                    
int length = Math.Abs(p1.Y - py.p1y.Y) + Math.Abs(py.p1y.X - py.p2y.X) + Math.Abs(py.p2y.Y

抱歉!评论已关闭.