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语言编写 ...
随机推荐
- SQL审核平台Yearning部署
SQL审核平台Yearning部署 Yearning优势: Yearning SQL 审计平台 基于Vue.js与Django的整套mysql-sql审核平台解决方案.提供基于Inception的S ...
- 用ASP创建API。NET Core (Day2):在ASP中创建API。网络核心
下载PDF article - 1.5 MB 下载source - 152.4 KB 下载source - 206.3 KB 下载source code from GitHub 表的内容 中间件路线图 ...
- 在Windows7系统中设置虚拟内存大小
当我们的电脑物理内存空间不够用时,操作系统就会自动从硬盘空间上分出一块空间来当内存使用,这就是虚拟内存.可以说虚拟内存是物理内存的补充,是备用的物理内存.一般来说,如果电脑里的程序不多,占用内存资源不 ...
- ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)解决方案
在Win7下使用MySQL5.6.35创建用户时,提示权限不足,具体解决方案如下: 1 停止mysql服务 net stop mysql 2 打开新的cmd窗口,切换到bin目录,运行如下命令,cmd ...
- 真的有这么丝滑吗?近日国外一小哥深入研究了KMP算法……
近日被朋友问到了字符串匹配算法,让我想起了大二上学期在一次校级编程竞赛中我碰到同样的问题时,为自己写出了暴力匹配算法而沾沾自喜的经历. 现在想来,着实有点羞愧,于是埋头去学习了一下KMP算法,为了让自 ...
- java中文件是否为空
在File类中并没有提供判断文件是否为空的方法,但可以借助length()方法的返回值进行判断.如果文件不存在或文件为空时,length()方法返回0. File file = new File(&q ...
- 会用Docker的人都别装了,这多简单呐
学术又官方的说法 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器或Windows 机器上,也可以实现虚拟化,容器是 ...
- ffmpeg实现视频文件合并/截取预览视频/抽取音频/crop(裁剪)(ffmpeg4.2.2)
一,ffmpeg的安装 请参见: https://www.cnblogs.com/architectforest/p/12807683.html 说明:刘宏缔的架构森林是一个专注架构的博客,地址:ht ...
- Apache Hudi助力nClouds加速数据交付
1. 概述 在nClouds上,当客户的业务决策取决于对近实时数据的访问时,客户通常会向我们寻求有关数据和分析平台的解决方案.但随着每天创建和收集的数据量都在增加,这使得使用传统技术进行数据分析成为一 ...
- mysql 改变表结构 alter
总结:alter添加栏位时,只需记住添加新栏位为第一列,用first;添加其他用,after 前一个栏位字段,如下例 1.需求:将新的栏位添加为第二列 添加前: 添加后: 参考:http://www. ...