一、简介
通过键盘上的上下左右键,移动方格来实现数字的加减;此次是使用wpf搭建的前台界面加上后台逻辑实现的;
二、实现步骤
1.搭界面
首先可以根据自己的结构喜好去搭建一个简单的界面,留一个较大的范围即可
界面可以根据自己需求设计,这里只是简单的做分隔
这一步用wpf前台的xaml来写还是很简单的,这里就不做过多描述了
2.大方格载体和独立的小方格
我这边设计想法是在一个大方格上放置十六个没有数字的小方格作为初始载体,然后把有数字的小方格在载体小方格上移动和相加,从而实现2048小游戏的效果
后面没有数字的空方格统称为载体方格,有数字可以移动的方格称为数字方格
首先我们要新建一个小方格类LittleRect,这个类可以作为载体方格,也可以作为数字方格去使用;这里我把这个类继承于Label,因为Label可以自定义背景颜色,并且有Content属性可以显示数字;我写了一个Texts属性,让他在值变化时背景颜色也跟着改变
public string Texts
{
get { return (string)GetValue(TextsProperty); }
set { SetValue(TextsProperty, value); }
}
// Using a DependencyProperty as the backing store for Texts. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextsProperty =
DependencyProperty.Register("Texts", typeof(string), typeof(LittleRect), new FrameworkPropertyMetadata(null,TextsChange));
/// <summary>
/// 值变更
/// </summary>
/// <param name="d"></param>
/// <param name="e"></param>
private static void TextsChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is LittleRect obj)
{
obj.TextsChanged(e.NewValue);
}
}
private void TextsChanged(object value)
{
int num = -1;
if (value!=null&&value?.ToString()!="")
{
num = Convert.ToInt32(value);
Content = num;
}
else
{
Background = new SolidColorBrush(Colors.RosyBrown);
Content = value?.ToString();
}
switch (num)
{
case 2:
Background = Brushes.GreenYellow;
break;
case 4:
Background = Brushes.Yellow; ;
break;
case 8:
Background = Brushes.LightYellow;
break;
case 16:
Background = Brushes.Orange;
break;
case 32:
Background = Brushes.OrangeRed;
break;
case 64:
Background = Brushes.Orchid;
break;
case 128:
Background = Brushes.Red;
break;
case 256:
Background = Brushes.MediumVioletRed;
break;
case 512:
Background = Brushes.IndianRed;
break;
case 1024:
Background = Brushes.PaleVioletRed;
break;
case 2048:
Background = Brushes.BlanchedAlmond;
break;
default: Background = new SolidColorBrush(Colors.RosyBrown); break;
}
}
除此以外,还要在加载小方块的时候设置后相应的样式,如Content居中等
在实现小方块类后,要新建一个大方块类BorderRetc,这个类要实现生成16个载体方块、生成初始的数字方块、生成移动过程中的数字方块;
private void BorderRetc_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
BorderStyleSet();//设置背景样式
for (int i = 0; i < GlobalsP.RectsRNums; i++)
{
for (int j = 0; j < GlobalsP.RectsCNums; j++)
{
GlobalsP.littleRects[i,j] = new LittleRect()
{
Width = this.ActualWidth / 4 - 5,
Height = this.ActualHeight / 4 - 5,
Background = new SolidColorBrush(Colors.RosyBrown),
};
SetRetcPos(GlobalsP.littleRects[i,j],(ActualWidth / 3.95) *(j),(ActualHeight / 3.95) *(i));//调整方块位置
}
}
AddRetc();//将方块添加到画布上
RandomTwoNum(); //初始生成随机的两个带数字的方块
}
由于本质上是将Label放置到一定的空间里进行排列;因此可以把BorderRetc类继承于Canvas,这样有助于方块的排列整齐;
在大方格载体类中,我们要实现的方法有:(1)添加十六个载体方格对象(2)清除小方格对象(3)初始随机生成两个有数字的小方格(4)每次移动动作后随机空白位置生成一个有数字的小方格
由于大方格类继承于Canvas,因此添加对象比较方便
3.初始方块和随机生成方块
首先是添加四行四列的载体方格
/// <summary>
/// 画布添加对象
/// </summary>
public void AddRetc()
{
ClearRect();
for (int i = 0; i < GlobalsP.RectsRNums; i++)
{
for (int j = 0; j < GlobalsP.RectsCNums; j++)
{
GlobalsP.littleRects[i, j].Texts = null;
}
}
for (int i = 0; i < GlobalsP.RectsRNums; i++)
{
for (int j = 0; j < GlobalsP.RectsCNums; j++)
{
this.Children.Add(GlobalsP.littleRects[i, j]);
}
}
}
/// <summary>
/// 清除画布对象
/// </summary>
private void ClearRect()
{
Children.Clear();
}
这里注意要调整方格的位置,不然会堆积到一起去;可以利用TranslateTransform类调整对象位置
其次就是初始生成两个数字方格和每次移动后随机载体方格位置生成一个数字方格
初始生成两个数字方格只在重新开始游戏或刚开始游戏的时候才触发
/// <summary>
/// 每次生成两个随机的数字格子
/// </summary>
public void RandomTwoNum()
{
int row1 = -1;
int row2 = -1;
int col1 = -1;
int col2 = -1;
while(row1==row2 && col1 == col2)
{
row1 = random.Next(0, GlobalsP.RectsRNums);
row2 = random.Next(0, GlobalsP.RectsRNums);
col1 = random.Next(0, GlobalsP.RectsCNums);
col2 = random.Next(0, GlobalsP.RectsCNums);
//row1 = 1;
//row2 = 3;
//col1 = 1;
//col2 = 1;
}
Children.Remove(GlobalsP.littleRects[row1, col1]);
Children.Remove(GlobalsP.littleRects[row2, col2]);
GlobalsP.littleRects[row1, col1].Texts = RandomNum();//随机赋予2或4
GlobalsP.littleRects[row2, col2].Texts = RandomNum();//随机赋予2或4
Children.Add(GlobalsP.littleRects[row1, col1]);
Children.Add(GlobalsP.littleRects[row2, col2]);
}
每次移动后随机在空白位置生成一个2或4
这里要注意,要先判断方格值是否为空,只有空的情况下才可添加
/// <summary>
/// 每次移动后随机位置生成一个随机的值
/// </summary>
public void RandomOneNums()
{
int row1 = -1;
int col1 = -1;
do
{
row1 = random.Next(0, GlobalsP.RectsRNums);
col1 = random.Next(0, GlobalsP.RectsCNums);
} while (!string.IsNullOrEmpty(GlobalsP.littleRects[row1, col1].Texts));//如果不是空,就循环生成随机值
Children.Remove(GlobalsP.littleRects[row1, col1]);//移除掉空值后
GlobalsP.littleRects[row1, col1].Texts = RandomNum();
Children.Add(GlobalsP.littleRects[row1, col1]);//添加有数字的方格
}
实现以上步骤后,就可以来编写最核心的部分,操作逻辑
4.移动和相加逻辑
游戏的玩法很简单,说到底还是用键盘来操作上下左右移动,把每行或每列中相邻或者中间空着的两个相同的方格相加,然后将两个合并成一个;
首先我们通过事件捕获键盘的按键,识别出是↑↓←→,然后依次进行方格的移动操作
这里要区分上下的动作和左右的动作,上下的动作是操作每列的方格,左右是操作每行的方格
进行上下的动作时,要循环每一列,再检测每一列的每行是否相邻有相同的值,或者相同的值之间是否有空格。
为了适应这种空方格的情况,先获取一整列的数据,将他们存放到一个数组中,然后将这个数组进行位置排列;比如当出现一下这种情况时
获取到的数据数组为{“4”,“”,“2”,“2”},然后我们可以通过排列的方式,把空值放到头或尾的位置,其他的依旧按顺序排列,如果是向上操作的话,就可以排列得到新的数组{“4”,“2”,“2”,“”},如果是向下操作的话,得到数组为{“”,“4”,“2”,“2”},排列完后,再遍历一遍列中的数值,判断是否有相邻的两个数,如果有则相加,相加合并后会得到以下数组,{“”,“4”,“”,“4”}(下操作)会出现一个空的方格,因此我们要再排列一遍数组,把空值放到一边,得到新的数组{“”,“”,“4”,“4”},这样就实现了移动和相加;
private void MoveZero(string[] strs, bool isdown)
{
int prt1 = 0;
int prt2 = 0;
string str = "-1";
while (prt1 < strs.Length)//利用双指针的方式
{
if (strs[prt1] == null)
{
while (prt2 < strs.Length)
{
if (strs[prt2] != null && prt1 < prt2)
{
str = strs[prt1];//把非空值移到空值上
strs[prt1] = strs[prt2];
strs[prt2] = str;
break;
}
prt2++;
}
}
prt1++;
}
if (isdown)
{
Array.Reverse(strs);
}
}
/// <summary>
/// 合并相同的值
/// </summary>
/// <param name="strs"></param>
private void CombineOperate(string[] strs)
{
int prt1 = 0;
int prt2 = 1;
while (prt1 < strs.Length)//利用双指针,判断相邻两个数值是否相等
{
while (prt2 < strs.Length)
{
if (strs[prt1] == strs[prt2])
{
if (strs[prt1] != null)
{
strs[prt1] = (Convert.ToInt32(strs[prt1]) * 2).ToString();//如果相等则翻倍
strs[prt2] = null;//并且把前值置空
}
}
break;
}
prt1++;
prt2++;
}
}
5.最后就是组合逻辑了
这个可以根据自己喜好去搭建环境和框架,每个人想法不同;
ps:第一次分享文章,很多不太懂的地方,如果有做的不好的麻烦可以提一下,本人代码能力一般般,单纯想分享一下自己的想法,如果有写的不好请多多包含和指教;有需要源码的可以联系我,免费分享