提示功能需要当前关卡所得分数超过100分才能使用
学习一个东西最好的办法就是去用它。这句话一点没错,通过写这个游戏,确实让我初窥了Silverlight的门径。
本来还有很多需要完善的地方比如音效、开始菜单动画以及一些高级玩法。不巧最近鼻炎发作,头痛难耐,实在是提不起精神来完善它了,索性就放出来吧。
宝石迷阵这个游戏的规则很简单,通过交换两个相连宝石的位置,使横着或竖着的相连并相同的宝石超过三个,然后消除它们,相同的越多,所得分数就越高。当交换位置后没有可消除的宝石,就把这两个相连的宝石的位置还原。
用bijou 类 来表示宝石,宝石具有Column、Row这两个属性。像这两个属性赋值时,也就修改了宝石在Grid控件里的位置:
/// <summary>
/// 宝石所在的列
/// </summary>
public int Column
{
get
{
return this._column;
}
set
{
Grid.SetColumn(this, value);
this._column = value;
}
}
private int _row;
/// <summary>
/// 宝石所在的行
/// </summary>
public int Row
{
get
{
return this._row;
}
set
{
Grid.SetRow(this, value);
this._row = value;
}
}
用一个二维数组来存储所有宝石的信息
现在,要实现通过bijous[Column, Row] 来得到指定行和列的宝石的引用。就要保证每一个宝石在bijous中的位置不会错误,并且在Gird中的行和列也要和bijous数组的索引值一样。为此,我实现了一个索引器
/// <summary>
/// 通过列号和行号获取bijou
/// </summary>
/// <param name="Column">列号</param>
/// <param name="Row">行号</param>
/// <returns>bijou</returns>
public bijou this[int Column, int Row]
{
get
{
return bijous[Column, Row];
}
set
{
if (value != null)
{
value.Column = Column;
value.Row = Row;
bijous[Column, Row] = value;
if (!LayoutRoot.Children.Contains(value))
{
this.LayoutRoot.Children.Add(value);
}
}
else
{
bijous[Column, Row] = null;
}
}
}
在游戏中,每一个宝石都可以上下左右移动(除了位置在边缘的宝石),所以,我写了4个方法,作用是把指定宝石向四个方向移动,并指定其在没有可消除宝石的情况下是否还原。
下面贴出Up方法的代码:
/// <summary>
/// 将指定的宝石向上移动一格
/// </summary>
/// <param name="bijou">要移动的宝石</param>
public void Up(bijou bijou, bool isRollBack)
{
var near = GetbijouByDirection(bijou, Direction.Up);
if (near != null)
{
this.ExchangeLocation(bijou, near); //调换两个宝石的位置
AddingZindexBybijou(bijou, near); //让bijou的Zindex比near大
bijou.RenderTransform = new TranslateTransform();
bijou.RenderTransform.SetValue(TranslateTransform.YProperty, 64.0); //实际位置已经往上移了一位,所以往下平移64
near.RenderTransform = new TranslateTransform();
near.RenderTransform.SetValue(TranslateTransform.YProperty, -64.0); //实际位置已经往下移了一位,所以网上平移64
EventHandler neareh = new EventHandler((object sender1, EventArgs ea1) =>
{
var da = sender1 as DoubleAnimation;
sbAll.Children.Remove(da);
bijou.RenderTransform.SetValue(TranslateTransform.YProperty, 0.0); //播放完后还原平移变换
near.RenderTransform.SetValue(TranslateTransform.YProperty, 0.0);
});
EventHandler bijoueh = new EventHandler((object sender1, EventArgs ea1) =>
{
var da = sender1 as DoubleAnimation;
sbAll.Children.Remove(da);
bijou.RenderTransform.SetValue(TranslateTransform.YProperty, 0.0); //播放完后还原平移变换
near.RenderTransform.SetValue(TranslateTransform.YProperty, 0.0);
var erasableBjous = GetErasablebijou();
if (erasableBjous == null)
{
Up(near,false);
}
else
{
RemoveListBijou(erasableBjous);
}
});
this.AddAnimationToStoryboard(near.RenderTransform, "Y", 0.0, TimeSpan.FromMilliseconds(300), neareh); //添加动画
if (isRollBack)
this.AddAnimationToStoryboard(bijou.RenderTransform, "Y", 0.0, TimeSpan.FromMilliseconds(300), bijoueh); //添加动画
else
this.AddAnimationToStoryboard(bijou.RenderTransform, "Y", 0.0, TimeSpan.FromMilliseconds(300), neareh); //添加动画
this.BeginAnimation();
}
}
检测是否可消除,我用了一个全局检测的办法,当一个宝石执行换位操作时,执行检测是否可消除的方法,如果有可消除的宝石,返回宝石的List列表,如果没有,返回null。
public List<bijou> GetErasablebijou()
{
List<bijou> columnSameBijou = new List<bijou>();
List<bijou> rowSameBijou = new List<bijou>();
#region 检测横着排列的是否可消除并保存可消除的宝石到columnSameBijou
for (int row = 0; row < MaxRow; row++)
{
int sameNum = 0;
bool find = false;
for (int column = 0; column < MaxColumn; column++)
{
while (true)
{
if (column < MaxColumn - 1 && this[column, row].Type == this[column + 1, row].Type)
{
sameNum++;
column++;
}
else
{
if (sameNum >= 2)
{
for (; sameNum >= 0; sameNum--)
{
columnSameBijou.Add(this[column - sameNum, row]);
}
find = true;
break;
}
else
{
sameNum = 0;
}
break;
}
}
if (find)
break;
}
if (find)
break;
}
#endregion
#region 检测竖着排列的是否可消除并保存可消除的宝石到rowSameBijou
for (int column = 0; column < MaxColumn; column++)
{
int sameNum = 0;
bool find = false;
for (int row = 0; row < MaxRow; row++)
{
while (true)
{
if (row < MaxRow - 1 && this[column, row].Type == this[column, row + 1].Type)
{
sameNum++;
row++;
}
else
{
if (sameNum >= 2)
{
for (; sameNum >= 0; sameNum--)
{
rowSameBijou.Add(this[column, row - sameNum]);
}
find = true;
break;
}
else
{
sameNum = 0;
}
break;
}
}
if (find)
break;
}
if (find)
break;
}
#endregion
if (rowSameBijou.Count >= 3)
{
foreach (var tempBijou in columnSameBijou)
{
if (tempBijou.Column == rowSameBijou[0].Column)
{
columnSameBijou.Clear();
break;
}
}
}
#region 合并两个集合并返回
if (columnSameBijou.Count >= 3 || rowSameBijou.Count >= 3)
{
List<bijou> returnBijous = new List<bijou>();
foreach (var tempBijou in columnSameBijou)
{
returnBijous.Add(tempBijou);
}
foreach (var tempBijou in rowSameBijou)
{
if (!columnSameBijou.Contains(tempBijou)) //不允许重复添加
{
returnBijous.Add(tempBijou);
}
}
return returnBijous;
}
else
{
return null;
}
#endregion
}
接下来,就是消除宝石的方法,它接受一个List<bijou>参数,删除里面所有的bijou并以动画显示出来。
/// <summary>
/// 从LayoutRoot.Children中移除bijou列表
/// </summary>
/// <param name="bijous">要移除的bijou列表</param>
public void RemoveListBijou(List<bijou> removebijous)
{
Storyboard sb = new Storyboard();
sb.Completed += (object sender1, EventArgs ea1) =>
{
var sb2 = sender1 as Storyboard;
sb.Stop();
AnimationIsPlaying = false;
foreach (var tempBijou2 in removebijous)
{
tempBijou2.Opacity = 0.0;
this.LayoutRoot.Children.Remove(tempBijou2);
this[tempBijou2.Column, tempBijou2.Row] = null;
}
Resources.Remove("RemoveBijou");
FillNull();
UpdateScoure(45 + (removebijous.Count - 3) * 45);
};
Resources.Add("RemoveBijou", sb);
foreach (var tempBijou in removebijous)
{
AddAnimationToStoryboard(sb, tempBijou, "Opacity", 0.0, TimeSpan.FromMilliseconds(200));
}
BeginAnimation(sb);
}
消除该消除的宝石后,并不能直接在原位上填充新的宝石,这里需要一个动画效果,简单的模拟真实物理环境:上方的宝石会因为下面的宝石的消失而下落,新填充的宝石会在被消除宝石的那一列的0行出现,为此,要实现一个方法“FillNull”
/// <summary>
/// 创建并播放填充动画
/// </summary>
private void FillNull()
{
List<bijou> changedBijou = new List<bijou>();
Storyboard sb = new Storyboard();
sb.Completed += (object sender1, EventArgs ea1) =>
{
var sb2 = sender1 as Storyboard;
sb2.Stop();
AnimationIsPlaying = false;
foreach (var tempBijou in changedBijou)
{
tempBijou.RenderTransform.SetValue(TranslateTransform.YProperty, 0.0);
}
Resources.Remove("sbFill");
var erasableBijous = GetErasablebijou();
if (erasableBijous != null)
{
RemoveListBijou(erasableBijous);
}
};
Resources.Add("sbFill", sb);
for (int i = 0; i < MaxColumn; i++)
{
int nullNum = 0;
int row = 0;
for (int j = 0; j < MaxRow; j++)
{
if (this[i, j] == null)
{
if (j > row) row = j;
nullNum++;
}
}
for (int k = row - nullNum; k >= 0 && nullNum != 0; k--) //添加被删除Bijou上面的Bijou下落动画
{
DoubleAnimation da = new DoubleAnimation();
bijou tempBijou = this[i, k];
tempBijou.RenderTransform = new TranslateTransform();
tempBijou.RenderTransform.SetValue(TranslateTransform.YProperty, (double)-64 * nullNum);
AddAnimationToStoryboard(sb, tempBijou.RenderTransform, "Y", 0.0, TimeSpan.FromMilliseconds(300 * nullNum));
this[tempBijou.Column, tempBijou.Row + nullNum] = tempBijou;
changedBijou.Add(tempBijou);
}
for (int l = nullNum - 1; l >= 0 && nullNum != 0; l--) //创建新的Bijou填充已消除的
{
int randomNum = GetRandomNum();
bijou tempBijou = new bijou(randomNum, i, l);
tempBijou.RenderTransform = new TranslateTransform();
tempBijou.RenderTransform.SetValue(TranslateTransform.YProperty, (double)-64 * nullNum);
AddAnimationToStoryboard(sb, tempBijou.RenderTransform, "Y", 0.0, TimeSpan.FromMilliseconds(300 * nullNum));
this[tempBijou.Column, tempBijou.Row] = tempBijou;
changedBijou.Add(tempBijou);
}
}
BeginAnimation(sb);
}
整个游戏的流程大概就是这样了。下面放出源代码。
https://files.cnblogs.com/zhubenwuzui/BejeweledRelease.rar
由于本人是学生+新手,写出的代码肯定有很多缺陷,还请大家多多指教!
QQ:234446552(加我时请注明来自博客园)
本文地址:http://www.cnblogs.com/zhubenwuzui/archive/2009/09/13/BejeweledbySilverlight.html
准备转载本文的各大网站的编辑们,在转载的同时请保留本文的链接并注明出处,谢谢!