HTML5 實(shí)現(xiàn)的一個(gè)俄羅斯方塊實(shí)例代碼
示例簡(jiǎn)單,運(yùn)行地址為:http://chendd.cn/demo/html/canvas/elsfk.html,得需要支持html5瀏覽器的環(huán)境。
實(shí)現(xiàn)的功能:方塊旋轉(zhuǎn)(W鍵)、自動(dòng)下落、移動(dòng)(ASD)、消行、快速下落(空格鍵)、下落陰影、游戲結(jié)束。
為實(shí)現(xiàn)功能:消行時(shí)的計(jì)分、等級(jí)、以及不同等級(jí)的下落速度等。
學(xué)習(xí)了xiaoE的Java版本的俄羅斯方塊后,自己動(dòng)手使用html5的canvas實(shí)現(xiàn)的,
參考效果圖如下:

詳細(xì)代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>俄羅斯方塊</title>
<style type="text/css">
/*整個(gè)畫布*/
#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(); //游戲地圖,二維數(shù)組
var gameTimer;
initGameMap();
//繪制垂直線條
drawGrid();
var arrays = basicBlockType();
var blockIndex = getRandomIndex();
//隨機(jī)畫一個(gè)方塊意思意思
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;
}
}
/**
* 方塊旋轉(zhuǎn)
* 順時(shí)針:
* A.x =O.y + O.x - B.y
* A.y =O.y - O.x + B.x
*/
function round() {
//正方形的方塊不響應(yīng)旋轉(zhuǎn)
if (blockIndex == 4) {
return;
}
//循環(huán)處理當(dāng)前的方塊,找新的旋轉(zhuǎn)點(diǎn)
for (var i = 1; i < block.length; i++) {
var o = block[0];
var point = block[i];
//旋轉(zhuǎn)后的位置不能與現(xiàn)有格子的方塊沖突
var tempX = o.y + o.x - point.y;
var tempY = o.y - o.x + point.x;
if (isOverZone(tempX, tempY)) {
return; //不可旋轉(zhuǎn)
}
}
clearBlock();
//可以旋轉(zhuǎn),設(shè)置新的旋轉(zhuǎn)后的坐標(biāo)
for (var i = 1; i < block.length; i++) {
var o = block[0];
var point = block[i];
//旋轉(zhuǎn)后的位置不能與現(xiàn)有格子的方塊沖突
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){
//如果不能向下移動(dòng)了,將當(dāng)前的方塊坐標(biāo)載入地圖
window.clearInterval(gameTimer);
add2GameMap();
//清除游戲區(qū)域內(nèi)的不同顏色的格子,使用單一顏色重新繪制地圖堆積物
redrawGameMap();
return;//游戲結(jié)束
}
var flag = moveTo(0, 1);
//如果可以移動(dòng),則繼續(xù)移動(dòng)
if (flag) {
return;
}
//如果不能向下移動(dòng)了,將當(dāng)前的方塊坐標(biāo)載入地圖
add2GameMap();
//進(jìn)行消行動(dòng)作
clearLines();
//清除游戲區(qū)域內(nèi)的不同顏色的格子,使用單一顏色重新繪制地圖堆積物
redrawGameMap();
//如果不能向下移動(dòng),則繼續(xù)下一個(gè)方塊
nextBlock();
}
/**
* 消行動(dòng)作,返回消除的行數(shù)
*/
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); //記錄消除行號(hào)的索引
}
}
var clearRows = clearRowList.length;
//所謂的消行就是將待消除行的索引,下方所有的格子上移動(dòng)
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++) {
//此處可以限制滿足相關(guān)條件的方塊進(jìn)行清除操作&& 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);
}
}
}
/**
* 返回最多可移動(dòng)到的坐標(biāo)位置(統(tǒng)計(jì)總共可以下落多少步驟)
* @return最多可移動(dòng)到的坐標(biāo)位置
*/
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() {
}
/**
* 將不能移動(dòng)的各種填充至地圖
*/
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; //將此行中的某個(gè)格子標(biāo)記為堆積物
gameMap[y] = gameMapRow; //再將行給設(shè)置回來
}
}
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); //判定是否可以移動(dòng)
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;
}
/**
* 下一個(gè)方塊
*/
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: //向上旋轉(zhuǎn) W
round();
break;
case 115: //向下移動(dòng) S
moveDown();
break;
case 97: //向左移動(dòng) A
moveLeft();
break;
case 100: //向右移動(dòng) D
moveRight();
break;
case 32: //空格鍵快速下落到底
quickDown();
break;
}
}
/**
* 判定是否可以移動(dòng)
* @parammoveX 橫向移動(dòng)的個(gè)數(shù)
* @parammoveY 縱向移動(dòng)的個(gè)數(shù)
*/
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;
}
/**
* 判定是否可以移動(dòng)
* @paramx 預(yù)移動(dòng)后的橫坐標(biāo)
* @paramy 預(yù)移動(dòng)后的縱坐標(biāo)
*/
function isOverZone(x, y) {
return x < minX || x >= maxX || y < minY || y >= maxY || gameMap[y][x];
}
document.body.click();
gameTimer = window.setInterval(moveDown , 800);
/**
* 初始化方塊的基礎(chǔ)數(shù)據(jù)
*/
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];
}
/**
* 根據(jù)編號(hào)返回指定編號(hào)的方塊
* @paramtypeCodeIndex 方塊編號(hào)索引
*/
function getPointByCode(typeCodeIndex) {
var arrays = basicBlockType();
return arrays[typeCodeIndex];
}
/**
* 獲取隨即出現(xiàn)方塊的范圍值
* @paramlens 隨機(jī)數(shù)的范圍
*/
function getRandomIndex() {
return parseInt(Math.random() * (arrays.length - 1), 10);
}
/**
* 繪制方塊,按格子單個(gè)繪制
*/
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);
}
}
/**
* 初始化一個(gè)新的行
*/
function initGameMapRow() {
var array = new Array();
for (var i = 0; i < maxX; i++) {
array[i] = false;
}
return array;
}
/**
* 根據(jù)坐標(biāo)清除指定格子的內(nèi)容
* @paramx 橫坐標(biāo)
* @paramy 縱坐標(biāo)
*/
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);
}
}
}
}
/**
* 繪制網(wǎng)格線
* @paramcontext 繪圖對(duì)象
*/
function drawGrid() {
clearAllNullPoint(); //清除掉當(dāng)前方塊下落位置造成的陰影
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 實(shí)現(xiàn)的一個(gè)俄羅斯方塊的實(shí)例,有興趣的小伙伴可以參考下,謝謝大家對(duì)本站的支持!
- 關(guān)于Android HTML5 audio autoplay無效問題的解決方案
- HTML5 canvas 9繪制圖片實(shí)例詳解
- js HTML5多圖片上傳及預(yù)覽實(shí)例解析(不含前端的文件分割)
- 手機(jī)端 HTML5使用photoswipe.js仿微信朋友圈圖片放大效果
- 使用HTML5+Boostrap打造簡(jiǎn)單的音樂播放器
- 正則表達(dá)式與HTML5新元素
- NodeJS與HTML5相結(jié)合實(shí)現(xiàn)拖拽多個(gè)文件上傳到服務(wù)器的實(shí)現(xiàn)方法
- JS+HTML5手機(jī)開發(fā)之滾動(dòng)和慣性緩動(dòng)實(shí)現(xiàn)方法分析
- HTML5 移動(dòng)頁面自適應(yīng)手機(jī)屏幕寬度詳解
相關(guān)文章
JS+CSS+HTML實(shí)現(xiàn)“代碼雨”類似黑客帝國(guó)文字下落效果
這篇文章主要介紹了JS+CSS+HTML實(shí)現(xiàn)“代碼雨”類似黑客帝國(guó)文字下落效果,需要的朋友可以參考下2020-03-03
微信小程序側(cè)邊欄滑動(dòng)特效(左右滑動(dòng))
這篇文章主要介紹了微信小程序側(cè)邊欄滑動(dòng)特效(左右滑動(dòng)),今天小編給大家?guī)硭膫€(gè)漂亮的特效,具體效果展示和代碼實(shí)現(xiàn)大家通過本文學(xué)習(xí)吧2017-01-01
HTML+JS實(shí)現(xiàn)“代碼雨”效果源碼(黑客帝國(guó)文字下落效果)
這篇文章主要介紹了HTML+JS實(shí)現(xiàn)“代碼雨”效果源碼類似黑客帝國(guó)文字下落效果,需要的朋友可以參考下2020-03-03
JS實(shí)現(xiàn)谷歌瀏覽器插件拷貝語音功能詳解
這篇文章主要為大家介紹了JS實(shí)現(xiàn)谷歌瀏覽器插件拷貝語音功能詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
HTML5 實(shí)現(xiàn)的一個(gè)俄羅斯方塊實(shí)例代碼
這篇文章主要介紹了HTML5 實(shí)現(xiàn)的一個(gè)俄羅斯方塊實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2016-09-09

