2048游戏简单实现
前言
最近突然心血来潮想写一个网页小游戏,我看网上有很多人推荐写2048来练练手,遂开始写。目前为止,基本功能已经实现,只是没有添加相应的动画效果,待以后有机会补上(其实我就是动画这块太菜了 T_T)
前方长文预警!!!
游戏截图
项目结构
这个项目结构挺简单的,应该也都看得懂,在此仅对js文件夹进行描述,其余的就不再赘述啦
(main.js是入口文件,move.js主要就是一些移动的处理,support.js里是对移动块背景颜色和文字颜色的处理,后面要添加的动画效果也准备写在这个文件里)
主要功能
1.游戏初始化:新建游戏4×4的16宫格画布,随机格子上生成2或者4两个数字
2.格子的移动:先判断能否移动,移动后判断能否合并,合并后改变格子颜色和数字
3.新格子的生成:移动一次,就在剩余的空格子中随机生成一个2或者4
4.判赢:16宫格中合并出了“2048”则为游戏胜利
5.判输:16宫格中没有剩余空格子且不能再向任何方向移动则为游戏失败
分步代码
一、HTML结构
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>2048</title><scriptsrc="http://code.jquery.com/jquery-3.3.1.min.js"></script><link rel="stylesheet" href="css/index.css">
</head>
<body><header><div class="left"><span class="title">2048</span><p class="slogan_1">Play 2048 Game Online</p><p class="slogan_2">Join the numbers and get to the 2048 tile!</p></div><div class="right"><p class="score-box">score<br /> <span id="score">669</span></p><button type="button" id="new-game">New Game</button></div></header><div id="grid-con"><!-- 第一行 --><div class="grid-cell" id="grid-cell-0-0"></div><div class="grid-cell" id="grid-cell-0-1"></div><div class="grid-cell" id="grid-cell-0-2"></div><div class="grid-cell" id="grid-cell-0-3"></div><!-- 第二行 --><div class="grid-cell" id="grid-cell-1-0"></div><div class="grid-cell" id="grid-cell-1-1"></div><div class="grid-cell" id="grid-cell-1-2"></div><div class="grid-cell" id="grid-cell-1-3"></div><!-- 第三行 --><div class="grid-cell" id="grid-cell-2-0"></div><div class="grid-cell" id="grid-cell-2-1"></div><div class="grid-cell" id="grid-cell-2-2"></div><div class="grid-cell" id="grid-cell-2-3"></div><!-- 第四行 --><div class="grid-cell" id="grid-cell-3-0"></div><div class="grid-cell" id="grid-cell-3-1"></div><div class="grid-cell" id="grid-cell-3-2"></div><div class="grid-cell" id="grid-cell-3-3"></div></div><div class="mask"></div> <!-- 灰色遮罩层:游戏结束时随gameover框一并出现 --><div id="game-over">Game Over!</div><div id="game-win">Congradulation!</div><script src="js/main.js"></script><script src="js/move.js"></script><script src="js/support.js"></script>
</body>
</html>
HTML结构的主要思路为:利用网格布局将游戏画布的16宫格绘制出来,通过class定制样式,id定位到具体的格子以重绘格子样式。
网格布局的详细教程移步 ——> CSS网格布局(Grid)完全教程
二、CSS样式文件
* {margin: 0;padding: 0;
}
body {text-align: center;font-family:Arial, Helvetica, sans-serif;position: relative;background: #F2EAE3;
}
header {width: 500px;margin: 0 auto;display: flex;justify-content: space-between;margin-top: 30px;
}
header .left {display: flex;flex-direction: column;align-items: flex-start;justify-content: space-between;
}
header .left .slogan_1 {color: #776E65;font-weight: bold;
}
header .left .slogan_2 {color: #7F7265;
}
header span.title {color: #776E65;font-size: 70px;font-weight: bold;
}
header button {width: 100px;height: 50px;border: 0;background: #907B66;font-size: 14px;font-weight: bold;color: #fff;padding: 5px;border-radius: 3px;margin-top: 10px;outline: none;cursor: pointer;
}
header p.score-box {width: 100px;background: #BBADA0;color: #EEE4DA;padding: 10px 5px;margin-top: 10px;font-size: 18px;box-sizing: border-box;border-radius: 3px;
}
header p.score-box #score {color: #fff;font-size: 22px;letter-spacing: 2px;font-weight: bold;
}
#grid-con {width: 500px;height: 500px;background: #BCAEA1;border-radius: 10px;margin: 30px auto 0;padding: 15px;display: grid;grid-template-columns: repeat(4,1fr);grid-template-rows: repeat(4,1fr);grid-gap: 15px;grid-template-areas: "grid-cell-0-0 grid-cell-0-1 grid-cell-0-2 grid-cell-0-3""grid-cell-1-0 grid-cell-1-1 grid-cell-1-2 grid-cell-1-3""grid-cell-2-0 grid-cell-2-1 grid-cell-2-2 grid-cell-2-3""grid-cell-3-0 grid-cell-3-1 grid-cell-3-2 grid-cell-3-3";
}
#grid-con .grid-cell {background: #CDC1B4;border-radius: 10px;
}
#grid-con .grid-cell.number-cell {text-align: center;background: #EEE4DA;border-radius: 10px;color: #776E65;font-size: 50px;font-weight: bold;display: flex;justify-content: center;align-items: center;
}
.mask {width: 530px;height: 530px;background: #F2EAE3;position: absolute;/* top: -30px; */top: 167px;left: calc(50vw - 265px);z-index: 1000;opacity: .6;
}
#game-over,#game-win {width: 300px;height: 100px;color: #fff;font-size: 30px;font-weight: bold;background: rgba(39,40,34,.6);border-radius: 5px;line-height: 100px;text-align: center;position: absolute;top: 370px;left: calc(50vw - 150px);z-index: 1001;
}
.hide {display: none;
}
三、JS逻辑代码
1 主程序入口文件main.js:
思路:创建全局变量score、board分别用于保存游戏得分和16宫格数字信息,并在浏览器加载后立即初始化一局新游戏newGame()。开始游戏后用户通过键盘的方向键控制格子的移动:
- 移动操作过程中需要先检测该方向上是否能够移动,能移动则16宫格中所有数字格子均向该方向移动,不能移动则按下方向键界面不产生响应;
- 移动后需检测移动方向上相邻两个格子中的数字是否一样,一样则可以进行合并(合并后需再次向该方向移动,重绘16宫格数据),若不能合并则完成本次移动操作。
1.1 整个流程
1.1.1 首先,将需要用到的全局变量声明在文件的开头,在此有两个:
score和board的作用前文已经讲到过,在此不再赘述
var score = 0
var board = new Array()
1.1.2 新建一局游戏newGame()
初始化16宫格为游戏截图图一的样式,init()和generateOnNumber()方法分别见1.2.1和1.2.2
function newGamen () {// 初始化16宫格init()// 初始生成两个数字 2 4 8 16 32 64 128 ...generateOneNumber()generateOneNumber()
}
1.1.3 监听方向键按下事件触发相应方向的移动
根据用户按下的方向键决定16宫格中数字的移动方向,先判断能否向该方向移动,若能则移动后重新渲染16宫格,然后在随机生成一个2或者4,此时还需判断新生成一个数字格后有没有造成游戏判输(16宫格中没有空余空格且四个方向均不能移动)或者判赢(16宫格中出现了2048);若不能向该方向移动,则什么都不做。
注:moverToXXX(true)方法返回true时,就意味着此时可移动且改变了board二维数组的值,应将改变后的二维数组值重新渲染到页面16宫格对应位置,renderBoard()方法见1.2.3。moveToXXX()方法将在后文的move.js移动文件中说明。
$(document).keyup(function (e) {switch (e.keyCode) {case 37 : // 向左if(moveToLeft(true)) {renderBoard()generateOneNumber()if(!isGameWin())isGameOver()}breakcase 38 : // 向上if(moveToTop(true)) {renderBoard()generateOneNumber()if(!isGameWin())isGameOver()}breakcase 39 : // 向右if(moveToRight(true)) {renderBoard()generateOneNumber()if(!isGameWin())isGameOver()}breakcase 40 : // 向下if(moveToBottom(true)) {renderBoard()generateOneNumber()if(!isGameWin())isGameOver()}breakdefault: break;}
})
1.1.4 点击“New Game”按钮新建一局游戏
$(document).on("click","button#new-game",function () {newGamen()
})
1.1.5 重新计算分数并回填到页面
计分规则是:每合并一次数字格分数加4
function setScore () {score += 4$("header #score").text(score)
}
1.2 具体功能代码块
1.2.1 init()
遮罩层功能在前面的HTML代码中注释过,它就是一个灰色的遮罩层,将16宫格覆盖住,只是一个样式,不具有任何功能(若是点击页面某个地方触发移动,遮罩层就有防止游戏结束用户再次点击的作用,可这里是用键盘事件触发的移动操作,所以,这里的遮罩层是没有啥作用的喔~)。
坑1:严格来说这不叫坑,是自己脑筋一时没转过弯来(捂脸orz...)。游戏结束时用户按下方向键是不会有任何作用的,我苦思冥想N久游戏结束时如何阻止用户的键盘事件未果,结果一问同事,同事说,难道不是因为用户按四个方向键都不再起任何作用时才触发的游戏结束吗?此时根本就不必再去限制键盘事件了啊。emmmm....好吧,我蠢了
function init () {score = 0 // 初始化分数为0$("header #score").text(score) // 回填分数到页面指定DOM节点上$(".mask,#game-over,#game-win").addClass("hide") // 隐藏遮罩层、gameover、gamewin框for(var x = 0;x < 4;x++) { // 将board二维数组的值全部置为0以初始化16宫格board[x] = new Array()for(var y = 0;y < 4;y++) {board[x][y] = 0}}
}
1.2.2 generateOnNumber()
function generateOneNumber () {// 随机生成一个数字 2or4var randNumber = Math.random() < 0.5 ? 2 : 4// 随机生成位置var randNumberX = Math.floor(Math.random()*4)var randNumberY = Math.floor(Math.random()*4)// 检查该位置上是否已有值,没有则直接在该位置上生成新数字格,若有值则重新随机生成位置if(board[randNumberX][randNumberY] !== 0) {generateOneNumber()} else {board[randNumberX][randNumberY] = randNumber}// board二维数组中重新生成了新数字当然要将board重新渲染到页面中咯renderBoard()
}
1.2.3 renderBoard()
循环遍历二维数组board中每一个值(赋值给num),若num不为零代表该位置对应的16宫格上有数字格,改变该格子的样式(addClass("number-cell")),并将num值填入格子中(html(board[x][y])),之后再根据num值获取到该数字格的背景颜色和数字颜色;若num为零则表示该位置对应的16宫格上没有数字,为空格子,此时应移除该位置上的数字格样式并把数字“清空”(html("")),然后将该空格子的背景色置为初始值颜色。
注:此处涉及getNumberCellBgColor(num)和getNumberColor(num)两个方法,将在后文的support.js公共方法文件中提及并说明。
function renderBoard () {for(var x = 0;x < 4;x++) {for(var y = 0;y < 4;y++) {var num = board[x][y]if(num !== 0) {$(`#grid-cell-${x}-${y}`).addClass("number-cell").html(board[x][y]).css("background",getNumberCellBgColor(num)).css("color",getNumberColor(num))} else {$(`#grid-cell-${x}-${y}`).removeClass("number-cell").html("").css("background",getNumberCellBgColor(num))}}}
}
1.2.4 游戏的判赢/判输
根据前文提及的规则:
- 判赢:16宫格中合并出了“2048”则为游戏胜利
- 判输:16宫格中没有剩余空格子且不能再向任何方向移动则为游戏失败
在每次成功移动数字格且再次随机生成一个新数字格之后需要对当前16宫格进行判定,检查其此时是否触发游戏的胜利或者失败。
tips:之所以在上文的1.1.3中先判断isGameWin(),是因为判赢的代码比判输的简单,先将其作为一个“关卡”判断此部分能否继续下去,这样就不用每次都触发较为麻烦的isGameOver()方法了。
1.2.4.1 判赢
function isGameWin () {for(var x = 0;x < 4;x++) {for(var y = 0;y < 4;y++) {if(board[x][y] === 2048) {gamewin()return true}}}return false
}
function gamewin () {$(".mask,#game-win").removeClass("hide")
}
1.2.4.2 判输
moveToXXX()方法接收一个参数,该参数用于判断此时调用moveToXXX()方法是想移动数字格还是仅仅判断能否移动,详细一点来讲,就是传入一个参数来判断此时要不要更新board中的值,如果仅仅是判断该方向上能否移动,则无需更新board数组,传入false,若是需要判断后移动数字格则需更新board
tips:此处isGameOver()方法中涉及一个“逻辑中断(逻辑与)”,其实作用和上一个tips中一样,先判断简单的noSpace(),若其返回值为false那么就不必再执行逻辑相对复杂的noMove()方法。
function isGameOver () {if(noSpace()&&noMove()) {gameover()}
}
// 判断此时四个方向上能否有一个能移动
function noMove () {if(moveToLeft(false) || moveToTop(false) || moveToRight(false) || moveToBottom(false)) return falsereturn true
}
// 判断此时16宫格中是否还有空格子
function noSpace () {for(var x = 0;x < 4;x++) {for(var y = 0;y < 4;y++) {if(board[x][y] === 0) return false}}return true
}
// 去掉对遮罩层和gameover框的隐藏效果
function gameover () {$(".mask,#game-over").removeClass("hide")
}
2 移动文件move.js
2.1 移动原理
首先,如果要保存16宫格中的情况,我们很容易就想到要用二维数组:
用一个4×4的二维数组来模拟16宫格中数字格子的位置关系,没有数字的空格子用"0"来表示,其余有数字的将其数值存入该位置对应的二维数组,例如:
对应的二维数组board为:[[8,16,8,16],[64,8,0,2],[8,4,0,0],[4,0,0,0]]
在开始研究原理之前,我们需要想清楚:当玩家按下方向键时,16宫格中的格子肯定是朝着按下的那个方向移动的,不管是向左、上、右、下移动,都是整行/列4个格子为一组进行移动,而每一组的行为都是一致的(朝着同一方向移动),所以,要研究移动的原理,只需研究长度为4的数组中值的移动规律。
此时,我们再来看看移动的原理:
以 [0,4,8,8] 为例,假如此时玩家按下向左的方向键,那么照理来看,此数组应该变为 [4,16,0,0] 。这要如何实现呢?
我的做法是:
第一步:抛开相同数字可以合并的规则,先将所有数字移动到它的"最终位置"上去。即遍历该数组,去掉其中的 0。因为0代表此格子上没有值,后面的数字格是可以移动到这个位置上来的。故此时,[0,4,8,8]就变成了[4,8,8]。
就这样?当然不行,数组的长度可是固定为4的!arr.splice(index,length)方法会删除数组中下标为index开始的长度为length的数值,所以每当删去一个零,就应该在数组的末尾添上一个0(arr.push(0))来保证数组长度始终为4,这样上述数组才按照我们预想的,变成了[4,8,8,0]
所以,第一步总结来看,就是删0补0,将数字全部移至最左边,数字与数字之间不会存在0的情况。
// 先删除数组中的0
var tag = 0
for(var i = 0;i < arr.length;i++) {if(arr[tag] === 0) {arr.splice(tag,1)arr.push(0)} else {tag++continue}
}
第二步:完成相同数字的合并。依旧是循环遍历该数组,但区别于第一步的遍历,此时的遍历从下标为1开始,有两种情况:
若当前值为0,则可直接结束这步操作,因为在第一步中我们已经将该数组中间位置的所有0都删除了,唯一可能出现0的情况,就是在数组的末尾或者是该数组全为0,不管是哪一种,都表示当前值到循环结束之间已经不存在有值的位置了。
若当前值不为0,则判断当前值与上一个值是否相等,如相等就将上一个值×2并删除当前值,在数组末尾push(0),如不相等就continue
总结来讲,第二步就是删除相邻的重复值,并将前一个值×2,数组末尾添0。
// 判断相加/合并
for(var i = 1;i < arr.length;i++) {if(arr[i] === 0) breakif(arr[i] === arr[i-1]) {setScore()arr[i-1] *= 2arr.splice(i,1)arr.push(0)}
}
此时,完成了我们想要的“最终效果”,即[0,4,8,8]变成了[4,16,0,0],然后利用renderBoard()将board渲染到16宫格中便大功告成了!!然鹅,当你多玩几次就会发现bug了。
如果数组为[2,2,4,8],按照上面的步骤操作下来,数组就变成了[4,4,8,0],然鹅我们的预想应该是[16,0,0,0]才对啊!所以,此时还需在第二步的基础上进行改进,即为下述的第三步:
第三步:合并数字后下标的回退。两个相邻的相同数字合并之后还应检查其合并后的值与其移动方向上一位的值是否一致,若一致,则应再次触发合并操作。例如:[2,2,4,8]第一次合并之后为[4,4,8,0],此时若想进行第二次合并,则应将下标再一次从1开始重新遍历数组,重复第二步的操作,得到[8,8,0,0],第三次重复遍历后才能得到最终值[16,0,0,0]。
总结第三步就是如遇合并重复遍历。
// 判断相加/合并
for(var i = 1;i < arr.length;i++) {if(arr[i] === 0) breakif(arr[i] === arr[i-1]) {setScore()arr[i-1] *= 2arr.splice(i,1)arr.push(0)i = 0 // 第三步!此处不能 i -= 1 [8,2,2,4]会出问题}
}
坑:如上述第三步的代码注释中,i=0不能写成i-=1。我最初的想法是,合并完成之后,将下标回退1然后for循环i++之后,下标i还是指向的是刚刚判断过的那一位,这样就完成了合并之后再次判断当前位与其移动方向上一位的值的比较。想来是没有什么问题,直到遇到[8,2,2,4]这种数组。
eg:[8,2,2,4]
第一次,循环到下标i=2时产生合并,即a[2]=a[2-1] = 2,a[2-1]=4,删去a[2],在数组末尾添0,处理之后为[8,4,4,0],此时下标i回退1,i = 1
第二次,for循环会使第一次得到的i先+1,即i = 2,此时a[2] = a[2-1] = 4,a[2-1] = 8,删去a[2],在数组末尾添0,处理之后为[8,8,0,0],此时下标i回退1,i=1
第三次,i仍是先+1,即i=2,此时a[2] = 0,会直接break循环,产生错误的结果——>[8,8,0,0],而非[16,0,0,0]
解决:故此,下标的回退必须从头开始。
完整的移动处理函数如下:
function updateArr (arr) {// 先删除数组中的0var tag = 0for(var i = 0;i < arr.length;i++) {if(arr[tag] === 0) {arr.splice(tag,1)arr.push(0)} else {tag++continue}}// 判断相加/合并for(var i = 1;i < arr.length;i++) {if(arr[i] === 0) breakif(arr[i] === arr[i-1]) {setScore()arr[i-1] *= 2arr.splice(i,1)arr.push(0)i = 0 // 此处不能 i -= 1 [8,2,2,4]会出问题}}
}
2.2 按序传入数组
讲完了移动的原理,剩下的就好办多了,几乎不怎么需要动脑子了。2.1中的移动原理是基于长度为4的数组往左移的情况,但我们的小游戏中16宫格中的数字格会随玩家按下的方向键不同而朝着不同方向移动,这可如何处理呢?
很简单,以下图中的情况为例进行说明:
2.2.1 左移
updateArr(arr)方法接收一个数组,并将其左移进行相关的合并操作,那么如果想将16宫格(4×4的二维数组)进行移动操作,就应将二维数组分行传入该处理函数,即分次传入[8,0,0,0],[16,0,0,0],[8,2,2,0],[2,8,4,0]
function moveToLeft () {var arr = []for(var x = 0;x < 4;x++) {arr[x] = board[x]updateArr(arr[x])}
}
!tips:此处用一个新数组arr来保存board每次传入的一维数组的目的,待后文阐述。
2.2.2 右移
同理,如要将二维数组向右移动,则应把每次传入的数组逆序传入处理函数,即分次传入[0,0,0,8],[0,0,0,16],[0,2,2,8],[0,4,8,2]
function moveToRight () {var arr = []for(var x = 0;x < 4;x++) {arr[x] = new Array()// 数组反向传入处理函数arr[x] = board[x].concat()arr[x].reverse()updateArr(arr[x])}
}
!tips:此处涉及一个数组API的问题,arr.reverse()方法会将数组元素倒序,但改变的是原数组的值,然而我想保留原数组board[x]值不变,将新数组arr[x]倒序传入处理函数即可。这里采用的是board[x].concat()来返回一个新数组并赋值给arr[x]的方式来保留原数组不受reverse的影响(保留原数组的原因见后文)。
2.2.3 上移
上移操作较麻烦一丢丢,但也还好。如上图,若要上移且满足updateArr()方法中的处理程序,应分次传入[8,16,8,2],[0,0,2,8],[0,0,2,4],[0,0,0,0]
function moveToTop () {var arr = []for(var y = 0;y < 4;y++) {arr[y] = new Array()for(var x = 0;x < 4;x++) {arr[y].push(board[x][y])}updateArr(arr[y])}
}
2.2.4 下移
同上移的原理,但传入updateArr()方法的一维数组同样应该逆序传入,即分次传入:[2,8,16,8],[8,2,0,0],[4,2,0,0],[0,0,0,0]
function moveToBottom () {var arr = []for(var y = 0;y < 4;y++) {arr[y] = new Array()for(var x = 0;x < 4;x++) {arr[y].unshift(board[x][y])}updateArr(arr[y])}
}
2.3 能否移动
到此为止,移动的原理及相关处理基本介绍完毕。之前为了简化对移动的处理,未在移动之前先检查该方向上能否移动。
如何才叫能移动呢?——>[0,4,8,16],[2,2,0,0]这两种情况。用文字来描述就是:
- 当前值不为0,且当前值之前有为0的值
- 该数组中存在相邻位置的值相等的情况(即能产生合并)
据此可写出代码如下:
function canMove (arr) {var hasZero = falsefor(var i = 0;i < arr.length;i++) {if(arr[i] === 0) {hasZero = true} else if(arr[i] !== 0 && hasZero || arr[i] === arr[i+1]) {return true} else {continue}}return false
}
2.4 完整移动
完整的移动逻辑应该是:先判断该方向上能否移动,但由于我们的移动是分次传入,只要有一次的结果是可移动,那么整个二维数组都是可移动的,所以要先将分次传入的数组进行移动处理后的结果保存在新数组里,当四次分次传入均处理完且其中有一个能移动时,将新数组的值赋值给原数组board,完成二维数组的条件更新。
以左移为例:
function moveToLeft (type) {var arr = [],tag = falsefor(var x = 0;x < 4;x++) {arr[x] = new Array()arr[x] = board[x]tag = tag || canMove(arr[x])if(type) updateArr(arr[x])}if(tag && type) board = arrarr = nullreturn tag
}
tag用于接收能否移动的结果,type的作用前文已讲过,不再细说。
3 support.js工具文件
主要是数字格的背景色和文字颜色的设置,理解上没什么难度。
function getNumberCellBgColor (num) {switch (num) {case 2 :return "#EEE4DA"case 4 :return "#EDE0C8"case 8:return "#F26179"case 16:return "#F59563"case 32:return "#F67C5F"case 64:return "#F65E36"case 128:return "#EDCF72"case 256:return "#EDCC61"case 512:return "#9C0"case 1024:return "#3365A5"case 2048:return "#09C"case 4096:return "#a6bc"case 8192:return "#93c"default: return "#CDC1B4"}
}function getNumberColor(number) {if (number <= 4){return "#776e65";}return "white";
}
完整代码
完整代码详见:https://github.com/Crystal-Zx/2048-H5-GAME
2048游戏简单实现相关推荐
- 2048游戏-AI程序算法分析
针对目前火爆的2048游戏,有人实现了一个AI程序,可以以较大概率(高于90%)赢得游戏,并且作者在stackoverflow上简要介绍了AI的算法框架和实现思路.但是这个回答主要集中在启发函数的选取 ...
- 2048游戏的python实现
2019独角兽企业重金招聘Python工程师标准>>> 一个2048小游戏的python实现 今天看了OSC网友xiaohui_hubei的2048游戏代码感觉很有意思,特意花时间玩 ...
- 2048游戏代码python_200 行代码实现简易版 2048 游戏 (python)
当然这一篇需要你有一定的python基础?如果你没有python基础不要着急,你可以先去找一些python的基础教程去了解了解学习学习这门短小精悍的语言. 好了,说了那么说没用的话,现在正式开始 创建 ...
- 是男人就下100层【第五层】——2048游戏从源码到发布市场
上一篇<是男人就下100层[第五层]--换肤版2048游戏>中阳光小强对2048游戏用自己的方式进行了实现,并分享了核心源码,这一篇阳光小强打算将该项目的所有源代码公开并结合这个实例在这篇 ...
- 2048游戏c语言实验报告,2048游戏语言实验报告.doc
2048游戏语言实验报告 成绩评定 教师签名 评定日期 嘉应学院 计算机学院 实验报告 课程名称: C程序设计 开课学期: 2015-2016学年第1学期 班 级: 计算机1505 指导老师: 陈广明 ...
- C++的学习心得和知识总结(十八)|基于EasyX实现 2048游戏 项目(C/C++版)
目录结构 注:提前言明 本文借鉴了以下博主.书籍或网站的内容,其列表如下: 1.网络热门游戏 2048,点击前往 2.EasyX官方链接,点击前往 3.中国色谱 颜色代码对照表(RGB多用于easyX ...
- 基于python的2048游戏设计_用python写一个2048游戏
self.randomGenerateNumberself.randomGenerateNumber 然后,当玩家按下方向键(↑↓←→)时,这个二维列表要根据玩家的操作指令进行更新,主要分为两个部分: ...
- python2048游戏撤销上一部功能怎么实现_python 实现 2048 游戏 (一)
初学 python ,大家恐怕都想找到一条终南捷径,会产生譬如 3 天精通 python 这样不太切合实际的想法.这种想法是很危险的,一旦你发现你根本不可能做到,你就会变得灰心丧气,甚至演变成 pyt ...
- Python 《Python 实现 2048 游戏》实验报告
74340da14d79fae0a21de03d44699f80b6c624f3.jpg 2048 游戏 wiki:<2048>是一款单人在线和移动端游戏,由19岁的意大利人 Gabrie ...
- Web版2048游戏制作
写在前面 工作之余参与了<慕课网2048游戏制作>的学习视频,视频断断续续看完了,游戏也制作成功了.因为其他的事情也没来的及总结,一拖时间也就过去了,整理磁盘的时候发现了2048源码,思考 ...
最新文章
- oracle省市表,省市之一 创建全国省市Sql表
- 大战即将来临,柯洁将于5月与AlphaGo正式对决
- 当代家长现状。。 | 今日最佳
- 带参数标签的取值方法
- java count rows_Java统计个人编写的Java文件个数及代码行数
- k阶原点距和k阶中心距各是说明什么数字特征
- JDBC学习总结4-------简化DAO的写法
- Python数据分析(二): Numpy技巧 (3/4)
- 2#使用新安装的ubuntu,之vim必须知道的细节
- python把两张图片合成一张_怎么合成图片-利用Python将两张图片合成为一张图
- 群晖(Synology)配置 NAS + 软路由 续
- 体育成绩统计——20180801模拟赛T3
- linux mentohust dhcp,Ubuntu下Mentohust的配置
- Web爬虫|入门实战之实习僧(编码反爬)
- 【Python+Appium】开展自动化测试(八)swipe()滑动页面
- quot;多看nbsp;fornbsp;kindle3”升级包下载
- Cowboy 源码分析(十一)
- JAVA程序设计:破解保险箱(LeetCode:753)
- 用Python画樱花树的代码
- android应用app开发