练手WPF(三)——扫雷小游戏的简易实现(中)
程序员文章站
2022-08-10 15:42:46
八、随机布雷 十、设置背景区图片组 循环读取背景区数据,根据数值设置对应的图片源。 十一、开始游戏准备 根据游戏级别分别调用随机布雷、设置雷边数值方法,同时添加背景图片数组到游戏背景区。 将该方法添加到开始游戏菜单中,并计时器打开。 重复点击开始菜单,看看效果。 十二、调整游戏级别 根据菜单设置的当 ......
八、随机布雷
/// <summary> /// 随机布地雷 /// </summary> /// <param name="minenum">地雷数</param> private void setrndmine(int minenum) { for (int k = 0; k < minenum; k++) { int nullnum = 0; for (int j = 0; j < _gamelevel._colgrid; j++) { for (int i = 0; i < _gamelevel._rowgrid; i++) { if (_backdata[j, i] == (int)backstate.blank) nullnum++; } } if (nullnum < 1) return; int index = rnd.next(1, nullnum); nullnum = 0; for (int j = 0; j < _gamelevel._colgrid; j++) { for (int i = 0; i < _gamelevel._rowgrid; i++) { if (_backdata[j, i] == 0) { nullnum++; if (nullnum != index) continue; _backdata[j, i] = (int)backstate.mine; // 设置为地雷 } } } } }
这个方法是不是很熟悉,我们在2048游戏中用到过,这里就不再多说了。
九、设置地雷旁边的格子标注的地雷数值
原理就是读取地雷位置,然后分别给不是地雷的格子数值+1。
/// <summary> /// 设置地雷周围格子雷数 /// </summary> private void setcellminenumber() { for (int y = 0; y < _gamelevel._colgrid; y++) { for (int x = 0; x < _gamelevel._rowgrid; x++) { if (_backdata[y, x] == (int)backstate.mine) // 遇到地雷则周围8格分别+1 { if (x - 1 > -1 && y - 1 > -1 && _backdata[y - 1, x - 1] != (int)backstate.mine) _backdata[y - 1, x - 1]++; if (y - 1 > -1 && _backdata[y - 1, x] != (int)backstate.mine) _backdata[y - 1, x]++; if (y - 1 > -1 && x + 1 < _gamelevel._rowgrid && _backdata[y - 1, x + 1] != (int)backstate.mine) _backdata[y - 1, x + 1]++; if (x - 1 > -1 && _backdata[y, x - 1] != (int)backstate.mine) _backdata[y, x - 1]++; if (x + 1 < _gamelevel._rowgrid && _backdata[y, x + 1] != (int)backstate.mine) _backdata[y, x + 1]++; if (y + 1 < _gamelevel._colgrid && x - 1 > -1 && _backdata[y + 1, x - 1] != (int)backstate.mine) _backdata[y + 1, x - 1]++; if (y + 1 < _gamelevel._colgrid && _backdata[y + 1, x] != (int)backstate.mine) _backdata[y + 1, x]++; if (y + 1 < _gamelevel._colgrid && x + 1 < _gamelevel._rowgrid && _backdata[y + 1, x + 1] != (int)backstate.mine) _backdata[y + 1, x + 1]++; } } } }
十、设置背景区图片组
循环读取背景区数据,根据数值设置对应的图片源。
private void setbackcellimage() { backcanvas.children.clear(); for (int y=0; y<_gamelevel._colgrid; y++) { for (int x=0; x<_gamelevel._rowgrid; x++) { _backimage[y, x] = new image(); if (_backdata[y, x] == (int)backstate.blank) { _backimage[y, x].source = imagehelper.cutimage(_bmpspace, new int32rect(0, 0, _cellsize.width, _cellsize.height)); } else if (_backdata[y, x] == (int)backstate.mine) { _backimage[y, x].source = imagehelper.cutimage(_bmpmine, new int32rect(0, 0, _cellsize.width, _cellsize.height)); } else { for (int i = 0; i < 8; i++) { if (_backdata[y, x] == (i+1)) { _backimage[y, x].source = imagehelper.cutimage( _bmpnum1_8, new int32rect(i * _cellsize.width, 0, _cellsize.width, _cellsize.height)); break; } } } _backimage[y, x].setvalue(canvas.leftproperty, x * (double)_cellsize.width); _backimage[y, x].setvalue(canvas.topproperty, y * (double)_cellsize.height); backcanvas.children.add(_backimage[y, x]); } } }
十一、开始游戏准备
根据游戏级别分别调用随机布雷、设置雷边数值方法,同时添加背景图片数组到游戏背景区。
private void resetgame() { initialgamestate(); initgamedata(_level); textblockminenum.text = _gamelevel._minenum.tostring(); setrndmine(_gamelevel._minenum); setcellminenumber(); setbackcellimage(); }
将该方法添加到开始游戏菜单中,并计时器打开。
private void menugamestart_click(object sender, routedeventargs e) { resetgame(); _gamestate = gamestate.start; // 开始计时 _stopwatchgame.start(); _timersettimetext.start(); }
重复点击开始菜单,看看效果。
十二、调整游戏级别
根据菜单设置的当前级别值设置菜单选择状态。
/// <summary> /// 设置级别菜单状态 /// </summary> /// <param name="level"></param> private void setmenulevelstate(level level) { switch (level) { case level.simple: menulowlevel.ischecked = true; menumiddlelevel.ischecked = false; menuhighlevel.ischecked = false; break; case level.normal: menulowlevel.ischecked = false; menumiddlelevel.ischecked = true; menuhighlevel.ischecked = false; break; case level.hard: menulowlevel.ischecked = false; menumiddlelevel.ischecked = false; menuhighlevel.ischecked = true; break; } }
/// <summary> /// 初级级别菜单 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void menulowlevel_click(object sender, routedeventargs e) { if (_level == level.simple) return; if (messagebox.show("将用新难度级别重置游戏,确认要继续吗?", "警告", messageboxbutton.yesno, messageboximage.asterisk) == messageboxresult.yes) { _level = level.simple; setmenulevelstate(_level); resetgame(); } } /// <summary> /// 中级级别菜单 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void menumiddlelevel_click(object sender, routedeventargs e) { if (_level == level.normal) return; if (messagebox.show("将用新难度级别重置游戏,确认要继续吗?", "警告", messageboxbutton.yesno, messageboximage.asterisk) == messageboxresult.yes) { _level = level.normal; setmenulevelstate(_level); resetgame(); } } /// <summary> /// 高级级别菜单 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void menuhighlevel_click(object sender, routedeventargs e) { if (_level == level.hard) return; if (messagebox.show("将用新难度级别重置游戏,确认要继续吗?", "警告", messageboxbutton.yesno, messageboximage.asterisk) == messageboxresult.yes) { _level = level.hard; setmenulevelstate(_level); resetgame(); } }
十三、设置前景区图片组
/// <summary> /// 设置前景图片数组 /// </summary> private void setforecellimages() { forecanvas.children.clear(); for (int y = 0; y < _gamelevel._colgrid; y++) { for (int x = 0; x < _gamelevel._rowgrid; x++) { if (_foredata[y, x] > (int)forestate.none) { _foreimage[y, x] = new image(); _foreimage[y, x].source = imagehelper.cutimage(_bmpforeground, new int32rect(0, 0, _cellsize.width, _cellsize.height)); _foreimage[y, x].setvalue(canvas.leftproperty, x * (double)_cellsize.width); _foreimage[y, x].setvalue(canvas.topproperty, y * (double)_cellsize.height); forecanvas.children.add(_foreimage[y, x]); } } } }
在resetgame()方法最后位置加入对该方法的调用。
运行程序,看看效果。