2048小游戏
一、游戲簡介:
2048是一款休閑益智類的數(shù)字疊加小游戲
二、 游戲玩法:
在4*4的16宮格中,您可以選擇上、下、左、右四個(gè)方向進(jìn)行操作,數(shù)字會(huì)按方向移動(dòng),相鄰的兩個(gè)數(shù)字相同就會(huì)合并,組成更大的數(shù)字,每次移動(dòng)或合并后會(huì)增加一個(gè)數(shù)字。
當(dāng)16宮格中沒有空格子,且四個(gè)方向都無法操作時(shí),游戲結(jié)束。
三、 游戲目的:
目的是合并出2048這個(gè)數(shù)字,獲得更高的分?jǐn)?shù)。
四、 游戲截圖:
六、游戲?qū)崿F(xiàn)原理:
使用js、jQuery實(shí)現(xiàn)了PC版及手機(jī)版,實(shí)現(xiàn)原理是一樣的,只是移動(dòng)端的一些樣式和上、下、左、右滑動(dòng)的事件與PC端不一樣
1. 首先,把16宮格看成是矩陣的形式
2. 在html中給每個(gè)格子添加類名及屬性,來記錄每個(gè)格子的位置
類名item是每個(gè)格子的類名,emptyItem是空格子的類名,nonEmptyItem是非空格式的類名
3. 游戲開始時(shí),隨機(jī)生成兩個(gè)數(shù)字,2或者4,出現(xiàn)在矩陣中任意位置
這部分是通過類名emptyItem及nonEmptyItem來實(shí)現(xiàn)的。
①. 隨機(jī)生成一個(gè)數(shù)字2或者4
②. 獲取所有空元素(類名emptyItem)
③. 隨機(jī)選擇一個(gè)空元素 將這個(gè)數(shù)字填充到空元素中,并將類名emptyItem移除,添加類名nonEmptyItem,即非空元素
④. 重復(fù)①、②、③步,再隨機(jī)生成一個(gè)數(shù)字填充一到隨機(jī)的位置
4. 游戲的核心在于移動(dòng)
移動(dòng)有四個(gè)方向:上、下、左、右,實(shí)現(xiàn)思路如下:
向左移動(dòng)
移動(dòng)或合并
遍歷所有非空元素
如果當(dāng)前元素在第一個(gè)位置 則不動(dòng)
如果當(dāng)前元素不在每一個(gè)位置
當(dāng)前元素左側(cè)是空元素 向左移動(dòng)
當(dāng)前元素左側(cè)是非空元素
左側(cè)元素和當(dāng)前元素的內(nèi)容不同 不動(dòng)
左側(cè)元素和當(dāng)前元素的內(nèi)容相同 向左合并
是否產(chǎn)生新元素
所有非空元素中,有移動(dòng)的 產(chǎn)生新元素
所有非空元素中,有合并的 產(chǎn)生新元素
向右移動(dòng)
移動(dòng)或合并
遍歷所有非空元素
如果當(dāng)前元素在最后一個(gè)位置 則不動(dòng)
如果當(dāng)前元素不在最后一個(gè)位置
當(dāng)前元素右側(cè)是空元素 向右移動(dòng)
當(dāng)前元素右側(cè)是非空元素
右側(cè)元素和當(dāng)前元素的內(nèi)容不同 不動(dòng)
右側(cè)元素和當(dāng)前元素的內(nèi)容相同 向右合并
是否產(chǎn)生新元素
所有非空元素中,有移動(dòng)的 產(chǎn)生新元素
所有非空元素中,有合并的 產(chǎn)生新元素
向上移動(dòng)、向下移動(dòng) 。。。。思路同上
5. 判斷游戲是否結(jié)束:
獲取所有元素
獲取所有非空元素
如果所有元素的個(gè)數(shù) == 所有非空元素的個(gè)數(shù)
循環(huán)遍歷所有非空元素
上面元素存在 && 當(dāng)前元素的內(nèi)容 == 上面元素的內(nèi)容 return
下面元素存在 && 當(dāng)前元素的內(nèi)容 == 下面元素的內(nèi)容 return
左邊元素存在 && 當(dāng)前元素的內(nèi)容 == 左邊元素的內(nèi)容 return
右邊元素存在 && 當(dāng)前元素的內(nèi)容 == 右邊元素的內(nèi)容 return
所有元素,以上條件都不滿足 gameover
代碼實(shí)現(xiàn)_Pc端
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>2048小游戲</title>
<link rel="stylesheet" >
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script>
<script src="http://libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
<style type="text/css">
* {
margin: 0;
padding: 0;
font-family: "YouYuan";
}
body {
background: lavenderblush;
}
.container {
margin-top: 30px;
}
.main {
width: 1000px;
height: 100%;
margin: 0 auto;
overflow: hidden;
text-align: center;
}
.main .gameName {
font-size: 35px;
font-weight: bold;
}
.main .maxScore {
font-size: 20px;
}
.main .maxScore span {
color: red;
font-weight: bold;
}
.main .gameBody {
width: 400px;
height: 400px;
margin: 0 auto;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 15px;
background: #999;
border-radius: 8px;
}
.main .gameBody .row {
display: flex;
justify-content: space-between;
}
.main .gameBody .row .item {
width: 80px;
height: 80px;
border-radius: 10px;
background: #fff;
text-align: center;
line-height: 80px;
font-size: 30px;
font-weight: bold;
color: #666;
font-family: "microsoft yahei";
}
.main .gameRule {
font-size: 20px;
font-weight: bold;
margin-top: 15px;
}
.main .gameScore {
font-size: 20px;
font-weight: bold;
margin-top: 15px;
}
.main .gameScore span {
color: red;
font-size: 30px;
}
.main .scoreAndRefresh {
display: flex;
justify-content: space-around;
width: 280px;
margin: 0 auto;
}
.main .scoreAndRefresh .refreshBtn {
height: 30px; margin-top: 22px;
}
.modal {
margin-top: 7%;
}
.modal .modal-header h4 {
text-align: left;
font-weight: bold;
}
.modal .modal-dialog {
width: 300px;
margin: 0 auto;
}
.modal .modal-body {
font-size: 18px;
font-weight: bold;
color: red;
}
#resetMaxScore {
color: #fff;
height: 30px;
}
</style>
</head>
<body>
<div class="container">
<div class="main">
<!--《2048》一款益智休閑小游戲,聽說能拼出2048的全世界不超過3%!-->
<div class="gameName">2048小游戲</div>
<div class="maxScore">最高分:
<span id="maxScore">134567</span>
</div>
<div class="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">請按上、下、左、右鍵進(jìn)行操作</div>
<div class="scoreAndRefresh">
<div class="gameScore">得分:<span id="gameScore">0</span> 分</div>
<button type="button" class="btn btn-danger refreshBtn">
<span class="glyphicon glyphicon-repeat"></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">關(guān)閉</button>
<button type="button" class="btn btn-danger refreshBtn">再玩一次</button>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script type="text/javascript">
$(function(){
//是否產(chǎn)生新元素
var isNewRndItme = false;
var gameScore = 0;
//最高分
var maxScore = 0;
if(localStorage.maxScore) {
maxScore = localStorage.maxScore - 0;
}else {
maxScore = 0;
}
//游戲初始化
gameInit();
//上、下、左、右監(jiān)聽事件
$('body').keydown(function(e) {
switch (e.keyCode) {
case 37:
// left
console.log('left');
isNewRndItme = false;
move('left');
isGameOver();
break;
case 38:
// up
console.log('up');
isNewRndItme = false;
move('up');
isGameOver();
break;
case 39:
// right
console.log('right');
isNewRndItme = false;
move('right');
isGameOver();
break;
case 40:
// down
console.log('down');
isNewRndItme = false;
move('down');
isGameOver();
break;
}
});
function refreshGame(){
var items = $('.gameBody .row .item');
for(var i = 0; i < items.length; i++) {
items.eq(i).html('').removeClass('nonEmptyItem').addClass('emptyItem');
}
gameScore = 0;
//分?jǐn)?shù)清零
$('#gameScore').html(gameScore);
//隨機(jī)生成兩個(gè)新元素
newRndItem();
newRndItem();
//刷新顏色
refreshColor();
$('#gameOverModal').modal('hide');
}
function getSideItem(currentItem, direction) {
//當(dāng)前元素的位置
var currentItemX = currentItem.attr('x') - 0;
var currentItemY = currentItem.attr('y') - 0;
//根據(jù)方向獲取旁邊元素的位置
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;
}
function itemMove(currentItem, direction) {
var sideItem = getSideItem(currentItem, direction);
if(sideItem.length == 0) {//當(dāng)前元素在最邊上
//不動(dòng)
}else if(sideItem.html() == '') { //當(dāng)前元素不在最后一個(gè)且左(右、上、下)側(cè)元素是空元素
sideItem.html(currentItem.html()).removeClass('emptyItem').addClass('nonEmptyItem');
currentItem.html('').removeClass('nonEmptyItem').addClass('emptyItem');
itemMove(sideItem, direction);
isNewRndItme = true;
}else if(sideItem.html() != currentItem.html()) {//左(右、上、下)側(cè)元素和當(dāng)前元素內(nèi)容不同
//不動(dòng)
}else {//左(右、上、下)側(cè)元素和當(dāng)前元素內(nèi)容相同
//向右合并
sideItem.html((sideItem.html() - 0) * 2);
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;
isNewRndItme = true;
return;
}
}
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);
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);
}
}
//是否產(chǎn)生新元素
if(isNewRndItme) {
newRndItem();
refreshColor();
}
}
function isGameOver(){
//獲取所有元素
var items = $('.gameBody .row .item');
//獲取所有非空元素
var nonEmptyItems = $('.gameBody .row .nonEmptyItem');
if(items.length == nonEmptyItems.length) {//所有元素的個(gè)數(shù) == 所有非空元素的個(gè)數(shù) 即沒有空元素
//遍歷所有非空元素
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()) {
//上邊元素存在 且 當(dāng)前元素中的內(nèi)容等于上邊元素中的內(nèi)容
return;
}else if(getSideItem(currentItem, 'down').length != 0 && currentItem.html() == getSideItem(currentItem, 'down').html()) {
//下邊元素存在 且 當(dāng)前元素中的內(nèi)容等于下邊元素中的內(nèi)容
return;
}else if(getSideItem(currentItem, 'left').length != 0 && currentItem.html() == getSideItem(currentItem, 'left').html()) {
//左邊元素存在 且 當(dāng)前元素中的內(nèi)容等于左邊元素中的內(nèi)容
return;
}else if(getSideItem(currentItem, 'right').length != 0 && currentItem.html() == getSideItem(currentItem, 'right').html()) {
//右邊元素存在 且 當(dāng)前元素中的內(nèi)容等于右邊元素中的內(nèi)容
return;
}
}
}else {
return;
}
$('#gameOverModal').modal('show');
}
//游戲初始化
function gameInit(){
//初始化分?jǐn)?shù)
$('#gameScore').html(gameScore);
//最大分值
$('#maxScore').html(maxScore);
//為刷新按鈕綁定事件
$('.refreshBtn').click(refreshGame);
//隨機(jī)生成兩個(gè)新元素
newRndItem();
newRndItem();
//刷新顏色
refreshColor();
}
//隨機(jī)生成新元素
function newRndItem(){
//隨機(jī)生成新數(shù)字
var newRndArr = [2, 2, 4];
var newRndNum = newRndArr[getRandom(0, 2)];
console.log('newRndNum: ' + newRndNum);
//隨機(jī)生成新數(shù)字的位置
var emptyItems = $('.gameBody .row .emptyItem');
var newRndSite = getRandom(0, emptyItems.length - 1);
emptyItems.eq(newRndSite).html(newRndNum).removeClass('emptyItem').addClass('nonEmptyItem');
}
//產(chǎn)生隨機(jī)數(shù),包括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;
}
}
}
});
</script>
</html>
移動(dòng)端滑動(dòng)事件
PC端2048和手機(jī)端2048的不同之處就是一些樣式和上、下、左、右滑動(dòng)事件
移動(dòng)端的滑動(dòng)事件如下:
(function (){
mobilwmtouch(document.getElementById("gameBody"))
document.getElementById("gameBody").addEventListener('touright',function (e){
e.preventDefault();
alert("方向向右");
});
document.getElementById("gameBody").addEventListener('touleft',function (e){
alert("方向向左");
});
document.getElementById("gameBody").addEventListener('toudown',function (e){
alert("方向向下");
});
document.getElementById("gameBody").addEventListener('touup',function (e){
alert("方向向上");
});
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];
}
}
})()
總結(jié)
- 上一篇: QML之TextEdit
- 下一篇: 北京宣布将超前布局6G未来网络!加快建设