JS实现2048小游戏
程序员文章站
2024-03-18 22:46:28
...
js实现2048小游戏
开始时的页面
当游戏结束时会显示得分情况并可以再试一次
HTML部分
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>2048小游戏</title>
<link rel="stylesheet" href="style.css" />
<meta name="viewport" content="withd=device-width,initial-scale=0.8,user-scalable=no"/>
</head>
<body>
<p class="header">SCORE:<span id="score01">0</span></p>
<div class="all">
<!--第一行-->
<div class="cell n2" id="c00">2</div>
<div class="cell n4" id="c01">4</div>
<div class="cell n8" id="c02">8</div>
<div class="cell n16" id="c03">16</div>
<!--第二行-->
<div class="cell n32" id="c10">32</div>
<div class="cell n64" id="c11">64</div>
<div class="cell n1024" id="c12">1024</div>
<div class="cell n2048" id="c13">2048</div>
<!--第三行-->
<div class="cell n4096" id="c20">4096</div>
<div class="cell n8192" id="c21">8192</div>
<div class="cell" id="c22"></div>
<div class="cell" id="c23"></div>
<!--第四行-->
<div class="cell" id="c30"></div>
<div class="cell" id="c31"></div>
<div class="cell" id="c32"></div>
<div class="cell" id="c33"></div>
</div>
<div class="gameover" id="gameover">
<p>
GAME OVER!
<br />
SCORE: <span id="score02">0</span>
<br />
<a href="javascript:game.start()">TRY AGAIN</a>
</p>
</div>
<script src="index.js"></script>
</body>
</html>
CSS样式部分
*{
margin: 0;
padding: 0;
user-select: none;
font-family: Arial;
}
.header{
font-size: 50px;
font-weight: bold;
width: 480px;
margin: 0 auto;
}
.header span{
color: #f00;
}
.all{
background-color: #bbada0;
width: 480px;
height: 480px;
margin: 0 auto;
border-radius: 10px;
}
.cell{
width: 100px;
height: 100px;
background-color: #ccc0b3;
border-radius: 5px;
float: left;
margin: 16px 0 0 16px;
line-height: 100px;
text-align: center;
font-size: 50px;
color: #fff;
}
.n2{background-color:#eee3da;color:#776e65}
.n4{background-color:#ede0c8;color:#776e65}
.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;font-size:40px}
.n2048{background-color:#09c;font-size:40px}
.n4096{background-color:#a6c;font-size:40px}
.n8192{background-color:#93c;font-size:40px}
.gameover{
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0,0,0,.3);
display: none;
}
.gameover p{
width: 300px;
height: 200px;
text-align: center;
font-size: 40px;
font-weight: bold;
background-color: #fff;
border: 1px solid #000;
border-radius: 10px;
line-height: 66.66px;
position: absolute;
top: 50%;
left: 50%;
margin-left: -150px;
margin-top: -100px;
}
.gameover p a{
text-decoration: none;
color: #fff;
background-color: #9f8d77;
padding: 10px;
border-radius: 10px;
}
js部分
//[
// [2,4,8,16],
// 00 01 02 03
// [32,64,128,0],
// 10 11 12 13
// [0,16,32,64],
// 20 21 22 23
// [0,0,2,0]
// 30 31 32 33
//]
//面向对象编程 设计模式-单例模式
//创建一个对象,里面存储所有的游戏数据及游戏方法
var game = {
data : [], //定义一个数组,用来存所有的游戏的数据
score : 0, //定义一个分数的属性
gamerunning : 1, //定义一个游戏运行的状态
gameover : 0, //定义一个游戏结束的状态
status : 0, //这个是目前游戏的状态,时刻的跟上面两个状态做比较,确定游戏处于运行或者结束
start : function(){ //游戏开始时候的方法
// 游戏开始的时候肯定是要把游戏的状态设置成游戏运行的状态
// this == game
this.status = this.gamerunning;
// 游戏开始的时候分数清空
this.score = 0;
// 数组中的所有元素全部设置成0
this.data = [
[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0]
];
this.randomNum();
this.randomNum();
this.randomNum();
this.randomNum();
this.randomNum();
this.dataView();
},
// 随机数的函数,开始的时候随机生成,移动的时候随机生成
randomNum: function(){
while(true){
// 随机生成行和列 0 - 3随机整数
var r = Math.floor( Math.random() * 4 ); //随机生成一个行
var c = Math.floor( Math.random() * 4 ); //随机生成一个列
if(this.data[r][c] == 0){
var num = Math.random() > 0.3 ? 2 : 4;
this.data[r][c] = num;
break;
}
}
},
// 更新试图的方法
dataView: function(){
// 大的循环,然后把所有的元素全部遍历一遍
for(var r = 0; r < 4; r++){
for(var c = 0; c < 4; c++){
// 找到对应的div
var div = document.getElementById("c" + r + c); //字符串拼接
if(this.data[r][c] != 0){
// 数组中对应的内容放到格子上面去
div.innerHTML = this.data[r][c];
// 样式也写成对应的
div.className = "cell n" + this.data[r][c];
}else{
div.innerHTML = "";
div.className = "cell"
}
}
}
// 更新分数
document.getElementById("score01").innerHTML = this.score;
//游戏没有结束的时候 弹出层时刻都是隐藏的
if(this.status == this.gamerunning){
document.getElementById("gameover").style.display = "none";
}else{
document.getElementById("gameover").style.display = "block";
document.getElementById("score02").innerHTML = this.score;
}
},
// 判断游戏是否结束的方法
isgameover: function(){
for(var r = 0; r < 4; r++){
for(var c = 0; c < 4; c++){
if(this.data[r][c] == 0){ //里面有空格子的时候,游戏还是可以运行
return false; //表示游戏还没有结束
}
if(c < 3){//判断左右是否有相同的
if(this.data[r][c] == this.data[r][c+1]){
return false;
}
}
if(r < 3){
if(this.data[r][c] == this.data[r+1][c]){
return false;
}
}
}
}
return true;
},
//移动的方法
// 左 右 上 下
// 左移的方法
moveLeft: function(){
// console.log("准备开始")
// 数组是引用类型的,引用类型如果直接拿来做比较,肯定是false
// 直接把原始类型的数组转换成引用类型的字符串,然后做比较
var before = String(this.data); //之前做一次转换
// 具体的移动需要处理的逻辑,直接处理好每一行即可
for(var r = 0;r < 4;r ++){
this.moveLeftInRow(r);
}
var after = String(this.data); //移动之后再做一次转换
// 如果说移动之前不等于移动之后,肯定是发生了移动
if(before != after){
this.randomNum(); //生成随机数
// 生成的随机数可能会造成游戏的gameover
if(this.isgameover()){
// 改变游戏的状态
this.status = this.gameover
}
// 更新视图
this.dataView();
}
},
moveLeftInRow: function(r){ //只去做处理每一行的逻辑
for(var c = 0; c < 3; c++){
var nextc = this.getNextinRow(r,c);
if(nextc != -1){
if(this.data[r][c] == 0){
// 如果等于0,直接替换
this.data[r][c] = this.data[r][nextc];
this.data[r][nextc] = 0; //位置恢复成0
c --; //要让位置恢复到原地
}else if(this.data[r][c] == this.data[r][nextc]){
this.data[r][c] *= 2; //位置直接翻一倍
this.data[r][nextc] = 0;
this.score += this.data[r][c]; //更新分数
}
}else{ //没有找到
break; //直接退出循环
}
}
},
getNextinRow: function(r,c){
for(var i = c + 1; i < 4; i++){
if(this.data[r][i] != 0){
return i; //表示已经找到位置,并且把位置返回出来
}
}
return -1; //返回一个标识符
},
// 右移的方法
moveRight: function(){
var before = String(this.data);
for(var r = 0; r < 4; r++){
this.moveRightInRow(r);
}
var after = String(this.data);
if(before != after){
this.randomNum();
if(this.isgameover()){
this.status = this.gameover;
}
this.dataView();
}
},
moveRightInRow: function(r){
for(var c = 4; c > 0; c--){
var prevc = this.getPrevInRow(r,c);
if(prevc != -1){
if(this.data[r][c] == 0){
this.data[r][c] = this.data[r][prevc];
this.data[r][prevc] = 0;
c ++
}else if(this.data[r][c] == this.data[r][prevc]){
this.data[r][c] *= 2;
this.data[r][prevc] = 0;
this.score += this.data[r][c];
}
}else{
break;
}
}
},
getPrevInRow: function(r,c){
for(var i = c - 1; i >= 0; i--){
if(this.data[r][i] != 0){
return i;
}
}
return -1;
},
// 上移
moveUp: function(){
var before = String(this.data);
for(var c = 0; c < 4; c++){
this.moveUpInCol(c);
}
var after = String(this.data);
if(before != after){
this.randomNum();
if(this.isgameover()){
this.status = this.gameover;
}
this.dataView();
}
},
moveUpInCol: function(c){
for(var r = 0;r < 4; r++){
var nextr = this.getNextInCol(r,c);
if(nextr != -1){
if(this.data[r][c] == 0){
this.data[r][c] = this.data[nextr][c];
this.data[nextr][c] = 0;
r -- ;
}else if(this.data[r][c] == this.data[nextr][c]){
this.data[r][c] *= 2;
this.data[nextr][c] = 0;
this.score += this.data[r][c];
}
}else{
break;
}
}
},
getNextInCol: function(r,c){
for(var i = r + 1; i < 4; i++){
if(this.data[i][c] != 0){
return i;
}
}
return -1;
},
// 下移的方法
moveDown: function(){
var before = String(this.data);
for(var c = 0;c < 4; c++){
this.moveDownInCol(c);
}
var after = String(this.data);
if(before != after){
this.randomNum();
if(this.isgameover()){
this.status = this.gameover;
}
this.dataView();
}
},
moveDownInCol: function(c){
for(var r = 3; r > 0; r--){
var prev = this.getPrevIncol(r,c);
if(prev != -1){
if(this.data[r][c] == 0){
this.data[r][c] = this.data[prev][c];
this.data[prev][c] = 0;
r -- ;
}else if(this.data[r][c] == this.data[prev][c]){
this.data[r][c] *= 2;
this.data[prev][c] = 0;
this.score += this.data[r][c];
}
}else{
break;
}
}
},
getPrevIncol: function(r,c){
for(var i = r - 1; i >= 0; i--){
if(this.data[i][c] != 0){
return i;
}
}
return -1;
},
}
game.start();
console.log(game.data)
console.log(game.status);
console.log(game.score);
//键盘事件
document.onkeydown = function(){
if(event.keyCode == 37){
//console.log("左")
game.moveLeft();
}else if(event.keyCode == 38){
//console.log("上")
game.moveUp()
}else if(event.keyCode == 39){
//console.log("右")
game.moveRight()
}else if(event.keyCode == 40){
//console.log("下")
game.moveDown()
}
}
//touch事件
//手指按下
var startX;
var startY;
var endX;
var endY;
document.addEventListener('touchstart',function(){
// console.log("手指按下了屏幕")
console.log(event);
startX = event.touches[0].pageX;
startY = event.touches[0].pageY;
})
//手指移动
//document.addEventListener('touchmove',function(){
// console.log("手指的移动")
//})
//手指松开
document.addEventListener("touchend",function(){
// console.log("手指松开")
console.log(event);
endX = event.changedTouches[0].pageX;
endY = event.changedTouches[0].pageY;
var X = endX - startX;
var Y = endY - startY
var absX = Math.abs(X) > Math.abs(Y);
var absY = Math.abs(Y) > Math.abs(X);
if(X > 0 && absX){
console.log("右滑动")
game.moveRight()
}else if(X < 0 && absX){
console.log("左滑动")
game.moveLeft()
}if(Y > 0 && absY){
console.log("下滑动")
game.moveDown()
}if(Y < 0 && absY){
console.log("上滑动")
game.moveUp()
}
})
这个既可以在PC端使用,也可以打包成APP在手机端使用。