当前位置: 移动技术网 > IT编程>开发语言>.net > 练手WPF(二)——2048游戏的简易实现(上)

练手WPF(二)——2048游戏的简易实现(上)

2019年05月28日  | 移动技术网IT编程  | 我要评论

造梦西游3狗妖在哪,梁多赟,埃弗顿队

1、创建游戏界面
编辑mainwindow.xaml,修改代码如下:

<window.resources>
        <style targettype="label">
            <setter property="height" value="105" />
            <setter property="width" value="105" />
            <setter property="horizontalcontentalignment" value="center"/>
            <setter property="verticalcontentalignment" value="center" />
            <setter property="fontweight" value="bold"/>
            <setter property="opacity" value="0.7" />
        </style>
        <style targettype="rectangle">
            <setter property="width" value="105"/>
            <setter property="height" value="105"/>
            <setter property="fill" value="#ccc0b2"/>
        </style>
    </window.resources>
    <grid horizontalalignment="left">
        <grid.rowdefinitions>
            <rowdefinition height="100"/>
            <rowdefinition height="500"/>
            <rowdefinition height="*"/>
        </grid.rowdefinitions>
        <grid.columndefinitions>
            <columndefinition width="20"/>
            <columndefinition width="500"/>
            <columndefinition width="*"/>
        </grid.columndefinitions>
        <image grid.row="0" grid.column="1" source="/images/title2048.png"/>
        <canvas x:name="mycanvas" grid.row="1" grid.column="1" width="495" height="495" background="#b8af9e"/>
        <stackpanel grid.row="0" grid.column="2" orientation="horizontal" verticalalignment="bottom" horizontalalignment="center">
            <button x:name="btnnewgame" content="新的起点" width="80" margin="8" height="30" 
                    click="btnnewgame_click"  focusable="false" />
            <button x:name="btnoldgame" content="旧的征程" width="80" margin="8" height="30" focusable="false"/>
        </stackpanel>
        <grid grid.row="1" grid.column="2" margin="10"  >
            <grid.rowdefinitions>
                <rowdefinition height="0.5*"/>
                <rowdefinition height="*"/>
                <rowdefinition height="0.5*"/>
                <rowdefinition height="*"/>
                <rowdefinition height="0.5*"/>
                <rowdefinition height="*"/>
                <rowdefinition height="*"/>
            </grid.rowdefinitions>
            <textblock text="当前得分: " width="210" fontsize="20" verticalalignment="bottom"/>
            <label x:name="lblcurrscore" grid.row="1" content="2048" width="210" fontsize="40" 
                   foreground="maroon" opacity="1" />
            <label x:name="lbladdscore" grid.row="1" content="0" width="210" fontsize="20" 
                   foreground="chocolate" opacity="0" >
                <label.rendertransform>
                    <translatetransform x:name="tt" x="0" y="0"/>
                </label.rendertransform>
            </label>

            <textblock text="最高记录: " grid.row="2" width="210" fontsize="20" verticalalignment="bottom"/>
            <label x:name="lblbastscore" grid.row="3" content="0" width="210" fontsize="35" 
                   foreground="darkgray" opacity="1" />
            <button x:name="btnshowtopscore" grid.row="4" content="排行榜" width="80" margin="8" height="25" horizontalalignment="right"
                    focusable="false"/>
            <button x:name="btnexitgame" grid.row="5" content="退出游戏" width="80" margin="8" height="30" 
                    horizontalalignment="right" verticalalignment="bottom"  focusable="false" click="btnexitgame_click"/>
        </grid>
    </grid>

(1)在window资源区分别定义了label和rectangle的样式,因为接下游戏区的4宫格中使用的主要是对lebel控件进行显示显示和移动操作的。
(2)另外还添加一个命名为lbladdscore的lebel控件(其初始透明度为0,即完全透明),用于增加成绩时的动画效果,其中定义了命名为tt的translatetransform变换效果。
(3)游戏主区控件为canvas,命名为mycanvas。
(4)其他可以根据自己的喜好进行调整。

 

2、定义几个字段变量
毕竟是小游戏,直接从mainwindow.xaml.cs开始下手了。

int lblwidth = 105;                     // 方块大小
int lblpadding = 15;                    // 方块间隙

int[,] griddata = null;                 // 游戏主数据数组
label[,] lblarray = null;               // 用于显示成方块的label数组

int currscore = 0;                      // 当前成绩

bool isstarted = false;                 // 游戏是否已开始

random rnd = new random();             // 随机数

 

3、几个开始需要调用的方法

   3.1 游戏开始数字板
界面中的16个游戏数字为0时,只显示空的16块小板面,其颜色比背景色稍浅。

/// <summary>
///  显示背景矩形块
/// </summary>
private void showbackrect()
{
    for (int y = 0; y < 4; y++)
    {
        for (int x = 0; x < 4; x++)
        {
            rectangle rect = new rectangle();
            rect.setvalue(canvas.leftproperty, (double)((x + 1) * lblpadding + x * lblwidth));
            rect.setvalue(canvas.topproperty, (double)((y + 1) * lblpadding + y * lblwidth));
            mycanvas.children.add(rect);
        }
    }
}

  3.2 生成新数
游戏开始后,需要随机生成值为2或4的两个新数字。之后,每上、下、左、右移动其中一次界面中的数字后,如果还有空位,又需要随机生成一个2或4的新数字。

/// <summary>
/// 重载生成新数
/// </summary>
/// <returns></returns>
private bool newnum()
{
    int num = rnd.next(0, 9) > 2 ? 2 : 4;

    int nullnum = 0;
    for (int y = 0; y < 4; y++)
    {
        for (int x = 0; x < 4; x++)
        {
            if (griddata[y, x] == 0)
                nullnum++;
        }
    }

    if (nullnum < 1)
    {
        return false;
    }

    int index = rnd.next(1, nullnum);
    nullnum = 0;
    for (int y = 0; y < 4; y++)
    {
        for (int x = 0; x < 4; x++)
        {
            if (griddata[y, x] == 0)
            {
                nullnum++;
                if (nullnum != index)
                    continue;

                griddata[y, x] = num;
            }
        }
    }

    return true;
}

先统计出界面中剩余空格数,再从空格数中获取随机数作为新数位置,赋值2或4之一。

  3.3 设置label板背景色和前景字体大小
根据griddata元素值的高低,显示不同的背景色和字体大小

/// <summary>
/// 根据数值生成方块背景色值
/// </summary>
/// <param name="num"></param>
/// <returns></returns>
private brush setbackground(int num)
{
    brush backcolor;
    switch (num)
    {
        case 2:
            backcolor = new solidcolorbrush(color.fromrgb(0xee, 0xe4, 0xda));
            break;
        case 4:
            backcolor = new solidcolorbrush(color.fromrgb(0xec, 0xe0, 0xc8));
            break;
        case 8:
            backcolor = new solidcolorbrush(color.fromrgb(0xf2, 0xb1, 0x79));
            break;
        case 16:
            backcolor = new solidcolorbrush(color.fromrgb(0xf5, 0x95, 0x63));
            break;
        case 32:
            backcolor = new solidcolorbrush(color.fromrgb(0xf5, 0x7c, 0x5f));
            break;
        case 64:
            backcolor = new solidcolorbrush(color.fromrgb(0xf6, 0x5d, 0x3b));
            break;
        case 128:
            backcolor = new solidcolorbrush(color.fromrgb(0xed, 0xce, 0x71));
            break;
        case 256:
            backcolor = new solidcolorbrush(color.fromrgb(0xed, 0xcc, 0x61));
            break;

        case 512:
            backcolor = new solidcolorbrush(color.fromrgb(0xec, 0xc8, 0x50));
            break;
        case 1024:
            backcolor = new solidcolorbrush(color.fromrgb(0xed, 0xc5, 0x3f));
            break;
        case 2048:
            backcolor = new solidcolorbrush(color.fromrgb(0xee, 0xc2, 0x2e));
            break;
        case 4096:
            backcolor = new solidcolorbrush(color.fromrgb(0xef, 0x85, 0x9c));
            break;
        default:
            backcolor = new solidcolorbrush(color.fromrgb(0xcc, 0xc0, 0xb2));
            break;
    }
    return backcolor;
}

/// <summary>
/// 根据数值设置方块字体大小
/// </summary>
/// <param name="num"></param>
/// <returns></returns>
private int setfontsize(int num)
{
    int ifontsize;
    switch (num)
    {
        case 2:
        case 4:
        case 8:
            ifontsize = 55;
            break;

        case 16:
        case 32:
        case 64:
            ifontsize = 50;
            break;

        case 128:
        case 256:
        case 512:
            ifontsize = 40;
            break;

        case 1024:
        case 2048:
        case 4096:
            ifontsize = 33;
            break;

        default:
            ifontsize = 30;
            break;
    }
    return ifontsize;
}

 

  3.4 显示游戏区的所有label控件
如果griddata元素值不为0的话,生成label控件并添加到游戏板中。

/// <summary>
/// 重新显示所有label
/// </summary>
private void showalllabel()
{
    mycanvas.children.clear();
    showbackrect();

    for (int y = 0; y < 4; y++)
    {
        for (int x = 0; x < 4; x++)
        {
            if (griddata[y, x] != 0)
            {
                lblarray[y, x] = new label();
                lblarray[y, x].setvalue(canvas.leftproperty, lblpadding * (x + 1) + (double)(x * lblwidth));
                lblarray[y, x].setvalue(canvas.topproperty, lblpadding * (y + 1) + (double)(y * lblwidth));
                lblarray[y, x].setvalue(label.contentproperty, griddata[y, x].tostring());
                lblarray[y, x].setvalue(label.backgroundproperty, setbackground(griddata[y, x]));
                lblarray[y, x].setvalue(label.fontsizeproperty, (double)setfontsize(griddata[y, x]));
                mycanvas.children.add(lblarray[y, x]);
            }
        }
    }
}

 

4、初始化游戏数据

/// <summary>
/// 初始化数据
/// </summary>
private void initdata()
{
    if (griddata != null)                       // 初始化主数据数组
        griddata = null;

    griddata = new int[4, 4]
    {
        { 0, 0, 0, 0 },
        { 0, 0, 0, 0 },
        { 0, 0, 0, 0 },
        { 0, 0, 0, 0 }
    };

    if (lblarray != null)                       // 初始化显示用label数组
        lblarray = null;

    lblarray = new label[4, 4];

    if (mycanvas.children.count > 0)
        mycanvas.children.clear();              // 清除界面

    newnum();                                   // 生成两个新数
    newnum();

    showalllabel();                             // 刷新游戏方块

    isstarted = true;
    currscore = 0;                              // 初始化当前成绩为0

    lblcurrscore.content = currscore.tostring();// 更新当前成绩显示
}

将initdata()方法添加到btnnewgame_click按钮事件方法中。

现在运行游戏,不断点击开始新游戏按钮,会在不同位置生成两个2或4的数字,并显示出来。

 

5、判断游戏是否结束
判断每一行是否存在空位,如果有则未结束。如果该行已满,则看看是否存在相邻是否有相同的数字,如果有则说明可以合并出新空位,即未结束。
列判断方式相同。

/// <summary>
/// 游戏是否结束
/// </summary>
/// <returns></returns>
private bool isgameover()
{
    for (int row = 0; row < 4; row++)
    {
        for (int i = 0; i < 4; i++)
        {
            if (griddata[row, i] == 0)  // 是否有空位
            {
                return false;
            }
        }
        for (int i = 0; i < 3; i++)
        {
            if (griddata[row, i] == griddata[row, i + 1])
            {
                return false;
            }
        }
    }

    for (int col = 0; col < 4; col++)
    {
        for (int i = 0; i < 4; i++)
        {
            if (griddata[i, col] == 0)
            {
                return false;
            }
        }
        for (int i = 0; i < 3; i++)
        {
            if (griddata[i, col] == griddata[i + 1, col])
            {
                return false;
            }
        }
    }

    return true;
}

/// <summary>
/// 显示动画结束对话框
/// </summary>
private void showgameover()
{
    messagebox.show("游戏已经结束。", "game over", messageboxbutton.ok, messageboximage.information);
    isstarted = false;
}

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网