今天使用html + css + js给同学们做了一个简易版的2048益智游戏,希望大家按照步骤勤加练习,在编码的坑里早日踏上康庄大道,祝前程似锦!
效果图:
附源码github链接:
https://github.com/LittleGreyKing-FriedBlackYoFeed-xoox/2048.git
开发思路:
一、使用HBuilder工具创建空白html项目
创建项目时路径尽量不要有中文路径
三、书写html标签
引入css和js文件:
书写html标签:
html标签的代码,直接放在body标签中即可:
index.html
<header>
<h1>2048</h1>
</header>
<div id="gamePanel">
<p><a class="button" id="newGame">New Game</a> Score: <span id="score">0</span><span class="writer">小灰灰版</span></p>
<div id="gridPanel">
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="cell " id="cell00"> </div>
<div class="cell " id="cell01"> </div>
<div class="cell " id="cell02"> </div>
<div class="cell " id="cell03"> </div>
<div class="cell " id="cell10"> </div>
<div class="cell " id="cell11"> </div>
<div class="cell " id="cell12"> </div>
<div class="cell " id="cell13"> </div>
<div class="cell " id="cell20"> </div>
<div class="cell " id="cell21"> </div>
<div class="cell " id="cell22"> </div>
<div class="cell " id="cell23"> </div>
<div class="cell " id="cell30"> </div>
<div class="cell " id="cell31"> </div>
<div class="cell " id="cell32"> </div>
<div class="cell " id="cell33"> </div>
</div>
<div id="gameOver">
<div>
<!--背景 -->
</div>
<p>
<!-- 前景 -->
Game Over!<br>
Score: <span id="finalScore">0</span><br>
<a class="button" id="restart">Try Again!</a>
</p>
</div>
</div>
* {
padding: 0;
margin: 0;
}
div,
p,
h1,
h2,
a,
span {
font-family: Arial;
font-weight: bold;
}
header {
padding-top: 16px;
}
h1 {
font-size: 40px;
font-weight: bold;
text-align: center;
}
#gamePanel {
margin: 0 auto;
width: 500px;
position: relative;
}
#gridPanel {
width: 480px;
height: 480px;
background: #BBADA0;
border-radius: 10px;
padding: 20px 0 0 20px;
position: relative;
}
#gamePanel p {
padding: 8px;
}
/* 按钮样式 */
.button {
display: inline-block;
padding: 10px;
background: #9F8B77;
border-radius: 6px;
color: #FFF;
cursor: pointer;
}
.grid,
.cell {
width: 100px;
height: 100px;
border-radius: 6px;
}
/* 背景网格 */
#gamePanel .grid {
background-color: #ccc0b3;
float: left;
margin: 0 20px 20px 0;
}
/* 格式化前景单元格中位置 */
.cell {
position: absolute;
line-height: 100px;
vertical-align: middle;
text-align: center;
font-size: 60px;
color: #776E65;
}
/* 前景格中的行位置 */
#cell00,
#cell01,
#cell02,
#cell03 {
top: 20;
}
#cell10,
#cell11,
#cell12,
#cell13 {
top: 140px;
}
#cell20,
#cell21,
#cell22,
#cell23 {
top: 260px;
}
#cell30,
#cell31,
#cell32,
#cell33 {
top: 380px;
}
/* 前景格中的列位置 */
#cell00,
#cell10,
#cell20,
#cell30 {
left: 20px;
}
#cell01,
#cell11,
#cell21,
#cell31 {
left: 140px;
}
#cell02,
#cell12,
#cell22,
#cell32 {
left: 260px;
}
#cell03,
#cell13,
#cell23,
#cell33 {
left: 380px;
}
/* 数字显示效果 */
.num8,
.num16,
.num32,
.num64,
.num128,
.num256,
.num512,
.num1024,
.num2048,
.num4096,
.num8192 {
color: #fff;
}
.num1024,
.num2048,
.num4096,
.num8192 {
font-size: 40px;
}
.num2 {
background: #eee4da;
}
.num4 {
background: #ede0c8;
}
.num8 {
background: #f2b179;
}
.num16 {
background: #f59563;
}
.num32 {
background: #f67c5f;
}
.num64 {
background: #f65e3b;
}
.num128 {
background: #edcf72;
}
.num256 {
background: #edcc61;
}
.num512 {
background: #9c0;
}
.num1024 {
background: #33b5e5;
}
.num2048 {
background: #09c;
}
.num4096 {
background: #a6c;
}
.num8192 {
background: #93c;
}
/* 格式化Game Over的样式 */
#gameOver {
display: none;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
#gameOver div {
width: 100%;
height: 100%;
background: #555;
filter: alpha(Opacity=50);
-moz-opacity: 0.5;
opacity: 0.5;
}
#gameOver p {
position: absolute;
top: 150px;
left: 100px;
border-radius: 10px;
width: 300px;
border: 1px solid #EDCF72;
background: #fff;
line-height: 1.6em;
font-size: 30px;
color: #000;
text-align: center;
}
.writer {
width: 80px;
margin-left: 30%;
}
五、创造JS事件函数
//动画效果工具对象
var animation = {
tasks:[], //动画任务数据
timer:null,//动画定时器
times:10, //定时器次数
interval:1000/60,//定时器间隔
add:function(obj, top, left){
//动画已经开始了,不能添加任务了!
if(this.timer){
return false;
}
if(! obj){
return false;
}
//计算移动步伐
var t = (top - obj.offsetTop)/this.times;
var l = (left - obj.offsetLeft)/this.times;
//添加动画任务,其中obj是被移动到对象,top, left是移动以后的位置
var task = {
topStep:t,
leftStep:l,
element:obj,
step:function(){
var t = this.element.offsetTop;
this.element.style.top = (t+ this.topStep )+"px";
var l = this.element.offsetLeft;
this.element.style.left = (l+ this.leftStep )+"px";
},
clear:function(){
this.element.style.top = "";
this.element.style.left = "";
}
};
this.tasks[this.tasks.length]=task;
return true;
},
start:function(callback){
//如果定时器已经启动,就不能再启动定时器了
if(this.timer){
return false;
}
console.log("STATRING");
if(this.tasks.length==0){
if(callback){
callback();
}
return false;
}
//如果有callback就交给this.callback
if(callback){
this.callback = callback;
}
this.timer = setInterval(function(){
//console.log("timeOut");
//console.log(animation.times);
for(var i=0; i<animation.tasks.length; i++){
var task = animation.tasks[i];
task.step();
}
animation.times--;
if(animation.times < 0){
animation.stop();
}
}, this.interval);
return true;
},
stop: function(){
if(this.timer){
window.clearInterval(this.timer);
this.timer=null;
this.times=10;
}
//结束以后执行callback()
if(this.callback){
this.callback();
}
for(var i=0; i<this.tasks.length; i++){
var task = this.tasks[i];
task.clear();
}
this.tasks = [];//清空动画任务
},
callback:null //动画结束时候执行的方法
};
JS的部分还有index.html中包含的:
index.html 中包含的js部分
<script type="text/javascript">
//game 封装了2048的数据和核心算法
var cells = [
[2, 0, 0, 0],
[0, 32, 0, 0],
[0, 4, 0, 0],
[0, 0, 2048, 0]
];
//游戏进行中
var PLAYING = 0;
//方块正在移动动画处理中,期间不能响应键盘事件
var CELL_MOVEING = 1;
//游戏结束了,结束了就不能响应键盘事件了
var GAME_OVER = 2;
var score = 0;
//当前游戏状态
var state = PLAYING;
//动态效果开关,打开后可以绘制方块的移动动画效果
var effect = true;
/* 向上的动作, */
function upAction() {
if (state == CELL_MOVEING) {
return false;
}
if (!canMoveUp()) {
return false;
}
//每次处理一个列
for (var col = 0; col < 4; col++) {
//每一个列中 从放方向判断是否需要移动处理
upCol(col);
}
return true;
}
// 处理一个列的移动
function upCol(col) {
//一个列中,按照方方向检查是否需要合并处理。
for (var row = 0; row < 4;) {
var current = cells[row][col];
var nextRow = getNextInCol(col, row + 1, 1);
//没有下一个,就直接结束了
if (nextRow == -1) {
return;
}
var next = cells[nextRow][col];
if (current == 0) {
//下一个格子移动到当前位置。
cells[row][col] = next;
cells[nextRow][col] = 0;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + nextRow + col);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else if (current == next) {
//两个格子一样,就合并格子
cells[row][col] = next + current;
cells[nextRow][col] = 0;
score += cells[row][col];
row++;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + nextRow + col);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else {
//下个不一样,就忽略之
row++;
}
}
}
function getNextInCol(col, startRow, step) {
var row = startRow;
while (true) {
if (row < 0 || row >= 4) {
return -1;
}
if (cells[row][col] != 0) {
return row;
}
row += step;
}
}
function getNextInRow(row, startCol, step) {
var col = startCol;
while (true) {
if (col < 0 || col >= 4) {
return -1;
}
if (cells[row][col] != 0) {
return col;
}
col += step;
}
}
function downAction() {
if (state == CELL_MOVEING) {
return false;
}
if (!canMoveDown()) {
return false;
}
//每次处理一个列
for (var col = 0; col < 4; col++) {
//每一个列中 从放方向判断是否需要移动处理
downCol(col);
}
return true;
}
// 处理一个列的移动
function downCol(col) {
//一个列中,按照方方向检查是否需要合并处理。
for (var row = 3; row >= 0;) {
var current = cells[row][col];
var nextRow = getNextInCol(col, row - 1, -1);
//没有下一个,就直接结束了
if (nextRow == -1) {
return;
}
var next = cells[nextRow][col];
if (current == 0) {
//下一个格子移动到当前位置。
cells[row][col] = next;
cells[nextRow][col] = 0;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + nextRow + col);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else if (current == next) {
//两个格子一样,就合并格子
cells[row][col] = next + current;
cells[nextRow][col] = 0;
score += cells[row][col];
row--;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + nextRow + col);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else {
//下个不一样,就忽略之
row--;
}
}
}
function leftAction() {
if (state == CELL_MOVEING) {
return false;
}
if (!canMoveLeft()) {
return false;
}
//每次处理一个行
for (var row = 0; row < 4; row++) {
//每一个行中 从放方向判断是否需要移动处理
moveLeft(row);
}
return true;
}
// 处理一个列的移动
function moveLeft(row) {
//一个列中,按照方方向检查是否需要合并处理。
for (var col = 0; col < 4;) {
var current = cells[row][col];
var nextCol = getNextInRow(row, col + 1, 1);
//没有下一个,就直接结束了
if (nextCol == -1) {
return;
}
var next = cells[row][nextCol];
//console.log("next:"+next);
//console.log("current:"+current);
if (current == 0) {
//下一个格子移动到当前位置。
cells[row][col] = next;
cells[row][nextCol] = 0;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + row + nextCol);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else if (current == next) {
//两个格子一样,就合并格子
cells[row][col] = next + current;
cells[row][nextCol] = 0;
score += cells[row][col];
col++;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + row + nextCol);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else {
//下个不一样,就忽略之
col++;
}
}
}
function rightAction() {
if (state == CELL_MOVEING) {
return false;
}
if (!canMoveRight()) {
return false;
}
//每次处理一个行
for (var row = 0; row < 4; row++) {
//每一个行中 从放方向判断是否需要移动处理
moveRight(row);
}
return true;
}
// 处理一个列的移动
function moveRight(row) {
//一个列中,按照方方向检查是否需要合并处理。
for (var col = 3; col >= 0;) {
var current = cells[row][col];
var nextCol = getNextInRow(row, col - 1, -1);
//没有下一个,就直接结束了
if (nextCol == -1) {
return;
}
var next = cells[row][nextCol];
//console.log("next:"+next);
//console.log("current:"+current);
if (current == 0) {
//下一个格子移动到当前位置。
cells[row][col] = next;
cells[row][nextCol] = 0;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + row + nextCol);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else if (current == next) {
//两个格子一样,就合并格子
cells[row][col] = next + current;
cells[row][nextCol] = 0;
score += cells[row][col];
col--;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + row + nextCol);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else {
//下个不一样,就忽略之
col--;
}
}
}
function canMoveUp() {
for (var col = 0; col < 4; col++) {
for (var row = 1; row < 4; row++) {
//格子上方是空位置, 可以移动
if (cells[row][col] != 0 && cells[row - 1][col] == 0) {
return true;
}
//格子上方相邻的相等,可以移动
if (cells[row][col] != 0 && (cells[row][col] == cells[row - 1][col])) {
return true;
}
}
}
return false;
}
function canMoveDown() {
for (var col = 0; col < 4; col++) {
for (var row = 0; row < 3; row++) {
//格子上方是空位置, 可以移动
if (cells[row][col] != 0 && cells[row + 1][col] == 0) {
return true;
}
//格子上方相邻的相等,可以移动
if (cells[row][col] != 0 && (cells[row][col] == cells[row + 1][col])) {
return true;
}
}
}
return false;
}
function canMoveLeft() {
for (var col = 1; col < 4; col++) {
for (var row = 0; row < 4; row++) {
//格子上方是空位置, 可以移动
if (cells[row][col] != 0 && cells[row][col - 1] == 0) {
return true;
}
//格子上方相邻的相等,可以移动
if (cells[row][col] != 0 && (cells[row][col] == cells[row][col - 1])) {
return true;
}
}
}
return false;
}
function canMoveRight() {
for (var col = 0; col < 3; col++) {
for (var row = 0; row < 4; row++) {
//格子上方是空位置, 可以移动
if (cells[row][col] != 0 && cells[row][col + 1] == 0) {
return true;
}
//格子上方相邻的相等,可以移动
if (cells[row][col] != 0 && (cells[row][col] == cells[row][col + 1])) {
return true;
}
}
}
return false;
}
function test() {
rightAction();
state = CELL_MOVEING;
animation.start(function() {
//console.log("update");
randomNumber();
updateView();
state = PLAYING;
});
}
//更新显示,将表格中的数据,更新到界面显示
function updateView() {
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
var n = cells[row][col];
var cell = $("cell" + row + col);
//清楚显示的数据和显示样式
cell.className = "cell";
cell.innerHTML = "";
if (n > 0) {
//更新显示样式
cell.className = "cell num" + n;
//更新显示的数字
cell.innerHTML = n;
}
}
}
$("score").innerHTML = score;
$("finalScore").innerHTML = score;
}
//检查当前的表格中是否是满的,如果满了返回true,否则返回false
function full() {
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
if (cells[row][col] == 0) {
return false;
}
}
}
return true;
}
//向表格随机插入一个数字,如果插入成功返回true,插入失败返回false
function randomNumber() {
if (full()) {
return false;
}
while (true) {
var col = parseInt(Math.random() * 4);
var row = parseInt(Math.random() * 4);
if (cells[row][col] == 0) {
var n = Math.random() < 0.5 ? 2 : 4;
cells[row][col] = n;
return true;
}
}
}
function startAction() {
$("gameOver").style.display = "none";
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
cells[row][col] = 0;
}
}
score = 0;
randomNumber();
randomNumber();
updateView();
state = PLAYING;
}
//元素查询方法
function $(id) {
return document.getElementById(id);
}
function has8192() {
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
if (cells[row][col] == 8192) {
return true;
}
}
}
}
function hasSpace() {
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
if (cells[row][col] == 0) {
return true;
}
}
}
}
/* 显示游戏结束界面 */
function gameOver() {
//发现8192游戏结束
if (has8192()) {
state = GAME_OVER;
$("gameOver").style.display = "block";
return true;
}
//发现空位置,游戏不结束
if (hasSpace()) {
return false;
}
//能够移动游戏不结束
if (canMoveUp() || canMoveDown() || canMoveLeft() || canMoveRight()) {
return false;
}
state = GAME_OVER;
$("gameOver").style.display = "block";
return true;
}
//软件启动初始代码
window.onload = function() {
$("newGame").onclick = function() {
if (state == PLAYING)
startAction();
}
$("restart").onclick = function() {
if (state == GAME_OVER)
startAction();
}
startAction();
//监听键盘事件
document.onkeydown = function(event) {
if (state != PLAYING) {
return;
}
var move = false;
switch (event.keyCode) {
case 37: //left
move = leftAction();
break;
case 38: //up
move = upAction();
break;
case 39: //right
move = rightAction();
break;
case 40: //down
move = downAction();
break;
}
if (!move) {
return;
}
if (effect) {
state = CELL_MOVEING;
animation.start(function() {
//console.log("update");
updateView();
state = PLAYING;
if (!gameOver()) {
setTimeout(function() {
randomNumber();
updateView();
}, 100);
}
});
} else {
if (!gameOver()) {
setTimeout(function() {
randomNumber();
updateView();
}, 100);
}
updateView();
state = PLAYING;
}
gameOver();
}; // 5211 0842 8479 快捷快递
}
</script>
六、测试和运行
七、懒人版全部源码
很多同学喜欢html 和 css 和 js都放在同一个文件中,我给大家也做了一个懒人版的2048,以下提供源码:
2048.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>2048-懒人版</title>
<!-- 2048.css -->
<style type="text/css">
* {
padding: 0;
margin: 0;
}
div,
p,
h1,
h2,
a,
span {
font-family: Arial;
font-weight: bold;
}
header {
padding-top: 16px;
}
h1 {
font-size: 40px;
font-weight: bold;
text-align: center;
}
#gamePanel {
margin: 0 auto;
width: 500px;
position: relative;
}
#gridPanel {
width: 480px;
height: 480px;
background: #BBADA0;
border-radius: 10px;
padding: 20px 0 0 20px;
position: relative;
}
#gamePanel p {
padding: 8px;
}
/* 按钮样式 */
.button {
display: inline-block;
padding: 10px;
background: #9F8B77;
border-radius: 6px;
color: #FFF;
cursor: pointer;
}
.grid,
.cell {
width: 100px;
height: 100px;
border-radius: 6px;
}
/* 背景网格 */
#gamePanel .grid {
background-color: #ccc0b3;
float: left;
margin: 0 20px 20px 0;
}
/* 格式化前景单元格中位置 */
.cell {
position: absolute;
line-height: 100px;
vertical-align: middle;
text-align: center;
font-size: 60px;
color: #776E65;
}
/* 前景格中的行位置 */
#cell00,
#cell01,
#cell02,
#cell03 {
top: 20;
}
#cell10,
#cell11,
#cell12,
#cell13 {
top: 140px;
}
#cell20,
#cell21,
#cell22,
#cell23 {
top: 260px;
}
#cell30,
#cell31,
#cell32,
#cell33 {
top: 380px;
}
/* 前景格中的列位置 */
#cell00,
#cell10,
#cell20,
#cell30 {
left: 20px;
}
#cell01,
#cell11,
#cell21,
#cell31 {
left: 140px;
}
#cell02,
#cell12,
#cell22,
#cell32 {
left: 260px;
}
#cell03,
#cell13,
#cell23,
#cell33 {
left: 380px;
}
/* 数字显示效果 */
.num8,
.num16,
.num32,
.num64,
.num128,
.num256,
.num512,
.num1024,
.num2048,
.num4096,
.num8192 {
color: #fff;
}
.num1024,
.num2048,
.num4096,
.num8192 {
font-size: 40px;
}
.num2 {
background: #eee4da;
}
.num4 {
background: #ede0c8;
}
.num8 {
background: #f2b179;
}
.num16 {
background: #f59563;
}
.num32 {
background: #f67c5f;
}
.num64 {
background: #f65e3b;
}
.num128 {
background: #edcf72;
}
.num256 {
background: #edcc61;
}
.num512 {
background: #9c0;
}
.num1024 {
background: #33b5e5;
}
.num2048 {
background: #09c;
}
.num4096 {
background: #a6c;
}
.num8192 {
background: #93c;
}
/* 格式化Game Over的样式 */
#gameOver {
display: none;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
#gameOver div {
width: 100%;
height: 100%;
background: #555;
filter: alpha(Opacity=50);
-moz-opacity: 0.5;
opacity: 0.5;
}
#gameOver p {
position: absolute;
top: 150px;
left: 100px;
border-radius: 10px;
width: 300px;
border: 1px solid #EDCF72;
background: #fff;
line-height: 1.6em;
font-size: 30px;
color: #000;
text-align: center;
}
.writer {
width: 80px;
margin-left: 30%;
}
</style>
<script type="text/javascript">
//game 封装了2048的数据和核心算法
var cells = [
[2, 0, 0, 0],
[0, 32, 0, 0],
[0, 4, 0, 0],
[0, 0, 2048, 0]
];
//游戏进行中
var PLAYING = 0;
//方块正在移动动画处理中,期间不能响应键盘事件
var CELL_MOVEING = 1;
//游戏结束了,结束了就不能响应键盘事件了
var GAME_OVER = 2;
var score = 0;
//当前游戏状态
var state = PLAYING;
//动态效果开关,打开后可以绘制方块的移动动画效果
var effect = true;
/* 向上的动作, */
function upAction() {
if (state == CELL_MOVEING) {
return false;
}
if (!canMoveUp()) {
return false;
}
//每次处理一个列
for (var col = 0; col < 4; col++) {
//每一个列中 从放方向判断是否需要移动处理
upCol(col);
}
return true;
}
// 处理一个列的移动
function upCol(col) {
//一个列中,按照方方向检查是否需要合并处理。
for (var row = 0; row < 4;) {
var current = cells[row][col];
var nextRow = getNextInCol(col, row + 1, 1);
//没有下一个,就直接结束了
if (nextRow == -1) {
return;
}
var next = cells[nextRow][col];
if (current == 0) {
//下一个格子移动到当前位置。
cells[row][col] = next;
cells[nextRow][col] = 0;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + nextRow + col);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else if (current == next) {
//两个格子一样,就合并格子
cells[row][col] = next + current;
cells[nextRow][col] = 0;
score += cells[row][col];
row++;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + nextRow + col);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else {
//下个不一样,就忽略之
row++;
}
}
}
function getNextInCol(col, startRow, step) {
var row = startRow;
while (true) {
if (row < 0 || row >= 4) {
return -1;
}
if (cells[row][col] != 0) {
return row;
}
row += step;
}
}
function getNextInRow(row, startCol, step) {
var col = startCol;
while (true) {
if (col < 0 || col >= 4) {
return -1;
}
if (cells[row][col] != 0) {
return col;
}
col += step;
}
}
function downAction() {
if (state == CELL_MOVEING) {
return false;
}
if (!canMoveDown()) {
return false;
}
//每次处理一个列
for (var col = 0; col < 4; col++) {
//每一个列中 从放方向判断是否需要移动处理
downCol(col);
}
return true;
}
// 处理一个列的移动
function downCol(col) {
//一个列中,按照方方向检查是否需要合并处理。
for (var row = 3; row >= 0;) {
var current = cells[row][col];
var nextRow = getNextInCol(col, row - 1, -1);
//没有下一个,就直接结束了
if (nextRow == -1) {
return;
}
var next = cells[nextRow][col];
if (current == 0) {
//下一个格子移动到当前位置。
cells[row][col] = next;
cells[nextRow][col] = 0;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + nextRow + col);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else if (current == next) {
//两个格子一样,就合并格子
cells[row][col] = next + current;
cells[nextRow][col] = 0;
score += cells[row][col];
row--;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + nextRow + col);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else {
//下个不一样,就忽略之
row--;
}
}
}
function leftAction() {
if (state == CELL_MOVEING) {
return false;
}
if (!canMoveLeft()) {
return false;
}
//每次处理一个行
for (var row = 0; row < 4; row++) {
//每一个行中 从放方向判断是否需要移动处理
moveLeft(row);
}
return true;
}
// 处理一个列的移动
function moveLeft(row) {
//一个列中,按照方方向检查是否需要合并处理。
for (var col = 0; col < 4;) {
var current = cells[row][col];
var nextCol = getNextInRow(row, col + 1, 1);
//没有下一个,就直接结束了
if (nextCol == -1) {
return;
}
var next = cells[row][nextCol];
//console.log("next:"+next);
//console.log("current:"+current);
if (current == 0) {
//下一个格子移动到当前位置。
cells[row][col] = next;
cells[row][nextCol] = 0;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + row + nextCol);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else if (current == next) {
//两个格子一样,就合并格子
cells[row][col] = next + current;
cells[row][nextCol] = 0;
score += cells[row][col];
col++;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + row + nextCol);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else {
//下个不一样,就忽略之
col++;
}
}
}
function rightAction() {
if (state == CELL_MOVEING) {
return false;
}
if (!canMoveRight()) {
return false;
}
//每次处理一个行
for (var row = 0; row < 4; row++) {
//每一个行中 从放方向判断是否需要移动处理
moveRight(row);
}
return true;
}
// 处理一个列的移动
function moveRight(row) {
//一个列中,按照方方向检查是否需要合并处理。
for (var col = 3; col >= 0;) {
var current = cells[row][col];
var nextCol = getNextInRow(row, col - 1, -1);
//没有下一个,就直接结束了
if (nextCol == -1) {
return;
}
var next = cells[row][nextCol];
//console.log("next:"+next);
//console.log("current:"+current);
if (current == 0) {
//下一个格子移动到当前位置。
cells[row][col] = next;
cells[row][nextCol] = 0;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + row + nextCol);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else if (current == next) {
//两个格子一样,就合并格子
cells[row][col] = next + current;
cells[row][nextCol] = 0;
score += cells[row][col];
col--;
if (effect) { //如果动效开关打开,就处理动画
// $("cell"+nextRow+col) 找到下一个对象对应的格子
var obj = $("cell" + row + nextCol);
var top = row * 120 + 20;
var left = col * 120 + 20;
animation.add(obj, top, left);
}
} else {
//下个不一样,就忽略之
col--;
}
}
}
function canMoveUp() {
for (var col = 0; col < 4; col++) {
for (var row = 1; row < 4; row++) {
//格子上方是空位置, 可以移动
if (cells[row][col] != 0 && cells[row - 1][col] == 0) {
return true;
}
//格子上方相邻的相等,可以移动
if (cells[row][col] != 0 && (cells[row][col] == cells[row - 1][col])) {
return true;
}
}
}
return false;
}
function canMoveDown() {
for (var col = 0; col < 4; col++) {
for (var row = 0; row < 3; row++) {
//格子上方是空位置, 可以移动
if (cells[row][col] != 0 && cells[row + 1][col] == 0) {
return true;
}
//格子上方相邻的相等,可以移动
if (cells[row][col] != 0 && (cells[row][col] == cells[row + 1][col])) {
return true;
}
}
}
return false;
}
function canMoveLeft() {
for (var col = 1; col < 4; col++) {
for (var row = 0; row < 4; row++) {
//格子上方是空位置, 可以移动
if (cells[row][col] != 0 && cells[row][col - 1] == 0) {
return true;
}
//格子上方相邻的相等,可以移动
if (cells[row][col] != 0 && (cells[row][col] == cells[row][col - 1])) {
return true;
}
}
}
return false;
}
function canMoveRight() {
for (var col = 0; col < 3; col++) {
for (var row = 0; row < 4; row++) {
//格子上方是空位置, 可以移动
if (cells[row][col] != 0 && cells[row][col + 1] == 0) {
return true;
}
//格子上方相邻的相等,可以移动
if (cells[row][col] != 0 && (cells[row][col] == cells[row][col + 1])) {
return true;
}
}
}
return false;
}
function test() {
rightAction();
state = CELL_MOVEING;
animation.start(function() {
//console.log("update");
randomNumber();
updateView();
state = PLAYING;
});
}
//更新显示,将表格中的数据,更新到界面显示
function updateView() {
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
var n = cells[row][col];
var cell = $("cell" + row + col);
//清楚显示的数据和显示样式
cell.className = "cell";
cell.innerHTML = "";
if (n > 0) {
//更新显示样式
cell.className = "cell num" + n;
//更新显示的数字
cell.innerHTML = n;
}
}
}
$("score").innerHTML = score;
$("finalScore").innerHTML = score;
}
//检查当前的表格中是否是满的,如果满了返回true,否则返回false
function full() {
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
if (cells[row][col] == 0) {
return false;
}
}
}
return true;
}
//向表格随机插入一个数字,如果插入成功返回true,插入失败返回false
function randomNumber() {
if (full()) {
return false;
}
while (true) {
var col = parseInt(Math.random() * 4);
var row = parseInt(Math.random() * 4);
if (cells[row][col] == 0) {
var n = Math.random() < 0.5 ? 2 : 4;
cells[row][col] = n;
return true;
}
}
}
function startAction() {
$("gameOver").style.display = "none";
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
cells[row][col] = 0;
}
}
score = 0;
randomNumber();
randomNumber();
updateView();
state = PLAYING;
}
//元素查询方法
function $(id) {
return document.getElementById(id);
}
function has8192() {
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
if (cells[row][col] == 8192) {
return true;
}
}
}
}
function hasSpace() {
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
if (cells[row][col] == 0) {
return true;
}
}
}
}
/* 显示游戏结束界面 */
function gameOver() {
//发现8192游戏结束
if (has8192()) {
state = GAME_OVER;
$("gameOver").style.display = "block";
return true;
}
//发现空位置,游戏不结束
if (hasSpace()) {
return false;
}
//能够移动游戏不结束
if (canMoveUp() || canMoveDown() || canMoveLeft() || canMoveRight()) {
return false;
}
state = GAME_OVER;
$("gameOver").style.display = "block";
return true;
}
//软件启动初始代码
window.onload = function() {
$("newGame").onclick = function() {
if (state == PLAYING)
startAction();
}
$("restart").onclick = function() {
if (state == GAME_OVER)
startAction();
}
startAction();
//监听键盘事件
document.onkeydown = function(event) {
if (state != PLAYING) {
return;
}
var move = false;
switch (event.keyCode) {
case 37: //left
move = leftAction();
break;
case 38: //up
move = upAction();
break;
case 39: //right
move = rightAction();
break;
case 40: //down
move = downAction();
break;
}
if (!move) {
return;
}
if (effect) {
state = CELL_MOVEING;
animation.start(function() {
//console.log("update");
updateView();
state = PLAYING;
if (!gameOver()) {
setTimeout(function() {
randomNumber();
updateView();
}, 100);
}
});
} else {
if (!gameOver()) {
setTimeout(function() {
randomNumber();
updateView();
}, 100);
}
updateView();
state = PLAYING;
}
gameOver();
}; // 5211 0842 8479 快捷快递
}
// animation.js的部分
var animation = {
tasks: [], //动画任务数据
timer: null, //动画定时器
times: 10, //定时器次数
interval: 1000 / 60, //定时器间隔
add: function(obj, top, left) {
//动画已经开始了,不能添加任务了!
if (this.timer) {
return false;
}
if (!obj) {
return false;
}
//计算移动步伐
var t = (top - obj.offsetTop) / this.times;
var l = (left - obj.offsetLeft) / this.times;
//添加动画任务,其中obj是被移动到对象,top, left是移动以后的位置
var task = {
topStep: t,
leftStep: l,
element: obj,
step: function() {
var t = this.element.offsetTop;
this.element.style.top = (t + this.topStep) + "px";
var l = this.element.offsetLeft;
this.element.style.left = (l + this.leftStep) + "px";
},
clear: function() {
this.element.style.top = "";
this.element.style.left = "";
}
};
this.tasks[this.tasks.length] = task;
return true;
},
start: function(callback) {
//如果定时器已经启动,就不能再启动定时器了
if (this.timer) {
return false;
}
console.log("STATRING");
if (this.tasks.length == 0) {
if (callback) {
callback();
}
return false;
}
//如果有callback就交给this.callback
if (callback) {
this.callback = callback;
}
this.timer = setInterval(function() {
//console.log("timeOut");
//console.log(animation.times);
for (var i = 0; i < animation.tasks.length; i++) {
var task = animation.tasks[i];
task.step();
}
animation.times--;
if (animation.times < 0) {
animation.stop();
}
}, this.interval);
return true;
},
stop: function() {
if (this.timer) {
window.clearInterval(this.timer);
this.timer = null;
this.times = 10;
}
//结束以后执行callback()
if (this.callback) {
this.callback();
}
for (var i = 0; i < this.tasks.length; i++) {
var task = this.tasks[i];
task.clear();
}
this.tasks = []; //清空动画任务
},
callback: null //动画结束时候执行的方法
};
</script>
</head>
<body>
<header>
<h1>2048</h1>
</header>
<div id="gamePanel">
<p><a class="button" id="newGame">New Game</a> Score: <span id="score">0</span><span class="writer">小灰灰版</span></p>
<div id="gridPanel">
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="grid"> </div>
<div class="cell " id="cell00"> </div>
<div class="cell " id="cell01"> </div>
<div class="cell " id="cell02"> </div>
<div class="cell " id="cell03"> </div>
<div class="cell " id="cell10"> </div>
<div class="cell " id="cell11"> </div>
<div class="cell " id="cell12"> </div>
<div class="cell " id="cell13"> </div>
<div class="cell " id="cell20"> </div>
<div class="cell " id="cell21"> </div>
<div class="cell " id="cell22"> </div>
<div class="cell " id="cell23"> </div>
<div class="cell " id="cell30"> </div>
<div class="cell " id="cell31"> </div>
<div class="cell " id="cell32"> </div>
<div class="cell " id="cell33"> </div>
</div>
<div id="gameOver">
<div>
<!--背景 -->
</div>
<p>
<!-- 前景 -->
Game Over!<br>
Score: <span id="finalScore">0</span><br>
<a class="button" id="restart">Try Again!</a>
</p>
</div>
</div>
</body>
</html>