您的位置:首页 > 编程语言 > C#

WPF实现蜘蛛纸牌游戏

2018-01-01 00:40 661 查看

WPF制作蜘蛛纸牌

一、结果展示



二、需求分析

1. 蜘蛛纸牌游戏逻辑分析:

胜利规则:移除游戏界面内的所有牌;

操作:通过鼠标拖动,将一组(张)牌从一个牌堆移动到另一个牌堆;发牌;

发牌规则:为每一个牌堆新增一张牌;只有每一个牌堆里都有牌时才允许该操作;

移动规则:这组牌为同种花色且从上到下牌面数字形成降序排列。

移除规则:一个牌堆里出现从K到A的同色降序牌组;

得分规则:一次移动的牌组数目越多,得分越多;

2. WPF程序功能分析:

1)支持选择游戏难度:单花色或者双花色;

2)支持新建游戏、保存游戏、打开游戏;

3. WPF界面分析:

1)中间区域显示操作数以及得分;

2)右下角区域为发牌区,方便玩家发牌;

3)左下角区域为已经完成的牌组;

三、代码设计



采用WPF完成界面:

该游戏中共有三个窗体:MainWindow窗体为主游戏窗体、GameWay窗体实现选择游戏方式的功能(新游戏或者打开存盘游戏)、MyDifficultyChooser窗体实现选择游戏难度的功能(单花色或者双花色);

游戏逻辑部分:

游戏逻辑主要在PuckStack类完成,包括判断是否可以移动牌组、接收牌组、移除牌组等功能;PuckStackServer类是PuckStack类的一个管理类,相当于MVC架构中的C,沟通前端数据源和数据处理者;

FinishPosition类、GameStackPosition类、UnfinishPosition类为三个与位置相关的辅助类,分别负责左下角区域相关图片绘制时的坐标计算、牌堆中牌图片的坐标计算和发牌区图片坐标计算;

card类是Puck类的浓缩版,在PuckMaker类洗牌时使用,但是使用了这个类来记录牌的基本信息,然后根据这些基本信息生成List<Puck>,在写博客时发现完全不需要这么做,只需要为Puck类添加一个2参数的构造函数即可,为什么会出现这种情况?答案在最后揭晓 :-)~

PuckGroup只有一个成员变量,就是一个List<Puck> 为什么使用一个类来做外壳呢?因为在生成游戏牌组的时候是10张牌每组,共10组余4张,然后再分配给第1~4组,一个组里面的牌分别属于十个游戏组,每一游戏组对应游戏界面一个游戏堆;游戏管理是按游戏组管理的,而游戏组内部也使用List<Puck> 作为数据容器,当很多地方都出现<Puck> 时就很容易搞混,当时应该是对游戏组和生成的牌组之间的关系不太明白,所以就用了类做外壳;

菜单设计:

在对应窗体的waml文件里编辑即可;

四、知识点

蜘蛛纸牌涉及到的计算比五子棋游戏要复杂一些;主要的计算为图片坐标的计算;

将蜘蛛纸牌的游戏规则转换为代码逻辑的过程中下标的应用很容易混淆:这个变量到底是从1开始的还是从0开始的?,到底要不要减一?(有时候使用从1开始的计数比较方便,比如标记个数,第1个总比第0个好理解一点,有时0会比较好,比如获取数组里的对象之类的),可怕的是没有一个统一的标准,两种同时混用,如果记得不是很清楚(比如,今天使用昨天声明的变量等情况),很容易出现数组越界之类让人头大的bug;

其实这是大二上C#实验课的结课作业,当时编程经验少,也没什么面向对象的概念,觉得变量、方法凑一起就算封装啦,所以代码中有很多现在看来很明显的不足,card类的使用就是一例:大概是因为考虑到List交换元素(洗牌)的过程中需要移除元素然后再插入元素,这样效率很低,所以就想先用数组产生牌的相关序列信息,然后用这些信息再产生List<Puck>于是有了card类;但是为啥没用Puck的数组?可能是以为对象间赋值会产生新的中间对象(应该是对C#面向对象以及对象数组的本质认识不足[说的现在就很了解一样:-)]),反正就蠢蠢地“面向对象”了。还有就是将游戏中的Image同代码中Puck类相关联的字典,的确在游戏中存在根据图像找到Puck(判断是否可以移动之类的)和根据Puck找到图像(收牌的时候需要将图片从界面中移除)的场景,所以我使用了两个Dictionary!一个Image做键,一个Puck做键,当然功能上来说没有问题,可是应该有更合理的方法(未测试,如有错误,还请指正):继承Image类,产生Image类的子类MyImage,然后在里面持有一个Puck类对象,然后在Puck类里持有一个MyImage对象,这样似乎更“面向对象”一些 :-)。

项目源码CSDN下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐