HTML5 实现的一个俄罗斯方块实例代码
程序员文章站
2023-12-03 09:21:58
示例简单,运行地址为:http://chendd.cn/demo/html/canvas/elsfk.html,得需要支持html5浏览器的环境。实现的功能:方块旋转(w键)、自动下落、移动(asd)...
示例简单,运行地址为:http://chendd.cn/demo/html/canvas/elsfk.html,得需要支持html5浏览器的环境。
实现的功能:方块旋转(w键)、自动下落、移动(asd)、消行、快速下落(空格键)、下落阴影、游戏结束。
为实现功能:消行时的计分、等级、以及不同等级的下落速度等。
学习了xiaoe的java版本的俄罗斯方块后,自己动手使用html5的canvas实现的,
参考效果图如下:
详细代码如下:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>俄罗斯方块</title> <style type="text/css"> /*整个画布*/ #tetris { border: 6px solid grey; } /*游戏面板*/ </style> </head> <body> <canvas id="tetris" width="565" height="576"></canvas> <script type="text/javascript"> var canvas = document.getelementbyid("tetris"); var context = canvas.getcontext("2d"); var padding = 6, size = 32, minx = 0, maxx = 10, miny = 0, maxy = 18, score = 0, level = 1; var gamemap = new array(); //游戏地图,二维数组 var gametimer; initgamemap(); //绘制垂直线条 drawgrid(); var arrays = basicblocktype(); var blockindex = getrandomindex(); //随机画一个方块意思意思 var block = getpointbycode(blockindex); context.fillstyle = getblockcolorbyindex(blockindex); drawblock(block); /** * 初始化游戏地图 */ function initgamemap() { for (var i = 0; i < maxy; i++) { var row = new array(); for (var j = 0; j < maxx; j++) { row[j] = false; } gamemap[i] = row; } } /** * 方块旋转 * 顺时针: * a.x =o.y + o.x - b.y * a.y =o.y - o.x + b.x */ function round() { //正方形的方块不响应旋转 if (blockindex == 4) { return; } //循环处理当前的方块,找新的旋转点 for (var i = 1; i < block.length; i++) { var o = block[0]; var point = block[i]; //旋转后的位置不能与现有格子的方块冲突 var tempx = o.y + o.x - point.y; var tempy = o.y - o.x + point.x; if (isoverzone(tempx, tempy)) { return; //不可旋转 } } clearblock(); //可以旋转,设置新的旋转后的坐标 for (var i = 1; i < block.length; i++) { var o = block[0]; var point = block[i]; //旋转后的位置不能与现有格子的方块冲突 var tempx = o.y + o.x - point.y; var tempy = o.y - o.x + point.x; block[i] = { x: tempx, y: tempy }; } drawblock(); } function movedown() { var overflag = canover(); if(overflag){ //如果不能向下移动了,将当前的方块坐标载入地图 window.clearinterval(gametimer); add2gamemap(); //清除游戏区域内的不同颜色的格子,使用单一颜色重新绘制地图堆积物 redrawgamemap(); return;//游戏结束 } var flag = moveto(0, 1); //如果可以移动,则继续移动 if (flag) { return; } //如果不能向下移动了,将当前的方块坐标载入地图 add2gamemap(); //进行消行动作 clearlines(); //清除游戏区域内的不同颜色的格子,使用单一颜色重新绘制地图堆积物 redrawgamemap(); //如果不能向下移动,则继续下一个方块 nextblock(); } /** * 消行动作,返回消除的行数 */ function clearlines() { var clearrowlist = new array(); for (var i = 0; i < maxy; i++) { var flag = true; for (var j = 0; j < maxx; j++) { if (gamemap[i][j] == false) { flag = false; break; } } if (flag) { clearrowlist.push(i); //记录消除行号的索引 } } var clearrows = clearrowlist.length; //所谓的消行就是将待消除行的索引,下方所有的格子上移动 for (var x = 0; x < clearrows; x++) { var index = clearrowlist[x]; for (var i = index; i > 0; i--) { for (var j = 0; j < maxx; j++) { gamemap[i][j] = gamemap[i - 1][j]; } } } if (clearrows > 0) { for (var i = 0; i < maxy; i++) { //此处可以限制满足相关条件的方块进行清除操作&& j < clearrowlist[clearrows - 1] for (var j = 0; j < maxx; j++) { if (gamemap[i][j] == false) { clearblockbypoint(i, j); } } } } } /** * 重绘游戏地图 */ function redrawgamemap() { drawgrid(); for (var i = 0; i < maxy; i++) { for (var j = 0; j < maxx; j++) { if (gamemap[i][j]) { roadblock(j, i); } } } } /** * 打印阴影地图 */ function drawshadowblock() { var currentblock = block; var shadowpoints = getcanmovedown(); if (shadowpoints != null && shadowpoints.length > 0) { for (var i = 0; i < shadowpoints.length; i++) { var point = shadowpoints[i]; if (point == null) { continue; } var start = point.x * size; var end = point.y * size; context.fillstyle = "#abcdef"; context.fillrect(start, end, size, size); context.strokestyle = "black"; context.strokerect(start, end, size, size); } } } /** * 返回最多可移动到的坐标位置(统计总共可以下落多少步骤) * @return最多可移动到的坐标位置 */ function getcanmovedown() { var nps = canmove(0, 1, block); var last = null; if (nps != null) { last = new array(); while ((nps = canmove(0, 1, nps)) != null) { if (nps != null) { last = nps; } } } return last; } function canover(){ var flag = false; for (var i = 0; i < block.length; i++) { var point = block[i]; var x = point.x; var y = point.y; if(isoverzone(x , y)){ flag = true; break; } } return flag; } function drawlevelscore() { } /** * 将不能移动的各种填充至地图 */ function add2gamemap() { for (var i = 0; i < block.length; i++) { var point = block[i]; var x = point.x; var y = point.y; var gamemaprow = gamemap[y]; //获取到地图的一行 gamemaprow[x] = true; //将此行中的某个格子标记为堆积物 gamemap[y] = gamemaprow; //再将行给设置回来 } } function moveleft() { moveto(-1, 0); } function moveright() { moveto(1, 0); } function quickdown() { while (moveto(0, 1)); } function moveto(movex, movey) { var move = canmove(movex, movey, block); //判定是否可以移动 if (move == null) { return false; } clearblock(); for (var i = 0; i < block.length; i++) { var point = block[i]; point.x = point.x + movex; point.y = point.y + movey; } drawblock(); return true; } /** * 下一个方块 */ function nextblock() { blockindex = getrandomindex(); block = getpointbycode(blockindex); context.fillstyle = getblockcolorbyindex(blockindex); drawblock(); } document.onkeypress = function(evt) { var key = window.event ? evt.keycode : evt.which; switch (key) { case 119: //向上旋转 w round(); break; case 115: //向下移动 s movedown(); break; case 97: //向左移动 a moveleft(); break; case 100: //向右移动 d moveright(); break; case 32: //空格键快速下落到底 quickdown(); break; } } /** * 判定是否可以移动 * @parammovex 横向移动的个数 * @parammovey 纵向移动的个数 */ function canmove(movex, movey, currentblock) { var flag = true; var newpoints = new array(); for (var i = 0; i < currentblock.length; i++) { var point = currentblock[i]; var tempx = point.x + movex; var tempy = point.y + movey; if (isoverzone(tempx, tempy)) { flag = false; break; } } if (flag) { for (var i = 0; i < currentblock.length; i++) { var point = currentblock[i]; var tempx = point.x + movex; var tempy = point.y + movey; newpoints[i] = { x: tempx, y: tempy }; } return newpoints; } return null; } /** * 判定是否可以移动 * @paramx 预移动后的横坐标 * @paramy 预移动后的纵坐标 */ function isoverzone(x, y) { return x < minx || x >= maxx || y < miny || y >= maxy || gamemap[y][x]; } document.body.click(); gametimer = window.setinterval(movedown , 800); /** * 初始化方块的基础数据 */ function basicblocktype() { var arrays = new array(); arrays[0] = [{ x: 4, y: 0 }, { x: 3, y: 0 }, { x: 5, y: 0 }, { x: 6, y: 0 }]; arrays[1] = [{ x: 4, y: 0 }, { x: 3, y: 0 }, { x: 5, y: 0 }, { x: 4, y: 1 }]; arrays[2] = [{ x: 4, y: 0 }, { x: 3, y: 0 }, { x: 5, y: 0 }, { x: 3, y: 1 }]; arrays[3] = [{ x: 4, y: 0 }, { x: 5, y: 0 }, { x: 3, y: 1 }, { x: 4, y: 1 }]; arrays[4] = [{ x: 4, y: 0 }, { x: 5, y: 0 }, { x: 4, y: 1 }, { x: 5, y: 1 }]; arrays[5] = [{ x: 4, y: 0 }, { x: 3, y: 0 }, { x: 5, y: 0 }, { x: 5, y: 1 }]; arrays[6] = [{ x: 4, y: 0 }, { x: 3, y: 0 }, { x: 4, y: 1 }, { x: 5, y: 1 }]; return arrays; } function basicblockcolor() { return ["#a00000", "#a05000", "#a0a000", "#00a000", "#00a0a0", "#0000a0", "#a000a0"]; } function getblockcolorbyindex(typecodeindex) { var arrays = basicblockcolor(); return arrays[typecodeindex]; } /** * 根据编号返回指定编号的方块 * @paramtypecodeindex 方块编号索引 */ function getpointbycode(typecodeindex) { var arrays = basicblocktype(); return arrays[typecodeindex]; } /** * 获取随即出现方块的范围值 * @paramlens 随机数的范围 */ function getrandomindex() { return parseint(math.random() * (arrays.length - 1), 10); } /** * 绘制方块,按格子单个绘制 */ function drawblock() { drawgrid(); for (var i = 0; i < block.length; i++) { var point = block[i]; var start = point.x * size; var end = point.y * size; context.fillstyle = getblockcolorbyindex(blockindex); context.fillrect(start, end, size, size); context.strokestyle = "black"; context.strokerect(start, end, size, size); } drawshadowblock(); } /** * 绘制障碍物 */ function roadblock(x, y) { context.fillstyle = "darkgray"; var start = x * size; var end = y * size; context.fillrect(start, end, size, size); } /** * 绘制新的方块先清除之前的方块 */ function clearblock() { for (var i = 0; i < block.length; i++) { var point = block[i]; var start = point.x * size; var end = point.y * size; context.clearrect(start, end, size, size); } } /** * 初始化一个新的行 */ function initgamemaprow() { var array = new array(); for (var i = 0; i < maxx; i++) { array[i] = false; } return array; } /** * 根据坐标清除指定格子的内容 * @paramx 横坐标 * @paramy 纵坐标 */ function clearblockbypoint(x, y) { var start = y * size; var end = x * size; context.clearrect(start, end, size, size); } /** * 清掉所有位置的空白格的绘图 */ function clearallnullpoint() { for (var i = 0; i < maxy; i++) { for (var j = 0; j < maxx; j++) { if (gamemap[i][j] == false) { clearblockbypoint(i, j); } } } } /** * 绘制网格线 * @paramcontext 绘图对象 */ function drawgrid() { clearallnullpoint(); //清除掉当前方块下落位置造成的阴影 context.strokestyle = "grey"; //画笔颜色 for (var i = 0; i <= maxx; i++) { var start = i * size; var end = start + size; context.beginpath(); context.moveto(start, 0); context.lineto(size * i, size * maxy); context.stroke(); context.closepath(); } //绘制水平线条 for (var i = 0; i <= maxy; i++) { var start = i * size; var end = start + size; context.beginpath(); context.moveto(0, size * i); context.lineto(size * maxx, size * i); context.stroke(); context.closepath(); } } </script> </body> </html>
以上就是html5 实现的一个俄罗斯方块的实例,有兴趣的小伙伴可以参考下,谢谢大家对本站的支持!