HTML5 实现的一个俄罗斯方块实例代码
/*实现的功能:方块旋转(W键)、自动下落、移动(ASD)、消行、快速下落(空格键)、下落阴影、游戏结束。*/
<!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 实现的一个俄罗斯方块实例代码的更多相关文章
- 详解 HTML5 中的 WebSocket 及实例代码-做弹幕
原文链接:http://www.php.cn/html5-tutorial-363345.html
- 每天一个JavaScript实例-html5拖拽
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- 我的第一个activiti实例 (代码方式) ctiviti入门列子一个简单的activiti请假流程
转: (activiti入门列子一个简单的activiti请假流程) 我的第一个activiti实例 2017年05月31日 14:29:45 chf_mixueer 阅读数:1223 整个项目的 ...
- Web 开发中应用 HTML5 技术的10个实例教程
HTML5 作为下一代网站开发技术,无论你是一个 Web 开发人员或者想探索新的平台的游戏开发者,都值得去研究.借助尖端功能,技术和 API,HTML5 允许你创建响应性.创新性.互动性以及令人惊叹的 ...
- seo之google rich-snippets丰富网页摘要结构化数据(微数据)实例代码
seo之google rich-snippets丰富网页摘要结构化数据(微数据)实例代码 网页摘要是搜索引擎搜索结果下的几行字,用户能通过网页摘要迅速了解到网页的大概内容,传统的摘要是纯文字摘要,而结 ...
- jquery ajax jsonp跨域调用实例代码
今天研究了AJAX使用JSONP进行跨域调用的方法,发现使用GET方式和POST方式都可以进行跨域调用,这里简单分享下,方便需要的朋友 客户端代码 复制代码 代码如下: <%@ Page Lan ...
- Javascript 俄罗斯方块 游戏代码解释!
俄罗斯方块代码说明 /** 名称:Javascript 俄罗斯方块! 作者:Gloot 邮箱:glootz@gmail.com QQ:345268267 网站:http://www.cnblogs.c ...
- PHP读取超大文件的实例代码
数据量大带来的问题就是单个文件很大,能够打开这个文件相当不容易,记事本就不要指望了,果断死机 去年年底的各种网站帐号信息的数据库泄漏,很是给力啊,趁机也下载了几个数据库,准备学学数据分析家来分析一 ...
- python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容
python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...
随机推荐
- Lesktop开源IM移动端:接入LayIM移动端UI
在<开源企业即时通讯和在线客服>中已介绍了Lesktop的桌面模式和Web模式,但是没有移动端.评论中 dotnetcms.org工作室 提到了LayIM,看了一下官网的演示和文档,如果用 ...
- 如何检测ASP中的浏览器。NET与浏览器文件
介绍 ASP.NET是一个用于使用Web表单.MVC.Web API和SignalR(这是官方定义)构建Web应用程序的高生产力框架.它是在.net框架上开发RESTful应用程序或使用HTML.CS ...
- Linux init 详解(0,1,2,3,4,5,6)
一.什么是 init init是Linux系统操作中不可缺少的程序之一. 所谓的init进程,它是一个由内核启动的用户级进程. 内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数 ...
- jquery购物车全选,取消全选,计算总金额
这是html代码 <div class="gwcxqbj"> <div class="gwcxd center"> <div cl ...
- Python+Appium自动化测试(7)-截图方法
一,selenium模块的两种截图方法 get_screenshot_as_file(filename) 参数filename为截图文件保存的绝对路径,如: driver.get_screenshot ...
- 实验二 HTML中图片和超链接的应用
实验二 HTML中图片和超链接的应用 [实验目的] 1.通过本例要求掌握常见的图像格式及图像的插入方法. 2.能够修改图像属性,利用外部图像处理软件编辑图像. 3.掌握设置各类超级连接的方法. 4.灵 ...
- CentOS 7操作系统基础优化介绍
01 前言 操作系统部署完毕后,需要做一些基础的简单优化操作,可以为系统未来的使用过程带来更多便捷. 02 操作系统安全优化配置 系统安装完毕后,默认系统中会存在两个重要的安全服务程序,建议将其首先进 ...
- CSP-S2020AFO记
2020-10.11 考初赛辣. 选择题考了一堆时间复杂度,一个不会(卒) 我寻思这01背包哪里能用贪心? 啊,这,这,这手写快排竟如此简单,手写取Max,手写队列,两个字符串颠来倒去,竟活到爆! 震 ...
- Vue.js 获得兄弟元素,子元素,父元素(DOM操作)
e.target 是你当前点击的元素 e.currentTarget 是你绑定事件的元素 e.currentTarget.previousElementSibling.innerHTML 获得点击元素 ...
- B. Petya and Divisors 解析(思維)
Codeforce 111 B. Petya and Divisors 解析(思維) 今天我們來看看CF111B 題目連結 題目 略,請看原題 前言 看了別人的解答就豁然開朗 @copyright p ...