JS實現2408小游戲


一.游戲簡介

2048是一款休閑益智類的數字疊加小游戲,類似於歡樂消消消,很有意思的一個小游戲。

二.游戲玩法

在 4*4 的16宮格中,您可以選擇上、下、左、右四個方向進行操作,數字會按方向移動,相鄰的兩個數字相同就會合並,組成更大的數字,每次移動或合並后會自動增加一個數字。

當16宮格中沒有空格子,且四個方向都無法操作時,游戲結束。

三、游戲目的

目的是合並出 2048 這個數字,獲得更高的分數。

四.游戲截圖

 

五.游戲實現的原理

把16個格子看成4*4的二維數組

在HTML中給每個格子添加類名和屬性,來記錄每個格子的位置

采用三元表達式隨機生成0~1的小數,和0.5(可以設置游戲難度)比較,來給出2或4

最后再把數據更新到每個div中

判斷游戲結束:

每個格子上的數都不為零,上下左右的數都不相同的時候就判斷游戲結束

HTML設置整體的布局

 

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>2048小游戲</title>
<link rel="stylesheet" type="text/css" href="2048.css">
</head>
<body>
<div class="bag">
<h1>2048</h1>
<button onclick="game.start();">new game</button>
<div class="score">
<span>當前分數:</span>
<span id="scoreValue">0</span>
</div>
<div class="highScore">
<span>最高得分:</span>
<span id="highScoreValue">0</span>
</div>

<div class="box">
<!-- 第一行 -->
<div class="item" id= "c00"></div>
<div class="item" id= "c01"></div>
<div class="item" id= "c02"></div>
<div class="item" id= "c03"></div>
<!-- 第二行 -->
<div class="item" id= "c10"></div>
<div class="item" id= "c11"></div>
<div class="item" id= "c12"></div>
<div class="item" id= "c13"></div>
<!-- 第三行 -->
<div class="item" id= "c20"></div>
<div class="item" id= "c21"></div>
<div class="item" id= "c22"></div>
<div class="item" id= "c23"></div>
<!-- 第四行 -->
<div class="item" id= "c30"></div>
<div class="item" id= "c31"></div>
<div class="item" id= "c32"></div>
<div class="item" id= "c33"></div>
</div>
<header id="false_1">
<h1>GAME OVER</h1>
<p>SCORE:<span id="endScore">0</span></p>
<br>
<button onclick="game.start();">再玩一次</button>
</header>
</div>

<script type="text/javascript" src="2048.js"></script>
</body>
</html>

CSS界面設置div樣式

body{
background-color: #fff8dc;
}
.bag{
width: 600px;
height: 650px;
background-color: #ffe4e1;
border-radius: 20px;
margin: 0 auto;
position: relative;
}
.bag>h1{
position: absolute;
font-size: 70px;
color:#ff69b4;
left: 75px;
top: 30px;
}
.box{
width: 450px;
height: 450px;
border-radius: 10px;
background-color:#ffb6c1;
position: absolute;
top: 170px;
left: 75px;

}
header{
width: 450px;
height: 450px;
border-radius: 20px;
background-color:rgba(20,20,20,0.5);
z-index: -99;
position: absolute;
top: 170px;
left: 75px;
}
header>h1{
font-size: 50px;
text-align: center;
color: #ffb6c1;
}
header>button{
width: 200px;
height: 60px;
font-size: 30px;
color: #ff69b4;
border-radius: 6px;
border:none;
background-color:#ffb6c1;
margin-left: 125px;
}
header>p{
color: #ff69b4;
font-size: 30px;
font-weight: bold;
text-align: center;
}
.false{
z-index: 99;
}
.item{
width: 100px;
height: 100px;
border-radius: 8px;
background-color:#ff69b4;
float:left;
margin: 10px 0 0 10px;
font-size: 60px;
text-align: center;
line-height: 100px;
}
.bag>button{
width: 100px;
height: 40px;
font-size: 18px;
color: #ff69b4;
border-radius: 6px;
border:none;
background-color:#ffb6c1;
position: absolute;
right: 75px;
top: 110px;
}
.bag>.score{
width: 100px;
height: 60px;
background-color: #ffb6c1;
position: absolute;
border-radius: 6px;
left: 75px;
top:20px;
color: #ff69b4;
font-size: 18px;
text-align: center;
}
.score>span{
display: block;
}
.highScore{
width: 100px;
height: 60px;
background-color: #ffb6c1;
position: absolute;
border-radius: 6px;
right:75px;
top:20px;
color: #ff69b4;
font-size: 18px;
text-align: center;
}
.highScore>span{
display: block;
}
.n2{background-color:#eee3da}
.n4{background-color:#ede0c8}
.n8{background-color:#f2b179}
.n16{background-color:#f59563}
.n32{background-color:#f67c5f}
.n64{background-color:#f65e3b}
.n128{background-color:#edcf72}
.n256{background-color:#edcc61}
.n512{background-color:#9c0}
.n1024{background-color:#33b5e5}
.n2048{background-color:#09c}
.n4096{background-color:#a6c}
.n8192{background-color:#93c}
.n2,.n4{color:#776e65}
.n1024,.n2048,.n4096,.n8192{font-size:40px}

最后JS界面設計算法運算調用函數

var game = {
RN:4,CN:4,
data:null,//保存游戲的二維數組 //總行數,總列數
score:0, //分數初始值為0
highScore:0,//最高分初始值為0
start(){
//清零分數
this.score = 0;
//1.初始化data二維數組 每一個數據都初始化為
//新建空數組存儲到data
this.data = [];
//通過總行數和總列數,循環遍歷每個數。並且賦值為0
for(var r = 0;r<this.RN;r++){
//空數組中的r行
//新建一個空數組保存在data的r行中
this.data[r] = [];
for(var c = 0;c<this.CN;c++){
//空數組中r行c位置的數值 設置為0
this.data[r][c] = 0;
}
}
//2.隨機在二維數組中添加兩個數值,2或4
this.randomNum();
this.randomNum();
console.log(this.data.join('\n'));
//3.將data二維數組中的數據展示到頁面的div中去
this.updataView();
//4.觸發游戲
//當在鍵盤上按上,下,左,右觸發事件
document.onkeydown = function(e){
switch(e.keyCode){
case 37://左移
//this.moveleft(); 這里面的this關鍵字不在指向game,因此調用game的成員不能使用this關鍵字
game.moveLeft();
break;
case 39://右移
game.moveRight();
break;
case 38://上移
game.moveTop();
break;
case 40://下移
game.moveBottom();
break;
}
}
//清零游戲結束界面的樣式
document.getElementById("false_1").className = '';
},
updataView(){
//將data中的數據更新到div中
//遍歷二維數組data
//r從0開始,到RN結束
//c從0開始,到CN結束
for(var r = 0;r<this.RN;r++){
for(var c = 0;c<this.CN;c++){
//找到id為"c"+r+c的div元素
var div = document.getElementById("c"+r+c);
//獲取到data r行c列的數據 存儲變量n中
var n = this.data[r][c];
//判斷n是否為0
//如果是0
//div的內容設置為空,清除div的內容
if(n==0){
div.innerHTML = "";
//恢復div的class為 item
div.className = "item";//否則
}else{
//將div的值設置為n
div.innerHTML = n;
//將div的class設置為 item 'n'+n
div.className ="item n"+n;
}
}//c 的循環結束
//r 的循環結束
}
document.getElementById("scoreValue").innerHTML = this.score;
if(this.score>this.highScore){
this.highScore = this.score;
}
document.getElementById('highScoreValue').innerHTML = this.highScore;
},
randomNum(){
//在一個隨機位置生成2或4
//反復:
while(true){
// 在0~RN-1之間生成隨機數r
r = Math.floor(Math.random()*this.RN);
// 在0~CN-1之間生成隨機數c
c = Math.floor(Math.random()*this.CN);
// 根據data中r行c列的值來處理
// 如果data中r行c列的值為0
if(this.data[r][c] == 0){
// 將data中的r行c列賦值為:
// 2或者4的數字 隨機生成一個小數,如果<0.5,就取2,否則就取4
this.data[r][c] = Math.random()>0.6?2:4;
break;
}
// 退出循環
}
},
end(){
for(var r = 0;r<this.RN;r++){
for(var c=0;c<this.CN;c++){
if(this.data[r][c]==0){
return false;
}
}
}
for(var r=1;r<this.RN-1;r++){
for(var c=0;c<this.CN;c++){
if((this.data[r+1][c] == this.data[r][c])||(this.data[r-1][c]==this.data[r][c])){
return false;
}
}
}
for(var r=0;r<this.RN;r++){
for(var c=1;c<this.CN-1;c++){
if((this.data[r][c-1] == this.data[r][c])||(this.data[r][c+1] == this.data[r][c])){
return false;
}
}
}
return true;
},
isend(){
if(this.end()){
document.getElementById("false_1").className = 'false';
document.getElementById("endScore").innerHTML = this.score;
}
},
moveLeft(){
//左移所有行
//給數組拍照 var before = String(arr)
var before = String(this.data);
//r從0開始,到<RN結束
for(var r = 0;r<this.RN;r++){
this.moveLeftInRow(r);
}
//左移r行
//r循環結束
//移動結束以后,再給數組拍照 賦值給after
var after = String(this.data);
//如果data數組中的數據有變化 如果before != after
if(before != after){
//調用updateView更新頁面中數據
this.randomNum();
this.updataView();
this.isend();
}
},
moveLeftInRow(r){
//c從0開始,到<CN-1
////查找r行c列 下一個不為0的位置nextc
for(var c = 0;c<this.CN-1;c++){
for(var i = c+1;i<this.CN;i++){
// i從c+1開始,到<CN結束
// 當前i位置的值是否為0
if(this.data[r][i] != 0){
// 值不為0的位置 i賦值nextc
var nextc = i;
break;
}else{
// 否則
// 將nextc賦值為-1
nextc = -1;
}
}// i循環結束
// 如果nextc的值為-1,證明后面的都是0,直接退出
if (nextc == -1) {
break;
}else{// 否則
// 找r行c列位置的值,判斷是否為0
if(this.data[r][c] == 0) {// 如果是0 將nextc位置的值賦值給c位置
this.data[r][c] = this.data[r][nextc];
this.data[r][nextc] = 0;// 將nextc位置的值賦值為0
c--;// 將c留在原地
}else if(this.data[r][c] == this.data[r][nextc]){
// 否則 else if(c位置的值等於nextc位置的值)
this.data[r][c] *= 2;// 將c位置的值*2
this.score += this.data[r][c];
this.data[r][nextc] = 0;// 將nextc位置的值賦值為0
// c的循環結束
}
}
}
},
moveRight(){
//右移所有行
//給數組拍照 var before = String(arr)
var before = String(this.data);
//r從0開始,到<RN結束
for(var r = 0;r<this.RN;r++){
this.moveRightInRow(r);
}
//右移r行
//r循環結束
//移動結束以后,再給數組拍照 賦值給after
var after = String(this.data);
//如果data數組中的數據有變化 如果before != after
if(before != after){
//調用updateView更新頁面中數據
this.randomNum();
this.updataView();
this.isend();
}
},
moveRightInRow(r){
//c從cn-1開始,到0
////查找r行c列 上一個不為0的位置nextc
for(var c = this.CN-1;c>0;c--){
for(var i = c-1;i>=0;i--){
// i從c-1開始,到>-1結束
// 當前i位置的值是否為0
if(this.data[r][i] != 0){
// 值不為0的位置 i賦值nextc
var nextc = i;
break;
}else{
// 否則
// 將nextc賦值為-1
nextc = -1;
}
}// i循環結束
// 如果nextc的值為-1,證明后面的都是0,直接退出
if (nextc == -1){
break;
}else{// 否則
// 找r行c列位置的值,判斷是否為0
if(this.data[r][c] == 0) {// 如果是0 將nextc位置的值賦值給c位置
this.data[r][c] = this.data[r][nextc];
this.data[r][nextc] = 0;// 將nextc位置的值賦值為0
c++;// 將c留在原地
}else if(this.data[r][c] == this.data[r][nextc]){
// 否則 else if(c位置的值等於nextc位置的值)
this.data[r][c] *= 2;// 將c位置的值*2
this.score += this.data[r][c];
this.data[r][nextc] = 0;// 將nextc位置的值賦值為0
// c的循環結束
}
}
}
},
moveTop(){
//上移所有列
//給數組拍照 var before = String(arr)
var before = String(this.data);
//c從0開始,到<CN結束
for(var c = 0;c<this.CN;c++){
this.moveTopInRow(c);
}
//上移c列
//c循環結束
//移動結束以后,再給數組拍照 賦值給after
var after = String(this.data);
//如果data數組中的數據有變化 如果before != after
if(before != after){
//調用updateView更新頁面中數據
this.randomNum();
this.updataView();
this.isend();
}
},
moveTopInRow(c){
//r從0開始,到<CN-1
////查找r行c列 下一個不為0的位置nextr
for(var r = 0;r<this.RN-1;r++){
for(var i = r+1;i<this.RN;i++){
// i從r+1開始,到<RN結束
// 當前i位置的值是否為0
if(this.data[i][c] != 0){
// 值不為0的位置 i賦值nextr
var nextr = i;
break;
}else{
// 否則
// 將nextr賦值為-1
nextr = -1;
}
}// i循環結束
// 如果nextr的值為-1,證明后面的都是0,直接退出
if (nextr == -1) {
break;
}else{// 否則
// 找r行c列位置的值,判斷是否為0
if(this.data[r][c] == 0) {// 如果是0 將nextr位置的值賦值給r位置
this.data[r][c] = this.data[nextr][c];
this.data[nextr][c] = 0;// 將nextr位置的值賦值為0
r--;// 將r留在原地
}else if(this.data[r][c] == this.data[nextr][c]){
// 否則 else if(c位置的值等於nextc位置的值)
this.data[r][c] *= 2;// 將c位置的值*2
this.score += this.data[r][c];
this.data[nextr][c] = 0;// 將nextc位置的值賦值為0
// c的循環結束
}
}
}
},
moveBottom(){
//下移所有行
//給數組拍照 var before = String(arr)
var before = String(this.data);
//c從0開始,到<CN結束
for(var c = 0;c<this.CN;c++){
this.moveBottomInRow(c);
}
//下移c列
//c循環結束
//移動結束以后,再給數組拍照 賦值給after
var after = String(this.data);
//如果data數組中的數據有變化 如果before != after
if(before != after){
//調用updateView更新頁面中數據
this.randomNum();
this.updataView();
this.isend();
}
},
moveBottomInRow(c){
//c從CN-1開始,到>0
////查找r行c列 下一個不為0的位置nextr
for(var r = this.CN-1;r>0;r--){
for(var i = r-1;i>=0;i--){
// i從r-1開始,到>-1結束
// 當前i位置的值是否為0
if(this.data[i][c] != 0){
// 值不為0的位置 i賦值nextr
var nextr = i;
break;
}else{
// 否則
// 將nextr賦值為-1
nextr = -1;
}
}// i循環結束
// 如果nextr的值為-1,證明后面的都是0,直接退出
if (nextr == -1){
break;
}else{// 否則
// 找r行c列位置的值,判斷是否為0
if(this.data[r][c] == 0) {// 如果是0 將nextr位置的值賦值給c位置
this.data[r][c] = this.data[nextr][c];
this.data[nextr][c] = 0;// 將nextr位置的值賦值為0
r++;// 將c留在原地
}else if(this.data[r][c] == this.data[nextr][c]){
// 否則 else if(c位置的值等於nextr位置的值)
this.data[r][c] *= 2;// 將c位置的值*2
this.score += this.data[r][c];
this.data[nextr][c] = 0;// 將nextr位置的值賦值為0
// r的循環結束
}
}
}
},
}

 六.總結

1.布局,樣式比較簡單

2.js算法設計比較麻煩,構造函數不熟練,練習較少

3.游戲進行到一半,出現死循環,界面卡死不動,原因是循環里面的break位置沒有放對地方

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM