Silverlight3游戏开发之空当接龙基础篇



说明:我是我2011年发表在IT168上面的一篇空当接龙文章的第一部分,后面几部分不好查找了。当然,我主要侧重学习微软ASP.NET及Silverlight+Windows Phone 7开发等技术。搬到此处,仅供学员参考。另外,注意中仅针对中高级玩家,而且我使用的是随机的发牌技术。



在本篇中,我们将讨论空当接龙游戏开发中的基础编程工作。  


一、定义全局变量

  本游戏中使用的关键数据结构列举如下:

  

private int nMaxMovingCards = 13;

  DispatcherTimer timer;

  private Card CurrentCard;

  private Card InverseColorCard;

  private Card SecondInverseColorCard;

  private Card PreviousMatchedCardInSeryAtBottom;

  private List topElementList;

  Card PreviousMatchedCardInCells;

  int iGlobalCellsIII = -1;

  List PlaceHolder;

  Card[] Cells=new Card[4];

  List[] FoundationPiles ;

  List[] TableauPiles;

  DateTime timeStart;

  int zIndexForAll = 0;

  private Cursor originalCursor;

  private GameOver gameoverDlg;

  private MoveMultiCardsDlg MoveMultiCardsDlg;

  InverseColorClickBehavior[] InverseBehaviorArray;

  int iGlobalBottomColumn = -1;

  int iGlobalBottomColumn2 = -1;

  int iGlobalCellsColumn = -1;

  下面分别给出这些变量的作用介绍。

  nMaxMovingCards:用于限制底部可移动的最大扑克数。

  timer:一个定时器控件,用于控制游戏总进程。

  CurrentCard:用于存储当前扑克。当你单击左上方可用单元或下部发牌区的任意一张扑克(除去右上方的回收单元)时,当前扑克即被存储到此变量中。

  InverseColorCard:用于存储当前的反色扑克。

  SecondInverseColorCard:用于存储屏幕下部最近出现的反色扑克。

  topElementList:用于记录屏幕下部可能存在的有效扑克序列,这个序列中的扑克将从一列移动到另一列上。

  PreviousMatchedCardInSeryAtBottom:与变量topElementList联合应用,用于标记下部的有效序列中的第一张扑克。

  Cells:一个Card数组,用于记录屏幕左上方右用单元区的4张扑克。

  FoundationPiles:一个List数组,用于记录屏幕右上方回收单元中的四叠扑克。

  TableauPiles:一个List数组,用于记录下部的8叠扑克。

  InverseBehaviorArray:一个InverseColorClickBehavior数组,用于关联到52张扑克中以实现反色效果。

  关于另外几个变量的作用,在此不再赘述。在接下来的文章中将结合代码介绍其作用。

  二、选择移动多张扑克的对话框

  在空当接龙游戏中,当你可能要移动多张扑克时将弹出一个对话框MoveMultiCardsDlg,如下图所示。你可以根据情况,选择移动一张还是多张。

  注意到,在上图游戏主界面中,在我们刚刚单击过的下部栈区存在一组有序的扑克,而当前单击的这一列为空。此时将弹出一个相关对话框提示你想要把一张还是多张扑克移动到这个空栏。而移动扑克的实际张数依赖于可用的中介单元的总数而定。

  三、初始化占位符

  为了方便确定扑克的位置,我们在本游戏中也引入了一个称为PlaceHolder的List列表。我们共定义了16个占位符,它们的初始化是在游戏初始化的InitPlaceHolder方法中实现的。主要实现代码如下:

  

private void InitPlaceHolder(){

  PlaceHolder = new List(16);

  PlaceHolder.Add(new Rect(3 + PADDING, 0 + PADDING, WIDTH, border="1" Height1));//cell1

  //……省略其他

  PlaceHolder.Add(new Rect(343 + PADDING, 0 + PADDING, WIDTH, border="1" Height1));//topright1

  //……省略其他

  PlaceHolder.Add(new Rect(0 + PADDING, 114 + PADDING, WIDTH, border="1" Height2));//bottom1

  //……省略其他

  }

  16个占位符中,4个相应于左上方的可用单元,4个相应于右上方的回收单元,剩下的8个对应于下部8列。

  下面,我们来讨论如何使用上面定义好的数据结构来生成扑克与发牌的问题。

  四、生成扑克与发牌

  首先,发牌操作是在GenerateAndDealCards方法中实现的。

  (1)生成52张随机顺序的扑克

  首先,应当以随机的顺序生成52张扑克:

  

private void GenerateAndDealCards(){

  Card[] arrPoker = new Card[52];

  Card[] OrderPoker = new Card[52];

  int[] RandomI = new int[52];

  int curNum;

  RandomKDiffer(0, 51, 52, RandomI);

  for (int i = 0; i < 52; i++){

  curNum = i < 13 ? i + 1 : ((i + 1) % 13 == 0 ? 13 : (i + 1) % 13);//range 1~13

  if (i < 13) //0-12

  OrderPoker[i] = new Card(curNum, Suits.Clubs);

  else if (i < 26) //13-25

  OrderPoker[i] = new Card(curNum, Suits.Diamonds);

  else if (i < 39) //26-38

  OrderPoker[i] = new Card(curNum, Suits.Hearts);

  else

  OrderPoker[i] = new Card(curNum, Suits.Spades);

  arrPoker[RandomI[i]] = OrderPoker[i];//乱序

  InverseBehaviorArray[i].Attach(arrPoker[RandomI[i]]);

  //……省略其他

  }

  首先,我们定义一个Card数组arrPoker来存储52张随机顺序的扑克。另一个Card数组OrderPoker用于存储52张按自小到大顺序的扑克。

  其次,借助于方法RandomKDiffer的帮助,我们生成序号从0到51的52张不同的扑克。

  接下来,存储在数组arrPoker中的52张扑克都被初始化为正面向上(其实在空当接龙游戏中根本没有正面朝下的情况)。

  最后,一旦生成一张扑克即把一个相关的InverseColorClickBehavior行为附加到其上。

  (2)创建游戏主界面中的初始元素

  当玩家按下菜单“Game”—“Start”后,界面底部的52张扑克准备就绪。下图给出了游戏开始时的运行时快照。

  注意到,我们在上部添加了一些矩形控件用于修饰可用单元和回收单元。当然,你也可以采用其他的策略,但是我们必须注意由此产生的一些“影响”。

  具体来说,本游戏中有两处涉及到这个“影响”。一处是前面讨论过的获取当前扑克牌的方法GetCurrentCard。另一处是我们应当何时及怎样添加上述矩形控件。

  首先,我们选择在方法GenerateAndDealCards中添加这些矩形。不过,在单击“Start”菜单前,屏幕上是看不到这些矩形的。

  其次,我们决定在正式加载扑克控件前以动态方法加载这些矩形相关的XAML代码。

  那么,如何动态加载呢?下面讨论完成这项任务的LoadRectangleElementsFirst方法。此方法的关键代码如下:

  

private void LoadRectangleElementsFirst(){

  XElement rectanglestr = XElement.Parse(

  @"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  Fill="Red" Stroke="Black" border="1"  height="32"  width="29" Canvas.Left="308" Canvas.Top="29" />");

  cardContainer.Children.Add(XamlReader.Load(rectanglestr.ToString()) as UIElement);

  XElement p3Str = XElement.Parse(

  @"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

 
 Fill="White" Stretch="Fill" border="1"  height="100"  width="1"
UseLayoutRounding="False" Canvas.Left="75" Data="M319,100 L319,8"
Stroke="#FFBEFF00"/>");

  cardContainer.Children.Add(XamlReader.Load(p3Str.ToString()) as UIElement);

  XElement p2Str = XElement.Parse(

  @"

  xmlns="http://schemas.microsoft.com/client/2007"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

 
 Fill="White" Stretch="Fill" Stroke="Black" border="1"  height="100"  
width="1" UseLayoutRounding="False" Canvas.Left="0" Data="M319,100
L319,8"/>");

  cardContainer.Children.Add(XamlReader.Load(p2Str.ToString()) as UIElement);

  //……省略其他

  cardContainer.Children.Add(XamlReader.Load(p0_Copy6Str.ToString()) as UIElement);

  }

  在上面代码中,有如下几点值得注意:

  使用LINQ to XML技术动态创建XAML元素。

  程序开始必须先添加对于程序集System.Xml.Linq.dll的引用。

  创建了大量的XElement对象并填充以繁琐的XAML标记。

  ?在每一个XElement对象中,必须要声明两个默认的XML命名空间;否则,我们会遇到如下运行时错误:AG_E_PARSER_MISSING_DEFAULT_NAMESPACE。

  五、把扑克控件添加到容器控件中

  在游戏的开始,仅有屏幕下部存在扑克。其中,从左边起的前4列各有7张随机生成的扑克,后4列放置6张随机生成的扑克。相关代码如下:

  

for (int column = 0; column < 4; column++){

  for (int i = 7 * column; i < 7 * (column + 1); i++) {

  Canvas.SetLeft(arrPoker[i], (double)PlaceHolder[8 + column].X);

  Canvas.SetTop(arrPoker[i], (double)PlaceHolder[8 + column].Y + LARGE_OFFSET * (i - 7 * column));

  TableauPiles[column].Add(arrPoker[i]);

  cardContainer.Children.Add(arrPoker[i]);

  }

  }

  for (int column = 0; column < 4; column++){

  for (int i = 6 * column + 28; i < 6 * column + 34; i++){

  Canvas.SetLeft(arrPoker[i], (double)PlaceHolder[12 + column].X);

  Canvas.SetTop(arrPoker[i], (double)PlaceHolder[12 + column].Y + LARGE_OFFSET * (i - 6 * column - 28));

  TableauPiles[column + 4].Add(arrPoker[i]);

  cardContainer.Children.Add(arrPoker[i]);

  }

  }

  上面代码通过二个简单的二重foreach循环语句把生成的随机顺序的52张扑克依次添加到容器控件cardContainer中。

  六、开始玩游戏

  通过菜单控件来控制本游戏的总体流程不但简化了程序设计而且使程序操作类似于传统桌面应用。启动游戏的代码如下所示:

  

private void MenuItem_Click(object sender, RoutedEventArgs e){

  string sText = (sender as MenuItem).MenuText.Trim();

  switch (sText) {

  case "Start":

  InitAndStartGame();

  bStart = true;

  break;

  //…省略其他

七、再次玩游戏

 
 作为一个完整的游戏程序,提供重玩游戏是基本的要求。顾名思义,在重新开始下一场游戏前应当把所有数据结构恢复到其最初的数据状态。事实上,这里面还存
在一定的技巧。一方面,恢复工作依赖于你所使用的数据结构;另一方面,恢复工作还依赖于我们从何位置启动这个恢复操作。本游戏中使用的恢复操作相关代码如
下:

  

private void MenuItem_Click(object sender, RoutedEventArgs e)

  {

  string sText = (sender as MenuItem).MenuText.Trim();

  switch (sText) {

  case "Start":

  InitAndStartGame();

  break;

  //…省略其他

  在此,通过调用一个助理方法InitAndStartGame,把所有内容准备就绪。

  下面,我们看一下在纸牌游戏和空当接龙游戏初始化阶段的主要区别。

  

private void InitAndStartGame(){

  if (timer != null) {

  timer.Tick -= new EventHandler(timer_Tick);

  timer.Stop();

  timer = null;

  }

  zIndexForAll = 0;

  PlaceHolder = null;

  timer = new DispatcherTimer();

  timer.Interval = new TimeSpan(0, 0, 1);

  timer.Tick += new EventHandler(timer_Tick);

  InitPlaceHolder();

  TableauPiles = null;

  FoundationPiles = null;

  TableauPiles = new List[8];

  for (int i = 0; i < 8; i++)

  TableauPiles[i] = new List();

  FoundationPiles = new List[4];

  for (int i = 0; i < 4; i++)

  FoundationPiles [i] = new List();

  InverseBehaviorArray = null;

  InverseBehaviorArray = new InverseColorClickBehavior[52];

  for (int i = 0; i < 52; i++)

  InverseBehaviorArray[i] = new InverseColorClickBehavior();

  GenerateAndDealCards();

  for (int i = 0; i < 4; i++)

  Cells[i] = null;

  nMaxMovingCards = 13;

  iGlobalCellsIII = -1;

  iGlobalBottomColumn = -1;

  iGlobalBottomColumn2 = -1;

  iGlobalCellsColumn = -1;

  bStart = false;

  timeStart = new DateTime();

  timeStart = DateTime.Now;

  timer.Start();

  }

  首先,初始化两个重要结构:TableauPiles和FoundationPiles。在此,我们使用数据结构TableauPiles存储游戏主界面底部的8列扑克,而数据结构FoundationPiles用于存储回收单元中的4列扑克。

  接下来,我们创建52个InverseColorClickBehavior类型的行为,它们分别用于关联到52张不同的扑克上。再次强调,在Silverlight编程中,一个行为只能关联到一个UI元素上。

  最后应当注意的是,鼠标相关事件的订阅是在MainPage控件的MainPage_Loaded方法中完成的,而不是在上面的InitAndStartGame方法中,恕不再赘举有关代码。

时间: 2024-08-30 09:16:32

Silverlight3游戏开发之空当接龙基础篇的相关文章

FSM:游戏开发中的有限状态机(理论篇)转

游戏系统的本质是输入加输出.我们把游戏系统划分为多个不同状态,不同的状态在不同输入下产出不同输出.按照这种思想,我们可以把游戏中复杂的子系统,比如战斗系统,划分成多个不同状态,然后我们要做的只是,对于不同的战斗操作输入,转换相应状态,执行相应状态下的动作输出. 那么什么是有限状态机? 我们要说的状态机输入和输出都是离散的.有限的:在这个基础上,我们所说的有限状态机就是描述这一类问题:在有限的输入里,由于不同的输入时序产生的有限的输出组合的映射关系.要描述这种映射关系,有两种表达方式: 状态迁移表

10、Cocos2dx 3.0游戏开发找小三之容器篇:Vector、Map、Value

重开发者的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27705613 容器 3.0版本之前Cocos2d-x 引擎为我们提供了 CCArray. CCDictionary 等 Objective-C 风格的容器: 使用 Cocos2d-x 容器的一个重要原因在于 Cocos2d-x 的内存管理. 一般来说,被存入容器的对象在移除之前都应该保证是有效的, 但值得注意的是,在v3.0 beta版本中加入了数据结

做web开发需要学习哪些技术--基础篇

做一个web网站,包含哪些技术,自己需要学习哪些技术 自己想到哪里就写到哪里 -- 给自己做的一个记录 1: 页面的展示, 一个web的开发语言  1.1 一个web的开发语言需要注意哪方面,才能符合你的网站业务发展     1:语言的选择     2:框架的设计 - 怎么符合未来业务的发展     3:对于业务的了解     4:了解http协议      那么就要了解tcp/ip协议 3: web安全     web安全又有哪些方面需要注意的呢     3.1 xss     3.2 sql

1、Cocos2dx 3.0游戏开发找小三之前言篇

尊重开发者的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27094663 前言 Cocos2d-x 是一个通用平面游戏引擎,基于一个同样十分著名的游戏引擎 Cocos2d-iPhone 设计. 它继承了 Cocos2d 系列引擎一贯的特点:使用简单,运行高效.灵活,且功能强大. 与 Cocos2d-iPhone 不同的是,Cocos2d-x 还拥有强大的跨平台能力,只需要编写一次代码, 就可以无缝地部署在包括

iOS开发范例实战宝典(基础篇)——互动出版网

这篇是计算机类的优质推荐>>>><iOS开发范例实战宝典(基础篇)> 以最新的IOS 8为版本编写,内容覆盖了IOS开发的方方面面,通过大量实例提升实战技能,并对书中的重点和难点进行了专门分析. 编辑推荐 *以最新的iOS 8为版本编写,内容覆盖了iOS开发的方方面面* *通过200多个实例提升实战技能,并对书中的重点和难点进行了专门分析 *注重实战:详细讲解了117个iOS开发经典实例,提高实战开发水平 *内容全面:全面介绍了iOS开发中最为常见的14类界面模块 *由

毕业2年,unity3d游戏开发2个月,第一篇随笔

今天是个值得纪念的日子.因为: 人生第一次通宵加班了,开通博客了,毕业刚好2年了,来上海2个月了. 欧了,说点什么吧(- o -)~zZ 一. [西安的日子]   大学过得很普通很普通,没什么波澜起伏的经历(额,我就不说是浑浑噩噩了,还是打算来电正能量吧@[email protected]).一句话就是——也是顺利毕业了,挂过科,还好有个证.就是毕业后,还觉着没玩好&没学好. 哦对了,在西安上的学,在西安开始的人生第一份工作. 大三去了个还算规模比较大的金融行业的软件公司实习,算是真正上的第一份

MVC模式在游戏开发的应用

原地址: http://www.cocoachina.com/gamedev/2012/1129/5212.html MVC是三个单词的缩写,分别为:模型(Model).视图(View)和控制Controller).MVC是一个设计模式,它强制性地使应用程序的输入.处理和输出分开,将应用程序分成三个核心部件:模型.视图.控制器.它们各自处理自己的任务,关系如图所示: 模型是数据层,视图是表现层,控制器是逻辑层,也对应于程序运行中的数据输入,数据处理,数据输出基本三步骤.事实上,MVC模式开发也适

Unity3D游戏开发初探—2.初步了解3D模型基础

一.什么是3D模型? 1.1 3D模型概述 简而言之,3D模型就是三维的.立体的模型,D是英文Dimensions的缩写. 3D模型也可以说是用3Ds MAX建造的立体模型,包括各种建筑.人物.植被.机械等等,比如一个大楼的3D模型图.3D模型也包括玩具和电脑模型领域. 互联网的形态一直以来都是2D模式的,但是随着3D技术的不断进步,在未来的时间里,将会有越来越多的互联网应用以3D的方式呈现给用户,包括网络视讯.电子阅读.网络游戏.虚拟社区.电子商务.远程教育等等.甚至对于旅游业,3D互联网也能

【读书笔记《Android游戏编程之从零开始》】13.游戏开发基础(Paint 画笔)

1.Paint画笔 Panit(画笔)是绘图额辅助类,其类中包含文字和位图额样式.颜色等属性信息.Paint 的常用方法如下: setAntiAlias(boolean aa) 作用:设置画笔是否无锯齿 参数:true 表示无锯齿,false 表示有锯齿,默认为 false . setAlpha(int a) 作用:设置画笔的透明度 参数:透明值 setTextAlign(Paint.Align align) 作用:设置绘制文本的锚点 参数:Paint.Align 类中的常量 measureTe