XNA实现3D连连看

网站的暑期开发一个月 基本啥都没干 捣鼓XNA 做了一个3D的连连看

缘由是强化班的暑期实践课题,选了连连看来做。MFC太古老, 直接上XNA。平面没新意,3D才好玩。哈哈~~

这个算是自己做的最大的也是最完整的一个软件了,斗胆发到首页,要拍砖的可以把砖送给我自己拍。。。

开发环境 Visual Studio 2008 + XNA Game Studio 3.1 (顺带 3DS Max 2010 和 Adobe的一些工具)

软件命名 Zodiac  因为是十二星座风格的 

半成品软件可以去csdn下载 http://download.csdn.net/source/1495350

源代码点此下载  需要装XNA Game Studio 3.1额...

自认为做的还是很华丽丽的说~~~看看界面:

1 2

 

关于算法 平面的连连看算法没有仔细研究 直接想了下3D的算法

 

ContractedBlock.gif ExpandedBlockStart.gif Code
    /// <summary>
    
/// 连连看抽象单元定义
    
/// </summary>
    public struct LLKBox
    {
        
/// <summary>
        
/// 指示盒子是否被选中
        
/// </summary>
        public bool IsSelected { getset; }
        
/// <summary>
        
/// 表示盒子的贴图索引
        
/// </summary>
        public int Index { getset; }
        
/// <summary>
        
/// 指示盒子是否被建议
        
/// </summary>
        public bool IsSuggested { getset; }
        
/// <summary>
        
/// 盒子的世界坐标
        
/// </summary>
        public Matrix ModelWorldTransform { getset; }
        
/// <summary>
        
/// 盒子是否被删除
        
/// </summary>
        public bool IsDeleted { getset; }

 

平面和3D的规则是一样的:从一个方块按xy(z)方向不超过两个弯无障碍到达另外一个方块

整个大的连连看的定义是一个三维数组,不过由于个人喜好一般定义一维数组转换。假设一个连连看边长为N,即N*N*N大小,定义一维数组LLKBox[] boxes,长度为(N+2)*(N+2)*(N+2),这里声明的数组显示边长为N+2,可以理解为将整个连连看包裹在一个空心的方块中,以便于寻路操作。(不过也有不好的地方,就是大大的增大了数组长度。)

 

ContractedBlock.gif ExpandedBlockStart.gif Code
        #region Translation
        
/// <summary>
        
/// 将三维坐标换算为一维坐标
        
/// </summary>
        
/// <param name="x">x坐标</param>
        
/// <param name="y">y坐标</param>
        
/// <param name="z">z坐标</param>
        
/// <returns>对应的一维坐标</returns>
        internal int ThreeToOne(int x, int y, int z)
        {
            
return MatrixLength * MatrixLength * z + MatrixLength * y + x;
        }
        
/// <summary>
        
/// 将一维坐标换算为三维坐标
        
/// </summary>
        
/// <param name="w">要换算的一味坐标</param>
        
/// <param name="x">换算后的x坐标</param>
        
/// <param name="y">换算后的y坐标</param>
        
/// <param name="z">换算后的z坐标</param>
        internal void OneToThree(int w, out int x, out int y, out int z)
        {
            z 
= w / (MatrixLength * MatrixLength);
            y 
= (w / MatrixLength) % MatrixLength;
            x 
= w % MatrixLength;
        }
        
 

 

连连看的算法基本可以分为两种:递归与非递归(貌似废话)。

简要介绍下递归思想:要使从box1到box2连通,那么从box1向xyz某一方向前进一格(暂且定义为box3),box3和box2必定要连通。如此将box1与box2连通的问题化为box3与box2连通的问题。按此递归直到box3=box1,递归完成。

采用递归方法寻路有些类似于深度优先搜索,在此使用递归虽然代码长度较短但性能不济,即使加上方向权重与自动剪枝,也不能在本质上解决性能问题,况且该方法不能解决找最短路径的问题,故在此舍弃使用。

非递归思想则是对两个方块在空间中的位置做分析,不同的情况使用不同的方法判断连通,并可以找到最短路径。

以下详细介绍非递归思想的算法。

两个方块在空间中的位置可以分为三种情况:
 

x(y z)轴方向上X(Y Z)平行平面内 但不在一直线空间中(不再一直线也不在一个面中)
line face 4

 

对三种情况分别作讨论

 

ContractedBlock.gifExpandedBlockStart.gifCode
        /// <summary>
        
/// 计算两个盒子是否能够消去
        
/// </summary>
        
/// <param name="box1">盒子1的索引</param>
        
/// <param name="box2">盒子2的索引</param>
        
/// <returns>消去的盒子之间的路径 若无法消去则返回null</returns>
        private List<int> Expurgate(int box1, int box2)
        {
            
int x1, y1, z1, x2, y2, z2;
            OneToThree(box1, 
out x1, out y1, out z1);
            OneToThree(box2, 
out x2, out y2, out z2);
            List
<int> path;
            List
<int> path1;
            List
<int> path2;
            List
<int> path3;
            
bool d1 = true, d2 = true, d3 = true, d4 = true;

 

 

x(y z)轴方向上  (仅对x轴方向的情况说明,y z轴方向同x轴)

示意图:
lin2

 

首先从Box1(x1, y, z)直线遍历到Box2(x2, y, z)   (图中黑色箭头表示)

若之间都为空,则两者连通且最短路即为两者的直接连线,无拐点,若不连通,进入下一个判断。

将box1,box2按照+y –y +z -z四个方向开始平移。如朝+y方向分别平移一格得到box1’(x1, y+1, z) box2’(x2, y+1, z),依次判断box1’ box2’是否为空,box1’与box1是否连通,box2’与box2是否连通,box1’与box2’是否连通,若全部满足,则已找到一条最短通路,两个拐点,若都不满足,则无通路。判断结束

 

ContractedBlock.gif ExpandedBlockStart.gif Code
            //In Line X
            if (x1 != x2 && y1 == y2 && z1 == z2)
            {
                
//Check If In One Line
                if ((path = CheckInLineX(y1, z1, x1, x2)) != null)
                    
return MergeOne(path, box1, box2);
                
//Check If In One Face
                for (int i = 1; i < MatrixLength; i++)
                {
                    
if (d1 && y1 + i < MatrixLength && boxes[ThreeToOne(x1, y1 + i, z1)].IsDeleted && boxes[ThreeToOne(x2, y1 + i, z1)].IsDeleted)
                        
if ((path1 = CheckInLineX(y1 + i, z1, x1, x2)) != null)
                            
if ((path2 = CheckInLineY(x1, z1, y1, y1 + i)) != null)
                                
if ((path3 = CheckInLineY(x2, z1, y1, y1 + i)) != null)
                                    
return MergeThree(path1, path2, path3, ThreeToOne(x1, y1 + i, z1), ThreeToOne(x2, y1 + i, z1), box1, box2);
                                
else
                                    d1 
= false;
                            
else
                                d1 
= false;
                    
if (d2 && y1 - i >= 0 && boxes[ThreeToOne(x1, y1 - i, z1)].IsDeleted && boxes[ThreeToOne(x2, y1 - i, z1)].IsDeleted)
                        
if ((path1 = CheckInLineX(y1 - i, z1, x1, x2)) != null)
                            
if ((path2 = CheckInLineY(x1, z1, y1, y1 - i)) != null)
                                
if ((path3 = CheckInLineY(x2, z1, y1, y1 - i)) != null)
                                    
return MergeThree(path1, path2, path3, ThreeToOne(x1, y1 - i, z1), ThreeToOne(x2, y1 - i, z1), box1, box2);
                                
else
                                    d2 
= false;
                            
else
                                d2 
= false;
                    
if (d3 && z1 + i < MatrixLength && boxes[ThreeToOne(x1, y1, z1 + i)].IsDeleted && boxes[ThreeToOne(x2, y1, z1 + i)].IsDeleted)
                        
if ((path1 = CheckInLineX(y1, z1 + i, x1, x2)) != null)
                            
if ((path2 = CheckInLineZ(x1, y1, z1, z1 + i)) != null)
                                
if ((path3 = CheckInLineZ(x2, y1, z1, z1 + i)) != null)
                                    
return MergeThree(path1, path2, path3, ThreeToOne(x1, y1, z1 + i), ThreeToOne(x2, y1, z1 + i), box1, box2);
                                
else
                                    d3 
= false;
                            
else
                                d3 
= false;
                    
if (d4 && z1 - i >= 0 && boxes[ThreeToOne(x1, y1, z1 - i)].IsDeleted && boxes[ThreeToOne(x2, y1, z1 - i)].IsDeleted)
                        
if ((path1 = CheckInLineX(y1, z1 - i, x1, x2)) != null)
                            
if ((path2 = CheckInLineZ(x1, y1, z1, z1 - i)) != null)
                                
if ((path3 = CheckInLineZ(x2, y1, z1, z1 - i)) != null)
                                    
return MergeThree(path1, path2, path3, ThreeToOne(x1, y1, z1 - i), ThreeToOne(x2, y1, z1 - i), box1, box2);
                                
else
                                    d4 
= false;
                            
else
                                d4 
= false;
                }
                
return null;

 

X(Y Z)平行平面内 但不在一直线 (仅对X平行平面的情况说明,Y Z平面同X平面)

示意图1:
 lin2e

计算得到Box1(x, y1, z1) Box2(x, y2, z2)所在矩形的另外两个顶点Box3(x, y1, z2) Box4(x, y2, z1),依次判断这两条路是否连通。若有一条路连通则找到最短路,一个拐点,若无,进入下个判断。

示意图2:
 linedsd

将某一条红色线段朝矩形内平移(分别平移y方向与z方向),分别计算两个中间节点是否为空与3条路是否连通,若都满足则找到一条通路且找到最短路,两个拐点,若无,进入下一个判断

示意图3:
lincce

将某一条红色线段朝举行外平移(+y –y +z -z方向分别平移),分别计算两个中间节点是否为空与3条路是否连通,若都满足则找到一条通路且找到最短路,两个拐点,若无,则两个方块之间无通路。判断结束。

 

ContractedBlock.gif ExpandedBlockStart.gif Code
            //In Face X
            if (x1 == x2 && y1 != y2 && z1 != z2)
            {
                
if (boxes[ThreeToOne(x1, y1, z2)].IsDeleted)
                    
if ((path1 = CheckInLineY(x1, z2, y1, y2)) != null)
                        
if ((path2 = CheckInLineZ(x1, y1, z1, z2)) != null)
                            
return MergeTwo(path1, path2, ThreeToOne(x1, y1, z2), box1, box2);
                
if (boxes[ThreeToOne(x1, y2, z1)].IsDeleted)
                    
if ((path1 = CheckInLineY(x1, z1, y1, y2)) != null)
                        
if ((path2 = CheckInLineZ(x1, y2, z1, z2)) != null)
                            
return MergeTwo(path1, path2, ThreeToOne(x1, y2, z1), box1, box2);

                
int minY = y1 < y2 ? y1 : y2;
                
int maxY = y1 < y2 ? y2 : y1;
                
int minZ = z1 < z2 ? z1 : z2;
                
int maxZ = z1 < z2 ? z2 : z1;

                
for (int i = minY + 1; i < maxY; i++)
                    
if (boxes[ThreeToOne(x1, i, z1)].IsDeleted && boxes[ThreeToOne(x1, i, z2)].IsDeleted)
                        
if ((path1 = CheckInLineZ(x1, i, z1, z2)) != null)
                            
if ((path2 = CheckInLineY(x1, z1, y1, i)) != null)
                                
if ((path3 = CheckInLineY(x1, z2, i, y2)) != null)
                                    
return MergeThree(path1, path2, path3, ThreeToOne(x1, i, z1), ThreeToOne(x1, i, z2), box1, box2);
                
for (int i = minZ + 1; i < maxZ; i++)
                    
if (boxes[ThreeToOne(x1, y1, i)].IsDeleted && boxes[ThreeToOne(x1, y2, i)].IsDeleted)
                        
if ((path1 = CheckInLineY(x1, i, y1, y2)) != null)
                            
if ((path2 = CheckInLineZ(x1, y1, z1, i)) != null)
                                
if ((path3 = CheckInLineZ(x1, y2, i, z2)) != null)
                                    
return MergeThree(path1, path2, path3, ThreeToOne(x1, y1, i), ThreeToOne(x1, y2, i), box1, box2);
                
for (int i = 1; i < MatrixLength; i++)
                {
                    
if (d1 && maxY + i < MatrixLength && boxes[ThreeToOne(x1, maxY + i, z1)].IsDeleted && boxes[ThreeToOne(x2, maxY + i, z2)].IsDeleted)
                        
if ((path1 = CheckInLineZ(x1, maxY + i, z1, z2)) != null)
                            
if ((path2 = CheckInLineY(x1, z1, y1, maxY + i)) != null)
                                
if ((path3 = CheckInLineY(x1, z2, y2, maxY + i)) != null)
                                    
return MergeThree(path1, path2, path3, ThreeToOne(x1, maxY + i, z1), ThreeToOne(x1, maxY + i, z2), box1, box2);
                                
else
                                    d1 
= false;
                            
else
                                d1 
= false;
                    
if (d2 && minY - i >= 0 && boxes[ThreeToOne(x1, minY - i, z1)].IsDeleted && boxes[ThreeToOne(x2, minY - i, z2)].IsDeleted)
                        
if ((path1 = CheckInLineZ(x1, minY - i, z1, z2)) != null)
                            
if ((path2 = CheckInLineY(x1, z1, y1, minY - i)) != null)
                                
if ((path3 = CheckInLineY(x1, z2, y2, minY - i)) != null)
                                    
return MergeThree(path1, path2, path3, ThreeToOne(x1, minY - i, z1), ThreeToOne(x1, minY - i, z2), box1, box2);
                                
else
                                    d2 
= false;
                            
else
                                d2 
= false;
                    
if (d3 && maxZ + i < MatrixLength && boxes[ThreeToOne(x1, y1, maxZ + i)].IsDeleted && boxes[ThreeToOne(x1, y2, maxZ + i)].IsDeleted)
                        
if ((path1 = CheckInLineY(x1, maxZ + i, y1, y2)) != null)
                            
if ((path2 = CheckInLineZ(x1, y1, z1, maxZ + i)) != null)
                                
if ((path3 = CheckInLineZ(x1, y2, z2, maxZ + i)) != null)
                                    
return MergeThree(path1, path2, path3, ThreeToOne(x1, y1, maxZ + i), ThreeToOne(x1, y2, maxZ + i), box1, box2);
                                
else
                                    d3 
= false;
                            
else
                                d3 
= false;
                    
if (d4 && minZ - i >= 0 && boxes[ThreeToOne(x1, y1, minZ - i)].IsDeleted && boxes[ThreeToOne(x2, y1, minZ - i)].IsDeleted)
                        
if ((path1 = CheckInLineY(x1, minZ - i, y1, y2)) != null)
                            
if ((path2 = CheckInLineZ(x1, y1, z1, minZ - i)) != null)
                                
if ((path3 = CheckInLineZ(x1, y2, z2, minZ - i)) != null)
                                    
return MergeThree(path1, path2, path3, ThreeToOne(x1, y1, minZ - i), ThreeToOne(x2, y1, minZ - i), box1, box2);
                                
else
                                    d4 
= false;
                            
else
                                d4 
= false;
                }
                
return null;

 

空间中(不再一直线也不在一个面中)

此种情况其实比较简单 判断方便。直接计算出Box1和Box2作为对角线定点的长方体的各个顶点和各条边,看能否找到一条通路即可。

 

ContractedBlock.gif ExpandedBlockStart.gif Code
            //In 3D
            if (x1 != x2 && y1 != y2 && z1 != z2)
            {
                List
<int>[] l = new List<int>[12];
                
if (boxes[ThreeToOne(x1, y1, z2)].IsDeleted)
                    l[
0= CheckInLineZ(x1, y1, z1, z2);
                
else
                    l[
0= null;
                
if (boxes[ThreeToOne(x1, y2, z1)].IsDeleted)
                    l[
1= CheckInLineY(x1, z1, y1, y2);
                
else
                    l[
1= null;
                
if (boxes[ThreeToOne(x2, y1, z1)].IsDeleted)
                    l[
2= CheckInLineX(y1, z1, x1, x2);
                
else
                    l[
2= null;
                
if (boxes[ThreeToOne(x2, y1, z2)].IsDeleted)
                    l[
3= CheckInLineY(x2, z2, y1, y2);
                
else
                    l[
3= null;
                
if (boxes[ThreeToOne(x2, y2, z1)].IsDeleted)
                    l[
4= CheckInLineZ(x2, y2, z1, z2);
                
else
                    l[
4= null;
                
if (boxes[ThreeToOne(x1, y2, z2)].IsDeleted)
                    l[
5= CheckInLineX(y2, z2, x1, x2);
                
else
                    l[
5= null;
                
if (l[0!= null && l[3!= null)
                    
if ((l[6= CheckInLineX(y1, z2, x1, x2)) != null)
                        
return MergeThree(l[0], l[3], l[6], ThreeToOne(x1, y1, z2), ThreeToOne(x2, y1, z2), box1, box2);
                
if (l[2!= null && l[3!= null)
                    
if ((l[7= CheckInLineZ(x2, y1, z1, z2)) != null)
                        
return MergeThree(l[2], l[3], l[7], ThreeToOne(x2, y1, z1), ThreeToOne(x2, y1, z2), box1, box2);
                
if (l[2!= null && l[4!= null)
                    
if ((l[8= CheckInLineY(x2, z1, y1, y2)) != null)
                        
return MergeThree(l[2], l[4], l[8], ThreeToOne(x2, y1, z1), ThreeToOne(x2, y2, z1), box1, box2);
                
if (l[1!= null && l[4!= null)
                    
if ((l[9= CheckInLineX(y2, z1, x1, x2)) != null)
                        
return MergeThree(l[1], l[4], l[9], ThreeToOne(x1, y2, z1), ThreeToOne(x2, y2, z1), box1, box2);
                
if (l[1!= null && l[5!= null)
                    
if ((l[10= CheckInLineZ(x1, y2, z1, z2)) != null)
                        
return MergeThree(l[1], l[5], l[10], ThreeToOne(x1, y2, z1), ThreeToOne(x1, y2, z2), box1, box2);
                
if (l[0!= null && l[5!= null)
                    
if ((l[11= CheckInLineY(x1, z2, y1, y2)) != null)
                        
return MergeThree(l[0], l[5], l[11], ThreeToOne(x1, y1, z2), ThreeToOne(x1, y2, z2), box1, box2);

 

最后 Over~~~

 

             return   null ;
        }

 稍稍计算时间复杂度,控制在了平方范围内…还好啊…就是代码长度有点长…比较郁闷…

还有好多功能没有开发出来,比如提示之类的。提示是一件比较麻烦的事情,有空还得再想想…

转载于:https://www.cnblogs.com/Kingpro/archive/2009/07/20/1526774.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值