1 Star 1 Fork 0

lazy/jsGame

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
tetris.html 18.05 KB
一键复制 编辑 原始数据 按行查看 历史
lazy 提交于 2019-10-08 23:52 +08:00 . 上传
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html:charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
<title>俄罗斯方块</title>
<style type="text/css">
html,body{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background-color: white;
}
html{
font-size:20px;
}
table{
margin: 0 auto;
border-collapse: separate;
border-spacing: 0px;
}
td{
padding: 0;
border: 1px solid transparent;
background-clip: padding-box;
}
#scoreArea{
text-align: center;
}
#score{
color: red;
}
#gameArea table{
border: 2px solid #D3D3D3;
}
#gameArea td{
border-color: #F5F5F5;
}
#shapeArea{
width: 100%;
margin-left: auto;
margin-right: auto;
font-size: 0;
}
#shapeArea div{
display: inline-block;
width: 33%;
height: 100%;
}
table.shape{
margin: 0 auto;
z-index: 1;
}
table.shape td{
}
#gameOverArea{
position: fixed;
z-index: 2;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.1);
display: none;
}
#gameOverArea > div{
margin: 0 auto;
width: 80%;
text-align: center;
color: white;
background-color: rgba(0,0,0,0.5);
padding: 1rem 0;
letter-spacing: 0.5rem;
}
#gameOverArea button{
background: #FFFACD;
border: none;
padding: 5px 12px;
font-size: 18px;
letter-spacing: 2px;
margin-top: 0.5rem;
}
</style>
</head>
<body>
<div id="gameOverArea">
<div>
<div>游戏结束</div>
<div>Game Over</div>
<div>
<button type="button" onclick="Tetris.newGame();">新游戏</button>
</div>
</div>
</div>
<div id="scoreArea">
<span>分数:</span>
<span id="score">0</span>
</div>
<div id="gameArea"></div>
<div id="shapeArea">
<div></div>
<div></div>
<div></div>
</div>
</body>
<script type="text/javascript">
window.onload = function(){
mobileEvents();
Tetris.init();
};
function isMobile(){
// 判断是否在移动端打开
return /Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent);
}
/*移动端事件*/
function mobileEvents(){
if(isMobile()){
// 禁止选中
document.body.addEventListener('touchstart', function (e) {
e.preventDefault();
}, {passive: false});
// 禁止拉动页面
document.body.addEventListener('touchmove', function (e) {
e.preventDefault();
}, {passive: false});
// 使按钮onclick执行,因为在body的touchstart中preventDefault()阻止了click事件
let buttons = document.getElementsByTagName("button");
for(let btn of buttons){
btn.addEventListener("touchend", function(e){
if(this.onclick){
this.onclick();
}
e.stopPropagation();
});
}
}
}
class Grid{
/* color 格子颜色,ele 对应的表格单元 */
constructor(color, ele) {
this.color = color;
this.ele = ele;
}
}
class Shape{
/* color 方块颜色, points 长度为2 + 16(4 * 4)的数组,前两位表示行数和列数,其后表示方块,0表示没方块,1表示有方块 */
constructor(color,points){
this.color = color;
this.points = points;
}
}
let Tetris = {
scoreAreaEle: document.getElementById("scoreArea"),
scoreEle: document.getElementById("score"),
gameAreaEle: document.getElementById("gameArea"),
shapeAreaEle: document.getElementById("shapeArea"),
gameOverAreaEle: document.getElementById("gameOverArea"),
isGameOver: false,
score: 0,
rows: 10,
cols: 10,
gridWidth: 0,
gridOffsetWidth: 0,
gridBorderWidth: 1,
grids: [],
shapes: [],
moveObj: null,
moveObjStyle: {},
preX: 0,
preY: 0,
init(){
Tetris.initGameArea();
Tetris.initSize();
Tetris.initShapes();
Tetris.bindEvents();
Tetris.getShape();
},
initGameArea(){
let w = Math.floor(document.body.clientWidth / (Tetris.cols + 3));
let h = Math.floor(document.body.clientHeight / (Tetris.rows + 6));
Tetris.gridOffsetWidth = Math.min(w, h);
Tetris.gridWidth = Tetris.gridOffsetWidth - 2 * Tetris.gridBorderWidth;
let htmlStr = "";
htmlStr += "<table>";
htmlStr += "<tbody>";
for(let i = 0; i < Tetris.rows; i++){
htmlStr += "<tr>";
for(let j = 0; j < Tetris.cols; j++){
htmlStr += '<td style="width: ' + Tetris.gridWidth + 'px; height: ' + Tetris.gridWidth + 'px;"></td>';
}
htmlStr += "</tr>";
}
htmlStr += "</tbody>";
htmlStr += "</table>";
Tetris.gameAreaEle.innerHTML = htmlStr;
let tdEles = Tetris.gameAreaEle.getElementsByTagName("td");
for(let tdEle of tdEles){
Tetris.grids.push(new Grid(null, tdEle));
}
},
initSize(){
this.scoreAreaEle.style.height = Tetris.gridOffsetWidth + "px";
this.scoreAreaEle.style.lineHeight = Tetris.gridOffsetWidth + "px";
this.gameAreaEle.style.paddingTop = Tetris.gridOffsetWidth + "px";
this.gameAreaEle.style.paddingBottom = Tetris.gridOffsetWidth + "px";
this.shapeAreaEle.style.height = (3 * Tetris.gridOffsetWidth) + "px";
this.shapeAreaEle.style.width = (Tetris.cols * Tetris.gridOffsetWidth) + "px";
this.gameOverAreaEle.style.paddingTop = (document.body.clientHeight * 0.3) + "px";
let height = this.scoreAreaEle.offsetHeight + this.gameAreaEle.offsetHeight + this.shapeAreaEle.offsetHeight;
if(document.body.clientHeight > height){
let marginTB = Math.floor((document.body.clientHeight - height) / 2);
this.scoreAreaEle.style.marginTop = marginTB + "px";
this.shapeAreaEle.style.marginBottom = marginTB + "px";
}
},
initShapes: function(){
/*
#
#
#
*/
let iShape = new Shape("cyan",[3,1, 1,1,1]);
Tetris.shapes.push(iShape);
/*
###
*/
let irShape = new Shape("cyan",[1,3, 1,1,1]);
Tetris.shapes.push(irShape);
/*
#00
###
*/
let lShape = new Shape("skyblue",[2,3, 1,0,0, 1,1,1]);
Tetris.shapes.push(lShape);
/*
##
#0
#0
*/
let lrShape = new Shape("skyblue",[3,2, 1,1, 1,0, 1,0]);
Tetris.shapes.push(lrShape);
/*
000
###
00#
*/
let lr2Shape = new Shape("skyblue",[2,3, 1,1,1, 0,0,1]);
Tetris.shapes.push(lr2Shape);
/*
0#
0#
##
*/
let lr3Shape = new Shape("skyblue",[3,2, 0,1, 0,1, 1,1]);
Tetris.shapes.push(lr3Shape);
/*
000
00#
###
*/
let jShape = new Shape("deeppink",[2,3, 0,0,1, 1,1,1]);
Tetris.shapes.push(jShape);
/*
#0
#0
##
*/
let jrShape = new Shape("deeppink",[3,2, 1,0, 1,0, 1,1]);
Tetris.shapes.push(jrShape);
/*
###
#00
*/
let jr2Shape = new Shape("deeppink",[2,3, 1,1,1, 1,0,0]);
Tetris.shapes.push(jr2Shape);
/*
##
0#
0#
*/
let jr3Shape = new Shape("deeppink",[3,2, 1,1, 0,1, 0,1]);
Tetris.shapes.push(jr3Shape);
/*
###
0#0
*/
let tShape= new Shape("yellow",[2,3, 1,1,1, 0,1,0]);
Tetris.shapes.push(tShape);
/*
0#
##
0#
*/
let trShape= new Shape("yellow",[3,2, 0,1, 1,1, 0,1]);
Tetris.shapes.push(trShape);
/*
0#0
###
*/
let tr2Shape= new Shape("yellow",[2,3, 0,1,0, 1,1,1]);
Tetris.shapes.push(tr2Shape);
/*
#0
##
#0
*/
let tr3Shape= new Shape("yellow",[3,2, 1,0, 1,1, 1,0]);
Tetris.shapes.push(tr3Shape);
/*
##
##
*/
let oShape = new Shape("blue",[2,2, 1,1, 1,1]);
Tetris.shapes.push(oShape);
/*
##0
0##
*/
let zShape = new Shape("purple",[2,3, 1,1,0, 0,1,1]);
Tetris.shapes.push(zShape);
/*
0#
##
#0
*/
let zrShape = new Shape("purple",[3,2, 0,1, 1,1, 1,0]);
Tetris.shapes.push(zrShape);
/*
0##
##0
*/
let sShape = new Shape("red",[2,3, 0,1,1, 1,1,0]);
Tetris.shapes.push(sShape);
/*
#0
##
0#
*/
let srShape = new Shape("red",[3,2, 1,0, 1,1, 0,1]);
Tetris.shapes.push(srShape);
/*
#
*/
let oneShape = new Shape("green",[1,1, 1]);
Tetris.shapes.push(oneShape);
},
createShape(){
let randomIndex = Math.round(Math.random() * (Tetris.shapes.length - 1));
let shape = Tetris.shapes[randomIndex];
let rs = shape.points[0];
let cs = shape.points[1];
let isBlock = 0;
let htmlStr = "";
let bgcolorStyle = "";
let marginTop = 0;
if(rs < 3){
marginTop = Tetris.gridOffsetWidth;
}
htmlStr += `<table class='shape' style="margin-top: ${marginTop}px;" data-shape-index="${randomIndex}">`;
htmlStr += "<tbody>";
for(let i = 0; i < rs; i++){
htmlStr += "<tr>";
for(let j = 0; j < cs; j++){
isBlock = shape.points[2 + i * cs + j];
if(isBlock == 1){
bgcolorStyle = "background-color: " + shape.color + ";";
}else{
bgcolorStyle = "";
}
htmlStr += '<td style="width: ' + Tetris.gridWidth + 'px; height: ' + Tetris.gridWidth + 'px;' + bgcolorStyle + '"';
htmlStr += ' data-is="' + isBlock + '"></td>';
}
htmlStr += "</tr>";
}
htmlStr += "</tbody>";
htmlStr += "</table>";
return htmlStr;
},
getShape(){
let divEles = Tetris.shapeAreaEle.children;
for(let divEle of divEles){
divEle.innerHTML = Tetris.createShape();
if(isMobile()){
divEle.firstElementChild.addEventListener("touchstart", Tetris.touchStart);
}else{
divEle.firstElementChild.addEventListener("mousedown", Tetris.mouseDown);
}
}
},
bindEvents(){
if(isMobile()){ /* 移动端 */
document.addEventListener("touchmove", Tetris.touchMove);
document.addEventListener("touchend", Tetris.touchEnd);
}else{ /* PC端 */
document.addEventListener("mousemove",Tetris.mouseMove);
document.addEventListener("mouseup",Tetris.mouseUp);
}
},
mouseDown(e){
Tetris.moveStart(e.clientX, e.clientY, this);
},
mouseMove(e){
Tetris.move(e.clientX, e.clientY);
},
mouseUp(e){
Tetris.moveEnd(e.clientX, e.clientY);
},
touchStart(e){
let x = e.touches[0].clientX;
let y = e.touches[0].clientY;
Tetris.moveStart(x, y, this);
},
touchMove(e){
let x = e.touches[0].clientX;
let y = e.touches[0].clientY;
Tetris.move(x, y);
},
touchEnd(e){
let x = e.changedTouches[0].clientX;
let y = e.changedTouches[0].clientY;
Tetris.moveEnd(x, y);
},
moveStart(clientX,clientY,mObj){
if(!Tetris.isGameOver){
Tetris.moveObj = mObj;
Tetris.preX = clientX;
Tetris.preY = clientY;
Tetris.moveObjStyle = {};
Tetris.moveObjStyle.marginTop = Tetris.moveObj.style.marginTop;
Tetris.moveObjStyle.marginLeft = Tetris.moveObj.style.marginLeft;
Tetris.moveObjStyle.marginRight = Tetris.moveObj.style.marginRight;
}
},
move(clientX,clientY){
if(!Tetris.isGameOver && Tetris.moveObj){
Tetris.moveObj.style.position="absolute";
Tetris.moveObj.style.left = (Tetris.moveObj.offsetLeft + clientX - Tetris.preX) + "px";
Tetris.moveObj.style.top = (Tetris.moveObj.offsetTop + clientY - Tetris.preY) + "px";
Tetris.moveObj.style.marginLeft = "0px";
Tetris.moveObj.style.marginRight = "0px";
Tetris.moveObj.style.marginTop = "0px";
Tetris.preX = clientX;
Tetris.preY = clientY;
}
},
moveEnd(clientX,clientY){
if(!Tetris.isGameOver && Tetris.moveObj){
/* 判断是否能放在游戏区,能就放,不能返回原位 */
if(!Tetris.putInPlace()){
Tetris.backPlace();
}
Tetris.moveObj = null;
}
},
gameOver(){
Tetris.isGameOver = true;
/* 提示游戏结束 */
Tetris.gameOverAreaEle.style.display = "block";
},
newGame(){
/* 隐藏游戏结束提示 */
Tetris.gameOverAreaEle.style.display = "none";
Tetris.isGameOver = false;
/* 分数归零 */
Tetris.scoreEle.innerText = "0";
Tetris.score = 0;
/* 清空游戏区域 */
for(let g of Tetris.grids){
Tetris.clearGrid(g);
}
/* 产生新形状 */
Tetris.getShape();
},
canContinue(){
let divEles = Tetris.shapeAreaEle.children;
let shape = null;
for(let divEle of divEles){
if(divEle.children.length > 0){
shape = Tetris.shapes[divEle.firstElementChild.getAttribute("data-shape-index")];
for(let i = 0; i <= Tetris.rows - shape.points[0]; i++){
for(let j = 0; j <= Tetris.cols - shape.points[1]; j++){
if(Tetris.canPutIn(i, j, shape)){
return true;
}
}
}
}
}
return false;
},
/* 能否把形状放在以(row,col)为左上角顶点的区域 */
canPutIn(row, col, shape){
if(row > Tetris.rows - shape.points[0] || col > Tetris.cols - shape.points[1]){
return false;
}
let rs = shape.points[0];
let cs = shape.points[1];
let gridIndex = null;
for(let i = 0; i < rs; i++){
for(let j = 0; j < cs; j++){
gridIndex = Tetris.getGridIndex(row + i, col + j);
if(Tetris.grids[gridIndex].color && shape.points[2 + i * cs + j]){
return false;
}
}
}
return true;
},
/* 把形状放在游戏区内,放入成功返回true,否则返回false */
putInPlace(){
let top = Tetris.moveObj.offsetTop;
let bottom = top + Tetris.moveObj.offsetHeight;
let left = Tetris.moveObj.offsetLeft;
let right = left + Tetris.moveObj.offsetWidth;
/* 移动对象左上角方块的中心 */
let centerX = left + Tetris.gridOffsetWidth / 2;
let centerY = top + Tetris.gridOffsetWidth / 2;
let gameScope = Tetris.getGameScope();
/* 在游戏区内 */
if(Tetris.between(centerY, gameScope.top, gameScope.bottom)
&& Tetris.between(centerX, gameScope.left, gameScope.right)){
let row = Math.floor((centerY - gameScope.top) / Tetris.gridOffsetWidth);
let col = Math.floor((centerX - gameScope.left) / Tetris.gridOffsetWidth);
console.info(row, col);
let shape = Tetris.shapes[Tetris.moveObj.getAttribute("data-shape-index")];
if(!Tetris.canPutIn(row, col, shape)){
return false;
}else{
let rs = shape.points[0];
let cs = shape.points[1];
let gridIndex = null;
/* 可以放在游戏区域,放置位置填充颜色,删除形状 */
for(let m = 0; m < rs; m++){
for(let n = 0; n < cs; n++){
if(shape.points[2 + m * cs + n]){
gridIndex = Tetris.getGridIndex(row + m, col + n);
Tetris.grids[gridIndex].color = shape.color;
Tetris.grids[gridIndex].ele.style.backgroundColor = shape.color;
}
}
}
/* 删除形状 */
Tetris.moveObj.parentNode.removeChild(Tetris.moveObj);
/* 放置形状后的处理 */
Tetris.afterPutIn(row, col, shape);
return true;
}
}else{/* 不在游戏区内 */
return false;
}
},
afterPutIn(row, col, shape){
/* 如果没有形状,产生新形状 */
let newShape = true;
let divEles = Tetris.shapeAreaEle.children;
for(let divEle of divEles){
if(divEle.children.length > 0){
newShape = false;
break;
}
}
if(newShape){
Tetris.getShape();
}
/* 消除填满方块的行和列 */
Tetris.clearFull(row, col, shape);
/* 判断是否还可以放入形状 */
if(!Tetris.canContinue()){
/* 已无路可走,游戏结束 */
Tetris.gameOver();
}
},
/* 判断能否消除 */
clearFull(row, col, shape){
let gridIndex = null;
let isFull = true;
let fullRows = [];
let fullCols = [];
/* 判断行能否消除 */
for(let i = 0; i < shape.points[0]; i++){
isFull = true;
for(let j = 0; j < Tetris.cols; j++){
gridIndex = Tetris.getGridIndex(row + i, j);
if(!Tetris.grids[gridIndex].color){
isFull = false;
break;
}
}
if(isFull){
fullRows.push(row + i);
}
}
/* 判断列能否消除 */
for(let m = 0; m < shape.points[1]; m++){
isFull =true;
for(let n = 0; n < Tetris.rows; n++){
gridIndex = Tetris.getGridIndex(n, col + m);
if(!Tetris.grids[gridIndex].color){
isFull = false;
break;
}
}
if(isFull){
fullCols.push(col + m);
}
}
console.info(fullRows, fullCols);
/* 消除行,清除颜色 */
for(let r of fullRows){
Tetris.score++;
for(let y = 0; y < Tetris.cols; y++){
gridIndex = Tetris.getGridIndex(r, y);
Tetris.clearGrid(Tetris.grids[gridIndex]);
}
}
/* 消除列,清除颜色 */
for(let c of fullCols){
Tetris.score++;
for(let x = 0; x < Tetris.rows; x++){
gridIndex = Tetris.getGridIndex(x, c);
Tetris.clearGrid(Tetris.grids[gridIndex]);
}
}
Tetris.scoreEle.innerText = Tetris.score;
},
/* 清除格子颜色 */
clearGrid(grid){
grid.color = null;
grid.ele.style.backgroundColor = "";
},
getGridIndex(row, col){
return row * Tetris.cols + col;
},
between(target, x, y){
let smaller = Math.min(x,y);
let larger = Math.max(x,y);
if(target >= smaller && target <= larger){
return true;
}else{
return false;
}
},
getGameScope(){
let gameEle = Tetris.gameAreaEle.firstElementChild;
let borderWidth = 2;
let top = gameEle.offsetTop + borderWidth;
let bottom = top + Tetris.rows * Tetris.gridOffsetWidth;
let left = gameEle.offsetLeft + borderWidth;
let right = left + Tetris.cols * Tetris.gridOffsetWidth;
return {"top": top, "bottom": bottom, "left": left, "right": right};
},
backPlace(){
Tetris.moveObj.style.position="";
Tetris.moveObj.style.left = "";
Tetris.moveObj.style.top = "";
for(let key in Tetris.moveObjStyle){
Tetris.moveObj.style[key] =Tetris.moveObjStyle[key];
}
Tetris.moveObjStyle = {};
},
};
</script>
</html>
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
JavaScript
1
https://gitee.com/luckiness/jsGame.git
git@gitee.com:luckiness/jsGame.git
luckiness
jsGame
jsGame
master

搜索帮助