博主教你轻轻松松利用js技巧 写出属于自己的2048小游戏!!

自己做出实现在页面中
想必大家都听说过甚至玩过2048这款小游戏 博主无聊时也会拿起手机或者在电脑上玩上几把 但是大家有没有想过自己花费点时间做出一个2048游戏 会不会非常有成就感呢?

废话不多说 开始
一.首先大家要整理一下逻辑。
首先大家在打开电脑,准备敲代码写出游戏的时候,一定要先思考,该游戏的每一步应该用什么样的逻辑判断去表达,包括游戏的输赢判断条件是什么,有没有理清楚,建议没玩过的宝贝们可以下载一个去玩玩,是非常有必要的。
1>游戏的界面应该怎么样用css去设计更为美观
每个人都有自己的审美观 在做到保证基本样式的情况下 可以添加一些自己的元素进去
2>游戏的开始与结束:
需要添加:游戏进行状态(status) 游戏结束状态(gameover) 游戏运行状态 (gamerunning)
然后分别写出游戏开始的代码块封装成一个函数 命名为“start游戏开始函数”。然后写出游戏在什么状态下会结束,写出一个总的判断条件封装成“gameover游戏结束函数”。
3>游戏的视图更新 分数,样式,数据
需要添加:游戏得分属性(score) 游戏数据存储数组[data]
然后写出游戏进行时视图的更新.样式的变化.数据的变化.分数的变化 封装成一个函数用来进行调用。
>特别重要的操作按钮键
创建键盘上下左右键按下事件绑定各自的功能
按下左键 数字移动功能封装成一个函数
按下左键 数字进行相加的功能以及判定封装成两个函数
为了保证游戏的完整性 所有的封装函数功能都是相辅相成的 所以每一个都是不可缺少的
二 在HTML文档中利用css写出游戏基本样式
因为布局比较简单 博主在这简单介绍一下我的布局 主要还是讲解js部分
首先打开百度搜索2048小游戏 然后对比页面进行设计 先上博主的效果图:

(ul li) 标签部分为游戏格 用div写也是一样的效果
注意:博主为了方便稍后的调用 li标签的id名 才设置成这个样子 与行列一一对应
(div的tab属性名标签)为游戏分数与历史分数
(div的zhebu属性名标签)为游戏结束后全屏遮布效果
<body>
<div class="father">
<div class="top_1">
<div class="top_l">
<p class="bigzi">2048</p>
<p class="bigzi1">Play 2048 Game Online</p>
<p class="bigzi2">Join the numbers and get to the <b>2048 tile!</b> </p>
</div>
<div class="top_r">
<div class="tab tab1">
<p>BEST</p>
<P class="score03">0</P>
</div>
<div class="tab tab2">
<p class="score01">SCORE</p>
<P class="score02">0</P>
</div>
<div class="tab3">
<p><button>New Gamen</button></p>
</div>
</div>
</div>
<div class="bot">
<ul>
<li class="cell" id="c00"></li>
<li class="cell" id="c01"></li>
<li class="cell" id="c02"></li>
<li class="cell" id="c03"></li>
<li class="cell" id="c10"></li>
<li class="cell" id="c11"></li>
<li class="cell" id="c12"></li>
<li class="cell" id="c13"></li>
<li class="cell" id="c20"></li>
<li class="cell" id="c21"></li>
<li class="cell" id="c22"></li>
<li class="cell" id="c23"></li>
<li class="cell" id="c30"></li>
<li class="cell" id="c31"></li>
<li class="cell" id="c32"></li>
<li class="cell" id="c33"></li>
</ul>
</div>
</div>
<div id="zhebu">
<p>
GAME OVER !<br> SCORE:
<span id="score00">0</span><br>
<a href="">TRY AGAIN</a>
</p>
</div>
</body>
css样式与大家分享一下 博主写的比较简略
<style>
//以下为主结构基本样式
* {
margin: 0px;
padding: 0px;
list-style: none;
/* background-color: #FAF8EF; */
}
.father {
width: 510px;
height: 700px;
/* border: 1px solid; */
margin: 0 auto;
z-index: 2;
}
.top_1 {
color: #776E65;
width: 100%;
height: 160px;
background-color: #FAF8EF;
}
.top_r {
width: 150px;
}
.bigzi {
font-weight: 900;
font-size: 75px;
}
.bigzi1 {
font-weight: 900;
font-size: 20px;
}
.top_l,
.top_r {
float: left;
margin-top: 5px;
}
.top_r {
margin-left: 10px;
width: 165px;
/* border: 1px solid; */
}
.tab {
width: 70px;
height: 70px;
/* border: 1px solid; */
float: right;
text-align: center;
background-color: #bbada0;
color: #fff;
}
.tab1 {
margin-left: 21px;
}
.tab3 {
width: 100%;
height: 40px;
text-align: center;
background-color: #9f8d77;
float: left;
line-height: 40px;
border-radius: 4px;
margin-top: 30px;
}
.bot {
width: 100%;
height: 535px;
/* border: 1px solid; */
background-color: #BBADA0;
}
.cell {
width: 110px;
height: 110px;
background-color: #CDC0B4;
float: left;
margin-left: 14px;
margin-top: 19px;
border-radius: 5px;
font-size: 60px;
line-height: 110px;
text-align: center;
color: #fff;
}
.score02,
.score03 {
font-size: 20px;
}
button {
font-size: 20px;
background: #9f8d77;
border: 0px;
color: #FAF8EF;
}
#zhebu {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: rgba(55, 55, 55, 0.5);
display: none; //游戏结束时 遮罩才会弹出来 所以先隐藏
}
#zhebu>p {
width: 300px;
height: 200px;
background-color: #fff;
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: -150px;
text-align: center;
border-radius: 10px;
border: 1px solid;
line-height: 65px;
font-size: 40px;
}
#zhebu>p>a {
padding: 10px;
color: #fff;
background-color: #9f8d77;
border-radius: 6px;
text-decoration: none;
}
//下面是不同数值 产生的不同游戏格字体颜色 以及格子颜色
.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
js代码部分 封装函数的逻辑代码解析
首先为了能更好的取值并使用各个函数
创建一个game对象,游戏中所有的属性和方法都放在game对象中
并创建出需要用到的对象名以及属性:
var game = {
score: 0, //添加一个得分属性
status: 1, //添加一个游戏状态
gameover: 0, //添加一个游戏结束状态
gamerunning: 1, //添加一个游戏运行状态
data: [], //添加一个数组,用于存储游戏数据的,
}
游戏开始的代码进行封装
大家请先思考 在进行游戏重新开始 要做到哪些方面的更新重置?
1.游戏状态必须设置为游戏运行中
2.将分数重置
3.清空历史游戏数据的储存器data数组
4.游戏开始时会产生两个随机数2或4 并随机出现在格子随机的两个位置
start: function() {
this.status = this.gamerunning; //游戏状态重新设置为运行状态
this.score = 0; //分数重置
this.data = []; //清空游戏数据数组
// 生成二维数组,放置在data数组中保存数据 16个0
for (var r = 0; r < 4; r++) {
this.data[r] = []
for (var c = 0; c < 4; c++) {
this.data[r][c] = 0;
}
}
this.randomNum() //随机产生的数封装的函数 因为开始会随机两个数 所以这里调用两次
this.randomNum()
this.dataView() //视图更新函数 稍后会做讲解
},
以及生成随机数的代码:
游戏开始产生的随机数字只可能是2或4 再根据for死循环生成随机行和列。
博主这里需要提到上面的li命名方式就是为了能一一对应,给大家画个简易图片:

行和列分别是从0开始 到3结束 每一行都是四格
所以用到floor向下取整 获取随机数
// 生成随机数
randomNum: function() {
for (;;) {
// 生成随机位置
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; //三元表达式 表示非2即4
this.data[r][c] = num;
break;
}
}
},
游戏进行需要视图更新以及样式和数据的修改 封装成函数
首先利用双层for循环 遍历出所有的li 即每一个横纵排列的游戏格
然后判断数组中的值是否为0 不为0则需要渲染游戏格
dataView: function() {
for (r = 0; r < 4; r++) {
for (c = 0; c < 4; c++) {
var liAll = document.getElementById("c" + r + c) //注意观察博主的li命名方式
if (this.data[r][c] != 0) { //数组中的值不为0,渲染页面
liAll.innerHTML = this.data[r][c]; //修改li的值
liAll.className = "cell n" + this.data[r][c]
} else { //数组中的值为0,数据不能显示至
liAll.innerHTML = "";
liAll.className = "cell";
}
}
}
//找到分数class名并设置分数
document.getElementsByClassName("score02")[0].innerHTML = this.score;
//判断条件
if (this.status == this.gameover) { //gameover 为游戏结束的函数 稍后会讲解
document.getElementById("score00").innerHTML = this.score;
document.getElementById("zhebu").style.display = "block"; //游戏结束便会弹出遮罩层 宣布游戏结束
} else {
document.getElementById("zhebu").style.display = "none" //没结束遮罩永远不会弹出
}
},
游戏结束判断代码片 封装成函数
所有的游戏都会在某种情况下结束掉 要先列举出每一种情况 一件都不能少 否则游戏会无限进行下去:
1.游戏中方格被数字填充满 没有位置可以移动并产生随机数
2.游戏格子占满时要判断相邻数字之间能否左右上下能否相加
如果以上两点都满足 则游戏结束 弹出遮罩层 宣布游戏结束。
给大家看一下遮罩层的效果图:

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) (moveLeftRow:)(getNextinRow)
三个函数都有着各自的功能 但是每一个功能都是联系紧密的 所以需要一起来看:
moveLeft: function() {
var before = String(this.data)
console.log(before);
for (r = 0; r < 4; r++) {
this.moveLeftRow(r)
}
var after = String(this.data)
console.log(after);
if (before != after) {
this.randomNum()
if (this.isGameover()) {
this.status = this.gameover
}
this.dataView()
}
},
moveLeftRow: function(r) { //单独抽出一行进行写逻辑
for (var c = 0; c < 3; c++) { //最左边的不需要移动,所以遍历三次
//找出r行c列后面不为0的数据的位置保存至nextc中
var nextc = this.getNextinRow(r, c)
console.log(nextc);
if (nextc != -1) {
//这一行中有需要移动的数据
if (this.data[r][c] == 0) {
this.data[r][c] = this.data[r][nextc]
this.data[r][nextc] = 0;
c--;
//c留在原地继续左移动
} else if (this.data[r][c] == this.data[r][nextc]) {
this.data[r][c] = this.data[r][c] * 2;
console.log(this.data[r][c]);
this.score += this.data[r][c] * 1000; //分数
this.data[r][nextc] = 0;
}
} else {
//这一行没有需要移动的数据
break;
}
}
},
getNextinRow: function(r, c) {
for (var i = c + 1; i < 4; i++) {
if (this.data[r][i] != 0) {
return i;
}
}
return -1; //如果当前行找不到不为0的数据则返回-1
},
同理只需要修改行列 就可以做出向右,向上,向下移动的封装函数:
moveRight: function() {
var before1 = String(this.data);
console.log(before1);
for (r = 0; r < 4; r++) {
this.moveRightRow(r)
}
var after1 = String(this.data);
console.log(after1);
if (before1 != after1) {
this.randomNum()
if (this.isGameover()) {
this.status = this.gameover
}
this.dataView()
}
},
moveRightRow: function(r) {
for (var c = 3; c > 0; c--) {
var prevc = this.getPrevRow(r, c)
console.log(prevc);
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] = this.data[r][c] * 2;
this.score += this.data[r][c] * 1000;
this.data[r][prevc] = 0;
}
} else {
break;
}
}
},
getPrevRow: function(r, c) {
for (var i = c - 1; i > -1; i--) {
if (this.data[r][i] != 0) {
return i;
}
}
return -1;
},
moveUp: function() {
var before1 = String(this.data);
console.log(before1);
for (c = 0; c < 4; c++) {
this.moveUpRow(c)
}
var after1 = String(this.data);
console.log(after1);
if (before1 != after1) {
this.randomNum()
if (this.isGameover()) {
this.status = this.gameover
}
this.dataView()
}
},
moveUpRow: function(r) {
for (var r = 0; r < 3; r++) {
var prevc = this.getPrev1Row(r, c)
console.log(prevc);
if (prevc != -1) {
if (this.data[r][c] == 0) {
this.data[r][c] = this.data[prevc][c]
this.data[prevc][c] = 0;
r--;
} else if (this.data[r][c] == this.data[prevc][c]) {
this.data[r][c] = this.data[r][c] * 2;
this.score += this.data[r][c] * 1000;
this.data[prevc][c] = 0;
}
} else {
break;
}
}
},
getPrev1Row: function(r, c) {
for (var i = r + 1; i < 4; i++) {
if (this.data[i][c] != 0) {
return i;
}
}
return -1;
},
moveDow: function() {
var before1 = String(this.data);
console.log(before1);
for (c = 0; c < 4; c++) {
this.moveDowRow(c)
}
var after1 = String(this.data);
console.log(after1);
if (before1 != after1) {
this.randomNum()
if (this.isGameover()) {
this.status = this.gameover
}
this.dataView()
}
},
moveDowRow: function(c) {
for (var r = 3; r > 0; r--) {
var prevc = this.getDowRow(r, c)
console.log(prevc);
if (prevc != -1) {
if (this.data[r][c] == 0) {
this.data[r][c] = this.data[prevc][c]
this.data[prevc][c] = 0;
r++;
} else if (this.data[r][c] == this.data[prevc][c]) {
this.data[r][c] = this.data[r][c] * 2;
this.score += this.data[r][c] * 1000;
this.data[prevc][c] = 0;
}
} else {
break;
}
}
},
getDowRow: function(r, c) {
for (var i = r - 1; i > -1; i--) {
if (this.data[i][c] != 0) {
return i;
}
}
return -1;
}
绑定键盘上下移动键
game.start()
// console.log(game.getNextinRow());
document.onkeydown = function(event) {
if (event.keyCode == 37) {
game.moveLeft()
}
if (event.keyCode == 39) {
game.moveRight()
}
if (event.keyCode == 38) {
game.moveUp()
}
if (event.keyCode == 40) {
game.moveDow()
}
这篇博客教你如何利用JavaScript轻松创建属于自己的2048小游戏。从游戏逻辑梳理、CSS样式设计到JS代码实现,包括游戏界面设计、开始与结束状态判断、视图更新、操作按键响应等关键步骤,让你一步步构建出完整的游戏功能。

8540

被折叠的 条评论
为什么被折叠?



