实现一个网页版的2048游戏,过程参考了慕课网2048游戏的教程,
具体代码如下:
html结构:
<body>
<div class="header">
<h2>2048</h2>
<a href="javascript:newGame()" id="newGameBtn">New Game</a>
<p>Score:<span id="score">0</span></p>
</div>
<div id="grid-container" class="grid-container">
<div class="grid-cell" id="grid-cell-0-0"></div>
<div class="grid-cell" id="grid-cell-0-1"></div>
<div class="grid-cell" id="grid-cell-0-2"></div>
<div class="grid-cell" id="grid-cell-0-3"></div>
<div class="grid-cell" id="grid-cell-1-0"></div>
<div class="grid-cell" id="grid-cell-1-1"></div>
<div class="grid-cell" id="grid-cell-1-2"></div>
<div class="grid-cell" id="grid-cell-1-3"></div>
<div class="grid-cell" id="grid-cell-2-0"></div>
<div class="grid-cell" id="grid-cell-2-1"></div>
<div class="grid-cell" id="grid-cell-2-2"></div>
<div class="grid-cell" id="grid-cell-2-3"></div>
<div class="grid-cell" id="grid-cell-3-0"></div>
<div class="grid-cell" id="grid-cell-3-1"></div>
<div class="grid-cell" id="grid-cell-3-2"></div>
<div class="grid-cell" id="grid-cell-3-3"></div>
</div>
一些css样式:
.header {
margin: 0 auto;
width: 100%;
font-family: "Microsoft YaHei", "微软雅黑";
position: relative;
clear: both;
}
.header h2 {
font-size: 55px;
display: inline-block;
color: #776E65;
margin: 10px 14px 10px -100px;
position: absolute;
}
.header a {
text-decoration: none;
background: #8F7A66;
display: inline-block;
height: 45px;
width: 120px;
line-height: 50px;
font-size: 20px;
border-radius: 5px;
color: #ffffff;
text-align: center;
margin: 10px;
}
.header p {
font-family: "Microsoft YaHei", "微软雅黑";
font-size: 20px;
color: #8F7A66;
margin-left: 10px;
}
.grid-container {
margin: 15px auto;
background-color: #bbada0;
position: relative;
}
.grid-cell {
width: 100px;
height: 100px;
background: #ccc0b3;
border-radius: 10px;
position: absolute;
}
.number-cell {
font-family: "Microsoft YaHei", "微软雅黑";
font-weight: bold;
text-align: center;
position: absolute;
}
JavaScript:
var board = new Array(),
score = 0,
hasConflicted = new Array();
var startx, starty, endx, endy;
screenWidth = $(window).width();
gridContainerWidth = screenWidth * 0.92;
cellWidth = screenWidth * 0.18;
cellDistance = screenWidth * 0.04;
$(function () {
newGame();
});
function newGame() {
adjustForMobile();
init();
}
function adjustForMobile() {
if (screenWidth >= 500) {
gridContainerWidth = 500;
cellWidth = 100;
cellDistance = 20;
}
$(".header").css("width", gridContainerWidth + "px");
$(".header").css("left", cellWidth * 3 + "px");
$(".header h2").css("margin-left", -(gridContainerWidth / 2 - cellDistance) + "px");
var theGridContainer = $("#grid-container");
theGridContainer.css({
"width": gridContainerWidth + "px",
"height": gridContainerWidth + "px",
"border-radius": gridContainerWidth * 0.02 + "px"
});
$(".grid-cell").css({
"height": cellWidth + "px",
"width": cellWidth + "px",
"border-radius": gridContainerWidth * 0.02 + "px"
});
}
function init() {
score = 0;
updateScore();
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
$("#grid-cell-" + i + "-" + j).css("top", getPosTop(i, j));
$("#grid-cell-" + i + "-" + j).css("left", getPosLeft(i, j));
}
}
for (var i = 0; i < 4; i++) {
board[i] = new Array();
hasConflicted[i] = new Array();
for (var j = 0; j < 4; j++) {
board[i][j] = 0;
hasConflicted[i][j] = false;
}
}
generateOneNumber();
generateOneNumber();
updateBoardView();
}
function updateBoardView() {
$(".number-cell").remove();
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
$("#grid-container").append('<div class="number-cell" id="number-cell-' + i + '-' + j + '"></div>');
var theNumberCell = $("#number-cell-" + i + "-" + j);
if (board[i][j] == 0) {
theNumberCell.css("width", 0);
theNumberCell.css("height", 0);
theNumberCell.css("top", getPosTop(i, j) + cellWidth / 2);
theNumberCell.css("left", getPosLeft(i, j) + cellWidth / 2);
}
else {
theNumberCell.css({
"width": cellWidth + "px",
"height": cellWidth + "px",
"line-height": cellWidth + "px",
"border-radius": gridContainerWidth * 0.02 + "px",
"top": getPosTop(i, j),
"left": getPosLeft(i, j),
"background-color": getNumberBackgroundColor(board[i][j]),
"color": getNumberColor(board[i][j]),
"font-size": cellWidth * 0.65 + "px"
});
theNumberCell.html(board[i][j]);
if (board[i][j] >= 128) {
theNumberCell.css("font-size", cellWidth * 0.5);
}
}
hasConflicted[i][j] = false;
}
}
}
function generateOneNumber() {
if (!nospace(board)) {
var randx = parseInt(Math.floor(Math.random() * 4));
var randy = parseInt(Math.floor(Math.random() * 4));
var count = 0;
while (count < 40) {
if (board[randx][randy] == 0) {
break;
}
randx = parseInt(Math.floor(Math.random() * 4));
randy = parseInt(Math.floor(Math.random() * 4));
}
if (count == 39) {
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
if (board[i][j] == 0) {
randx = i;
randy = j;
}
}
}
}
var randNumber = Math.random() < 0.6 ? 2 : 4;
board[randx][randy] = randNumber;
showNumberWithAnimation(randx, randy, randNumber);
}
return true;
}
function isGameOver() {
if (nospace(board) && noMove(board)) {
gameOver("Just Try Again!")
}
}
function gameOver(text) {
generateOneNumber();
alert(text);
}
function isWinGame(board) {
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
if (board[i][j] == 2048) {
return true;
}
}
}
return false;
}
$(document).keydown(function (event) {
switch (event.keyCode) {
case 37:
event.preventDefault();
if (moveLeft()) {
setTimeout(generateOneNumber(), 220);
setTimeout(isGameOver(), 220);
}
break;
case 38:
event.preventDefault();
if (moveUp()) {
setTimeout(generateOneNumber(), 210);
setTimeout(isGameOver(), 220);
}
break;
case 39:
event.preventDefault();
if (moveRight()) {
setTimeout(generateOneNumber(), 210);
setTimeout(isGameOver(), 220);
}
break;
case 40:
event.preventDefault();
if (moveDown()) {
setTimeout(generateOneNumber(), 210);
setTimeout(isGameOver(), 220);
}
break;
default :
}
});
function moveLeft() {
if (!canMoveLeft(board)) {
generateOneNumber();
return false;
}
for (var i = 0; i < 4; i++) {
for (var j = 1; j < 4; j++) {
if (board[i][j] != 0) {
for (var k = 0; k < j; k++) {
if (board[i][k] == 0 && noBlockHorizontal(i, k, j, board)) {
showMoveAnimation(i, j, i, k);
board[i][k] = board[i][j];
board[i][j] = 0;
continue;
}
if (board[i][k] == board[i][j] && noBlockHorizontal(i, k, j, board) && !hasConflicted[i][k]) {
showMoveAnimation(i, j, i, k);
board[i][k] += board[i][j];
board[i][j] = 0;
score += board[i][k];
updateScore();
if (isWinGame(board)) {
gameOver("You Get 2048!");
}
continue;
}
}
}
}
}
setTimeout(updateBoardView(), 210);
return true;
}
function moveUp() {
if (!canMoveUp(board)) {
generateOneNumber();
return false;
}
for (var j = 0; j < 4; j++) {
for (var i = 1; i < 4; i++) {
if (board[i][j] != 0) {
for (var k = 0; k < i; k++) {
if (board[k][j] == 0 && noBlockVertical(k, i, j, board)) {
showMoveAnimation(i, j, k, j);
board[k][j] = board[i][j];
board[i][j] = 0;
continue;
}
if (board[k][j] == board[i][j] && noBlockVertical(k, i, j, board) && !hasConflicted[k][j]) {
showMoveAnimation(i, j, k, j);
board[k][j] += board[i][j];
board[i][j] = 0;
score += board[k][j];
updateScore();
if (isWinGame(board)) {
gameOver("You Get 2048!");
}
continue;
}
}
}
}
}
setTimeout(updateBoardView(), 220);
return true;
}
function moveRight() {
if (!canMoveRight(board)) {
generateOneNumber();
return false;
}
for (var i = 0; i < 4; i++) {
for (var j = 2; j >= 0; j--) {
if (board[i][j] != 0) {
for (var k = 3; k > j; k--) {
if (board[i][k] == 0 && noBlockHorizontal(i, j, k, board)) {
showMoveAnimation(i, j, i, k);
board[i][k] = board[i][j];
board[i][j] = 0;
continue;
}
if (board[i][k] == board[i][j] && noBlockHorizontal(i, j, k, board) && !hasConflicted[i][k]) {
showMoveAnimation(i, j, i, k);
board[i][k] += board[i][j];
board[i][j] = 0;
score += board[i][k];
updateScore();
if (isWinGame(board)) {
gameOver("You Get 2048!");
}
continue;
}
}
}
}
}
setTimeout(updateBoardView(), 500);
return true;
}
function moveDown() {
if (!canMoveDown(board)) {
generateOneNumber();
return false;
}
for (var j = 0; j < 4; j++) {
for (var i = 2; i >= 0; i--) {
if (board[i][j] != 0) {
for (var k = 3; k > i; k--) {
if (board[k][j] == 0 && noBlockVertical(i, k, j, board)) {
showMoveAnimation(i, j, k, j);
board[k][j] = board[i][j];
board[i][j] = 0;
continue;
}
if (board[k][j] == board[i][j] && noBlockVertical(i, k, j, board) && !hasConflicted[k][j]) {
showMoveAnimation(i, j, k, j);
board[k][j] += board[i][j];
board[i][j] = 0;
score += board[k][j];
updateScore();
if (isWinGame(board)) {
gameOver("You Get 2048!");
}
continue;
}
}
}
}
}
setTimeout(updateBoardView(), 220);
return true;
}
function updateScore() {
$("#score").html(score);
}
function getPosTop(i, j) {
return cellDistance + (cellDistance + cellWidth) * i;
}
function getPosLeft(i, j) {
return cellDistance + (cellDistance + cellWidth) * j;
}
function getNumberBackgroundColor(number) {
switch (number) {
case 2:
return "#EEE4DA";
break;
case 4:
return "#EDE0C8";
break;
case 8:
return "#F2B179";
break;
case 16 :
return "#F59563";
break;
case 32:
return "#F67C5F";
break;
case 64:
return "#F65E3B";
break;
case 128:
return "#EDCF72";
break;
case 256:
return "#6BADF6";
break;
case 512:
return "#EBC400";
break;
case 1024:
return "#EBC400";
break;
case 2048:
return "#EBC400";
break;
}
return "#FC6";
}
function getNumberColor(number) {
if (number <= 4) {
return "#776E65";
}
return "#F9F6F2";
}
function nospace(board) {
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
if (board[i][j] == 0) {
return false;
}
}
}
return true;
}
function noMove(board) {
if (canMoveLeft(board) ||
canMoveUp(board) ||
canMoveRight(board) ||
canMoveDown(board)) {
return false;
}
return true;
}
function canMoveLeft(borad) {
for (var i = 0; i < 4; i++) {
for (var j = 1; j < 4; j++) {
if (board[i][j] != 0) {
if (board[i][j - 1] == 0 || board[i][j - 1] == board[i][j]) {
return true;
}
}
}
}
return false;
}
function canMoveUp(borad) {
for (var i = 1; i < 4; i++) {
for (var j = 0; j < 4; j++) {
if (board[i][j] != 0) {
if (board[i - 1][j] == 0 || board[i - 1][j] == board[i][j]) {
return true;
}
}
}
}
return false;
}
function canMoveRight(borad) {
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 3; j++) {
if (board[i][j] != 0) {
if (board[i][j + 1] == 0 || board[i][j + 1] == board[i][j]) {
return true;
}
}
}
}
return false;
}
function canMoveDown(borad) {
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 4; j++) {
if (board[i][j] != 0) {
if (board[i + 1][j] == 0 || board[i + 1][j] == board[i][j]) {
return true;
}
}
}
}
return false;
}
function noBlockHorizontal(row, col1, col2, board) {
for (var i = col1 + 1; i < col2; i++) {
if (board[row][i] != 0) {
return false;
}
}
return true;
}
function noBlockVertical(row1, row2, col, board) {
for (var i = row1 + 1; i < row2; i++) {
if (board[i][col] != 0) {
return false;
}
}
return true;
}
function showNumberWithAnimation(i, j, randNumber) {
var numberCell = $("#number-cell-" + i + "-" + j);
numberCell.css("background-color", getNumberBackgroundColor(board[i][j]));
numberCell.css("color", getNumberColor(board[i][j]));
numberCell.css("border-radius", gridContainerWidth * 0.02 + "px");
numberCell.css("line-height", cellWidth + "px");
numberCell.css("font-size", cellWidth * 0.65 + "px");
numberCell.html(board[i][j]);
numberCell.animate({
width: cellWidth,
height: cellWidth,
top: getPosTop(i, j),
left: getPosLeft(j, j)
}, 150)
}
function showMoveAnimation(fromx, fromy, tox, toy) {
var numberCell = $("#number-cell-" + fromx + "-" + fromy);
numberCell.animate({
top: getPosTop(tox, toy),
left: getPosLeft(tox, toy)
}, 100)
}
ps:
- 简单实现了基本的游戏功能,以及简单的响应式可能还存在一些bug,有时间再来调试吧
- 附上原版游戏地址: http://gabrielecirulli.github.io/2048/
- 附上我完整的源代码地址:My Demos