示例简单,运行地址为: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 实现的一个俄罗斯方块的实例,有兴趣的小伙伴可以参考下,谢谢大家对本站的支持!
发表评论