js部分,核心
$(function () {//windows.onload方法
//是否产生新元素
var isNewRndItem = false;
var gameScore = 0;
//最高分
var maxScore = 0;
if (localStorage.maxScore) {
//在HTML5中,新加入了一个localStorage特性,这个特性主要是用来作为本地存储来使用的,解决了cookie存储空间不足的问题(cookie中每条cookie的存储空间为4k),localStorage中一般浏览器支持的是5M大小,这个在不同的浏览器中localStorage会有所不同。
maxScore = localStorage.maxScore - 0;
} else {
maxScore = 0;
}//历史最高分的设置
//游戏初始化
gameInit();
function refreshGame() {
var items = $('.gameBody .row .item');//所有游戏块(.item)
for (var i = 0; i < items.length; i++) {
items.eq(i).html('').removeClass('nonEmptyItem').addClass('emptyItem');
//.html->innerHTML方法
//.classList.add("类名") 是源生的添加类方法
//.classList.remove("类名") 是源生的删除类方法
}
gameScore = 0;
//分数清零
$('#gameScore').html(gameScore);
//随机生成两个新元素
newRndItem();//函数方法,之后有详细解释(封装的好处)
newRndItem();
//刷新颜色
refreshColor();
$('#gameOverModal').modal('hide');
//BootStrap框架内方法,打开一个浮层,承载相应的操作(弹出对话框)
}
/*
函数详解:功能函数,是用于每次操作后刷新,创建新块
*/
function getSideItem(currentItem, direction) {
//当前元素的位置
var currentItemX = currentItem.attr('x') - 0;//改变数据格式的简单方法!(S->N)不一定用Number()
var currentItemY = currentItem.attr('y') - 0;
//.attr的用途1-改变html元素内属性的值(x)
//2-获取html源生OR自定义属性的值(这里采用的是这种方法)
//根据方向获取旁边元素的位置
switch (direction) {
case 'left':
var sideItemX = currentItemX;
var sideItemY = currentItemY - 1;
break;
case 'right':
var sideItemX = currentItemX;
var sideItemY = currentItemY + 1;
break;
case 'up':
var sideItemX = currentItemX - 1;
var sideItemY = currentItemY;
break;
case 'down':
var sideItemX = currentItemX + 1;
var sideItemY = currentItemY;
break;
}
//旁边元素
//实际意思是要去的地方的元素,通过与其进行判断来判断是否能进行移动
var sideItem = $('.gameBody .row .x' + sideItemX + 'y' + sideItemY);
return sideItem;
//返回值是什么?(目前未知)
//返回了要去的位置的元素DOM对象
}
/*
函数详解:传入2个参数,请注意!一个用于获得方块的位置,other用于判断方向
*/
function itemMove(currentItem, direction) {
var sideItem = getSideItem(currentItem, direction);
if (sideItem.length == 0) {//当前元素在最边上
//不动
//length 属性可返回下拉列表中选项的数目。HTML-DOM操作函数(这个不精确)
//JQ中 - length 属性包含 jQuery 对象中元素的数目。
//在此题目中,如果没有相关元素,即不存在移动后x=-1 OR y=-1的元素,就是边上元素,不动
} else if (sideItem.html() == '') { //当前元素不在最后一个且左(右、上、下)侧元素是空元素
//首先判断不是最边,而且要移动去的元素位置是空 ''
sideItem.html(currentItem.html()).removeClass('emptyItem').addClass('nonEmptyItem');
//sideItem.html(currentItem.html())这段代码是把currentItem.html()<currentItem里面的内容赋值给sideItem.html> ,之后配合迭代,使得数字移动!
currentItem.html('').removeClass('nonEmptyItem').addClass('emptyItem');
itemMove(sideItem, direction);//迭代,一直移动
isNewRndItem = true;//判断是否创建新初始块
} else if (sideItem.html() != currentItem.html()) {//左(右、上、下)侧元素和当前元素内容不同
//不动
} else {//左(右、上、下)侧元素和当前元素内容相同
//向右合并
sideItem.html((sideItem.html() - 0) * 2);//sideItem.html()为String数据类型,-0使其快速转换为Number类型
currentItem.html('').removeClass('nonEmptyItem').addClass('emptyItem');
gameScore += (sideItem.text() - 0) * 10;
$('#gameScore').html(gameScore);
// itemMove(sideItem, direction);
maxScore = maxScore < gameScore ? gameScore : maxScore;//三元判断
$('#maxScore').html(maxScore);
localStorage.maxScore = maxScore;
isNewRndItem = true;//创建新块的条件
return;
//只有在这里return,这是why?是因为在游戏过程中'推'一次,即'合并'一次以后就会结束这一轮迭代
//如果return后面没有值,则返回的结果(函数返回值)为undefined
}
}
function move(direction) {
//获取所有非空元素(一个数组)
var nonEmptyItems = $('.gameBody .row .nonEmptyItem');
//如果按下的方向是左或上,则正向遍历非空元素
if (direction == 'left' || direction == 'up') {
for (var i = 0; i < nonEmptyItems.length; i++) {
var currentItem = nonEmptyItems.eq(i);
//:eq() 选择器选取带有指定 index 值的元素。index 值从 0 开始,所有第一个元素的 index 值是 0(不是 1)。
//currentItem.html为啥出现的原因找到了@平安JavaScript
//移动每一个非空数块,迭代循环《正向》
itemMove(currentItem, direction);
}
} else if (direction == 'right' || direction == 'down') {//如果按下的方向是右或下,则反向遍历非空元素
for (var i = nonEmptyItems.length - 1; i >= 0; i--) {
var currentItem = nonEmptyItems.eq(i);
itemMove(currentItem, direction);
}
}
//是否产生新元素
if (isNewRndItem) {
newRndItem();
refreshColor();
}
}
function isGameOver() {
//获取所有元素
var items = $('.gameBody .row .item');
//获取所有非空元素
var nonEmptyItems = $('.gameBody .row .nonEmptyItem');
if (items.length == nonEmptyItems.length) {//所有元素的个数 == 所有非空元素的个数 即没有空元素
//遍历所有非空元素
for (var i = 0; i < nonEmptyItems.length; i++) {
var currentItem = nonEmptyItems.eq(i);
if (getSideItem(currentItem, 'up').length != 0 && currentItem.html() == getSideItem(currentItem, 'up').html()) {
//上边元素存在 且 当前元素中的内容等于上边元素中的内容
return;
} else if (getSideItem(currentItem, 'down').length != 0 && currentItem.html() == getSideItem(currentItem, 'down').html()) {
//下边元素存在 且 当前元素中的内容等于下边元素中的内容
return;
} else if (getSideItem(currentItem, 'left').length != 0 && currentItem.html() == getSideItem(currentItem, 'left').html()) {
//左边元素存在 且 当前元素中的内容等于左边元素中的内容
return;
} else if (getSideItem(currentItem, 'right').length != 0 && currentItem.html() == getSideItem(currentItem, 'right').html()) {
//右边元素存在 且 当前元素中的内容等于右边元素中的内容
return;
}
}
} else {
return;
}
$('#gameOverModal').modal('show');
}
//游戏初始化
function gameInit() {
//初始化分数
$('#gameScore').html(gameScore);
//最大分值
$('#maxScore').html(maxScore);
//为刷新按钮绑定事件
$('.refreshBtn').click(refreshGame);
//随机生成两个新元素
newRndItem();
newRndItem();
//刷新颜色
refreshColor();
}
//随机生成新元素
function newRndItem() {
//随机生成新数字
var newRndArr = [2, 2, 4];
var newRndNum = newRndArr[getRandom(0, 2)];
console.log('newRndNum: ' + newRndNum);
//随机生成新数字的位置
var emptyItems = $('.gameBody .row .emptyItem');
var newRndSite = getRandom(0, emptyItems.length - 1);
emptyItems.eq(newRndSite).html(newRndNum).removeClass('emptyItem').addClass('nonEmptyItem');
}
//产生随机数,包括min、max
function getRandom(min, max) {
return min + Math.floor(Math.random() * (max - min + 1));
}
//刷新颜色
function refreshColor() {
var items = $('.gameBody .item');
for (var i = 0; i < items.length; i++) {
// console.log(items.eq(i).parent().index());
switch (items.eq(i).html()) {
case '':
items.eq(i).css('background', '');
break;
case '2':
items.eq(i).css('background', 'rgb(250, 225, 188)');
break;
case '4':
items.eq(i).css('background', 'rgb(202, 240, 240)');
break;
case '8':
items.eq(i).css('background', 'rgb(117, 231, 193)');
break;
case '16':
items.eq(i).css('background', 'rgb(240, 132, 132)');
break;
case '32':
items.eq(i).css('background', 'rgb(181, 240, 181)');
break;
case '64':
items.eq(i).css('background', 'rgb(182, 210, 246)');
break;
case '128':
items.eq(i).css('background', 'rgb(255, 207, 126)');
break;
case '256':
items.eq(i).css('background', 'rgb(250, 216, 216)');
break;
case '512':
items.eq(i).css('background', 'rgb(124, 183, 231)');
break;
case '1024':
items.eq(i).css('background', 'rgb(225, 219, 215)');
break;
case '2048':
items.eq(i).css('background', 'rgb(221, 160, 221)');
break;
case '4096':
items.eq(i).css('background', 'rgb(250, 139, 176)');
break;
}
}
}
// 电脑的方向键监听事件
$('body').keydown(function (e) {
switch (e.keyCode) {
case 37:
// left
console.log('left');
isNewRndItem = false;
move('left');
isGameOver();
break;
case 38:
// up
console.log('up');
isNewRndItem = false;
move('up');
isGameOver();
break;
case 39:
// right
console.log('right');
isNewRndItem = false;
move('right');
isGameOver();
break;
case 40:
// down
console.log('down');
isNewRndItem = false;
move('down');
isGameOver();
break;
}
});
// 手机屏幕划动触发
(function () {
mobilwmtouch(document.getElementById("gameBody"))
document.getElementById("gameBody").addEventListener('touright', function (e) {
e.preventDefault();
// alert("方向向右");
console.log('right');
isNewRndItem = false;
move('right');
isGameOver();
});
document.getElementById("gameBody").addEventListener('touleft', function (e) {
// alert("方向向左");
console.log('left');
isNewRndItem = false;
move('left');
isGameOver();
});
document.getElementById("gameBody").addEventListener('toudown', function (e) {
// alert("方向向下");
console.log('down');
isNewRndItem = false;
move('down');
isGameOver();
});
document.getElementById("gameBody").addEventListener('touup', function (e) {
// alert("方向向上");
console.log('up');
isNewRndItem = false;
move('up');
isGameOver();
});
function mobilwmtouch(obj) {
var stoux, stouy;
var etoux, etouy;
var xdire, ydire;
obj.addEventListener("touchstart", function (e) {
stoux = e.targetTouches[0].clientX;
stouy = e.targetTouches[0].clientY;
//console.log(stoux);
}, false);
obj.addEventListener("touchend", function (e) {
etoux = e.changedTouches[0].clientX;
etouy = e.changedTouches[0].clientY;
xdire = etoux - stoux;
ydire = etouy - stouy;
chazhi = Math.abs(xdire) - Math.abs(ydire);
//console.log(ydire);
if (xdire > 0 && chazhi > 0) {
console.log("right");
//alert(evenzc('touright',alerts));
obj.dispatchEvent(evenzc('touright'));
} else if (ydire > 0 && chazhi < 0) {
console.log("down");
obj.dispatchEvent(evenzc('toudown'));
} else if (xdire < 0 && chazhi > 0) {
console.log("left");
obj.dispatchEvent(evenzc('touleft'));
} else if (ydire < 0 && chazhi < 0) {
console.log("up");
obj.dispatchEvent(evenzc('touup'));
}
}, false);
function evenzc(eve) {
if (typeof document.CustomEvent === 'function') {
this.event = new document.CustomEvent(eve, {//自定义事件名称
bubbles: false,//是否冒泡
cancelable: false//是否可以停止捕获
});
if (!document["evetself" + eve]) {
document["evetself" + eve] = this.event;
}
} else if (typeof document.createEvent === 'function') {
this.event = document.createEvent('HTMLEvents');
this.event.initEvent(eve, false, false);
if (!document["evetself" + eve]) {
document["evetself" + eve] = this.event;
}
} else {
return false;
}
return document["evetself" + eve];
}
}
})();
});
<!DOCTYPE html >
<html >
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>2048小游戏</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no">
<script src="https://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<link href="https://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="main.css"/>
<script type="text/javascript" src="main.js"></script>
</head>
<body>
<div class="container">
<div class="main">
<div class="gameName">2048小游戏</div>
<div class="maxScore">最高分:
<span id="maxScore">1345612</span>
</div>
<div class="col-sm-3 col-md-4"></div>
<div class="gameBody col-sm-6 col-md-4" id="gameBody">
<div class="row">
<div class="item emptyItem x0y0" x="0" y="0"></div>
<div class="item emptyItem x0y1" x="0" y="1"></div>
<div class="item emptyItem x0y2" x="0" y="2"></div>
<div class="item emptyItem x0y3" x="0" y="3"></div>
</div>
<div class="row">
<div class="item emptyItem x1y0" x="1" y="0"></div>
<div class="item emptyItem x1y1" x="1" y="1"></div>
<div class="item emptyItem x1y2" x="1" y="2"></div>
<div class="item emptyItem x1y3" x="1" y="3"></div>
</div>
<div class="row">
<div class="item emptyItem x2y0" x="2" y="0"></div>
<div class="item emptyItem x2y1" x="2" y="1"></div>
<div class="item emptyItem x2y2" x="2" y="2"></div>
<div class="item emptyItem x2y3" x="2" y="3"></div>
</div>
<div class="row">
<div class="item emptyItem x3y0" x="3" y="0"></div>
<div class="item emptyItem x3y1" x="3" y="1"></div>
<div class="item emptyItem x3y2" x="3" y="2"></div>
<div class="item emptyItem x3y3" x="3" y="3"></div>
</div>
</div>
<div class="gameRule col-sm-12 col-md-12">电脑:请用键盘的方向键进行操作</div>
<div class="gameRule col-sm-12 col-md-12">手机:请划动屏幕进行操作</div>
<div class="col-sm-4 col-md-4"></div>
<div class="scoreAndRefresh col-sm-6 col-md-6">
<div class="gameScore ">得分:<span id="gameScore">0</span> 分</div>
<button type="button" class="btn btn-danger refreshBtn">
<span class="">刷新</span>
</button>
</div>
<div class="modal fade" id="gameOverModal" aria-labelledby="myModalLabel" aria-hidden="true"
data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
×
</button>
<h4 class="modal-tittle" id="myModalLabel">2048小游戏</h4>
</div>
<div class="modal-body">
Game Over!
</div>
<div class="modal-footer">
<button type="button" class="btn btn-info" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-danger refreshBtn" onclick="refreshGame()">再玩一次</button>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>