目录
- 写在前面
- 游戏介绍
- Demo 演示
- 思路整理
- 代码介绍
- HTML
- CSS
- JS
- createTable
- checkAdjacentCell
- clickHandler
- checkWin
- 代码改良 !!!
- 写在最后
写在前面
这篇文章比较长,建议先收藏哦😯
戳这里拿原码👉 github.
游戏介绍
创建一个4 x 4的面板(HTML5表实现),总共16个格子。其中一个格子是空的,其他格子从1到15随机编号。可通过单击格子将当前空格子旁边的任何图块移入当前空格子。将格子按顺序逐行排列即为胜利✌️。当用户点击了与空格子不相邻的格子时,用户会收到提醒。
Demo 演示
稍微解释一下,从上面的Demo可以看到,只可以点击与空格子相邻的格子,然后空格子和被点击的格子(下面就叫target吧)会互换。如果点击了空格子,或者不与空格子相邻的格子,就会显示红色,表示点击无效。理解完毕后,开始想思路吧😄 😄 😄
思路整理
首先,我们想一下这个游戏有什么组成呢?第一个想到的肯定是 – 16个格子!!!没错,我们肯定需要一个方法来创建格子。因为这里虽然是4x4, 可是如果需要10x10, 100x100呢,不可能手动创吧,那要到什么时候😕😕。于是我们确定了第一个方法,就叫createTable吧。接下来就开始玩了嘛~~也就是点击格子。那点击格子这个操作需要什么方法来支持呢?简单来说,点击格子就两种结果,要么换,要么不换。那这能不能换,就需要检测了 --> 看看target相邻有没有空格子。检测方法我们单独拿出来,就叫checkAdjacentCell吧。那检测完了,就需要有一个方法来控制怎么换,怎么才能把空格子和target互换呢,这就由clickHandler来实现吧。😃 到目前为止,我们已经能创造16个格子,然后都填上数字,开始愉快的玩耍了。那这个游戏就完成了吗?当然不是,除非你想一直玩下去😅 。没错,来到了我们最后一个方法,是不是把游戏玩通关了呢,就通过checkWin来实现了。到此,我们的前期头脑风暴就结束了。看到这里的你也已经非常明确了所需方法了吧⭐️⭐️⭐️,那我们就继续深入!
戳这里拿原码👉 github.
代码介绍
HTML
这里就直接附上html的码,因为很短,就没什么好说的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Game</title>
<link rel = "stylesheet" type = "text/css" href ="style.css">
</head>
<body onload="createTable()">
<h2>The Puzzle of the Fifteen Tiles</h2>
</body>
<script src="javaScript.js" type="text/javascript"></script>
</html>
CSS
body{
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
height: 100vh;
}
.puzzle {
border-style: solid;
border-color:darkcyan;
border-width: 5px;
margin-left: auto;
margin-right: auto;
text-align: center;
}
.cell,.emptyCell {
width: 60px;
height: 60px;
margin: 10px;
text-align: center;
font-weight: bold;
font-size: xx-large;
padding: 10px;
border: 1px solid;
}
.cell:hover, .emptyCell:hover{
cursor:pointer;
background-color: cadetblue;
}
JS
createTable
-
首先我们需要创建一个table,需要用到document.createElement(“table”),然后给它一个id和className,怎么给呢就是👇这样。然后用document.body.appendChild,把table元素节点添加到body元素节点中成为其子节点,但是放在body的现有子节点的最后。通过html可以知道,这行代码后body只有一个子节点,那就是table。
const myTable = document.createElement("table"); myTable.id = "myTable"; myTable.className = "puzzle"; document.body.appendChild(myTable);
-
table是由行和列组成的,所以接下里由行和列得到16个格子。因为是4x4的table,所以需要4行,由第一个for loop完成。然后每一行,有4个格子(cell),由第二个for loop完成。依然是给每个格子一个id,然后把4个格子append到每行,然后把每行append到table上。
var counter = 0; for (let i = 0; i < 4; i++) { const row = document.createElement("tr"); for (j = 0; j < 4; j++) { const cell = document.createElement("td"); cell.id = counter; //cell.addEventListener("click", clickHandler); !!!!!!!! row.appendChild(cell); counter++; } myTable.appendChild(row); }
至此,完成了一个有16个格子的table。你是不是以为运行html能实现一个4x4的table,像这样👇
然而现实却是,这样👇
这是为什么呢????
我们先回想一下,是怎么用html创建table的?是不是👇这样?<body> <table> <tr> <td></td> <td></td> <td></td> </tr> <tr> <td></td> <td></td> <td></td> </tr> </table> </body>
这就算创建好了一个没有内容的2行3列的table了。那跑这个html的时候会有东西显示吗,当然没有!都没有内容,肯定只有白茫茫。为了方便观察,给table加个框。
<style> table { border-style: solid; border-color:darkcyan; border-width: 5px; margin-left: auto; margin-right: auto; text-align: center; } </style>
就只有这样
那往里面加点内容试试,就会变成这样👇
所以说,我们目前的代码还没有内容,就不会有除框外的显示。换句话来说,createElement(“tr”)和createElement(“td”)也就是完成了上述html的功能。
-
接下来让我们把1-15放到格子里,是乱序的哦。这里就会遇到☝️问题,我当然知道要用Math.random随机从1-16里选出一个数放到格子里,但这要怎么保证随机选到的不是同一个数呢?在这里,我的方法是,创建一个叫numbers [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]的数组,然后打乱这个数组,再按顺序把数组的数放到格子里。 打乱数组这里我单独拿出来写了一个方法,叫random。
function random() { //numbers = [1,2,3,4] for (let i = 0; i < type ** 2; i++) { numbers[i] = i + 1; } var ctr = numbers.length, temp, index; // While there are elements in the array while (ctr > 0) { // Pick a random index index = Math.floor(Math.random() * ctr); // Decrease ctr by 1 ctr--; // And swap the last element with it temp = numbers[ctr]; numbers[ctr] = numbers[index]; numbers[index] = temp; } }
到这里乱序的问题也解决了,现在就是把数字放进格子了。因为需要一个空格子,所以当遇到16时,就显示空。其余则显示被分到的数字。也通过className进行区分。
for (let i = 0; i < 4 * 4; i++) { var cell = document.getElementById(i); if (numbers[i] == 4 * 4) { cell.innerHTML = ""; cell.className = "emptyCell"; } else { cell.innerHTML = numbers[i]; cell.className = "cell"; } }
终于,终于,到现在,我们就有了👇
顺利完成了一个方法,掌声!!!!👏👏👏👏👏👏👏
戳这里拿原码👉 github.
checkAdjacentCell
这个方法唯一的注意点可能是数学吧~
- 参数是target的ID,也就是通过这个方法我们要检测出target是否有相邻的空格子。如果有,则返回空格子的id,如果没有则返回-1。
- 首先,target前后左右的ID先表示出来,放到一个数组里。中间的一段if/else就是处理数学问题了。ID从0开始,假如ID是3,也就是第一行最右边的一个,它的rightCellI和topCellId是不成立的。假如ID是12,也就是第四行最左边一个,同理它的leftCellId和bottomCellId也是不成立的。这一段if/else就能解决这个问题。大家画个图就知道了,easy easy.
- 最后一个for loop也是很容易懂,因为在前面我们把空格子的className设为"emptyCell",而其它格子的className是“cell”,所以这时候就可以通过className找到空格子了。
function checkAdjacentCell(id) {
var flag = -1;
const topCellId = parseInt(id) - 4,
bottomCellId = parseInt(id) + 4,
rightCellId = parseInt(id) + 1,
leftCellId = parseInt(id) - 1;
adjacentId = [topCellId, bottomCellId, rightCellId, leftCellId];
if (adjacentId[2] % 4 == 0) {
adjacentId[2] = -1;
} else if (adjacentId[3] % 4 == 4 - 1) {
adjacentId[3] = -1;
}
for (let i = 0; i < adjacentId.length; i++) {
if (adjacentId[i] <= 4 ** 2 - 1 && adjacentId[i] >= 0) {
var cell = document.getElementById(adjacentId[i]);
if (cell.className == "emptyCell") {
flag = adjacentId[i];
}
}
}
return flag;
}
戳这里拿原码👉 github.
clickHandler
正如我们前面所说的,这个方法要实现换格子的功能。
- 首先获取targetID,以及空格子的id。如果emptyID不等于-1,那就是说可以换。把空格子和target的className,以及内容互换。如果emptyID=0,也就是target相邻没有空格子,那就显示红色,表示不能换。最后,判断用户是都赢得游戏~Done!
function clickHandler() {
var emptyID = checkAdjacentCell(this.id);
var target = document.getElementById(this.id);
if (emptyID >= 0) {
target.animate({ backgroundColor: "lightblue" }, 200);
var text = target.textContent;
var empty = document.getElementById(emptyID);
target.className = "emptyCell";
target.innerHTML = "";
empty.className = "cell";
empty.innerHTML = text;
} else {
target.animate({ backgroundColor: "red" }, 400);
}
checkWin();
}
戳这里拿原码👉 github.
checkWin
来到了最后一个也是最简单的一个方法~!!!这个方法的主要逻辑就是测试每个格子显示的数字是否等于它的id+1。我们在创建格子的时候就已经给每个格子一个id,从0开始。那么如果每个格子都满足这个条件,就说明Win Win~!
function checkWin(){
flag=true;
for(let i=0; i<(4*4)-1; i++){
var cell = document.getElementById(i);
if(cell.textContent==i+1){
continue;
}else{
flag=false;
}
}
if(flag){
var mesg = confirm("Congratulations!You win!! Do you want to play again?");
if(mesg){
location.reload()
}
}
}
这里用到了confirm方法,就是会弹出一个小窗口,问是否进行新的一轮。如果用户选择了“确定”,confrim的返回值就是true,否则就是false。如果是true的话,即重新加载页面,也就是一个新的table。
看到这里,这个游戏已经完成了~~~🌟🌟🌟🌟🌟 各位辛苦了❤️
戳这里拿原码👉 github.
代码改良 !!!
通过改良代码,不仅可以有4x4的table,还能有3x3, 2x2, 6x6的,这样一来,检测checkWin这个方法也更简单了呢,毕竟4x4我玩不赢😓
怎么改呢?非常,非常,非常简单!!!
-
首先,加两个global variable。如果是4x4,那type就是4,如果是2x2,type就是2。
var type = 4; var numbers = [];
-
然后,把所有出现 4 的地方,改成 type!惊不惊喜,意不意外,就是这么简单!戳这里拿源码👉github.
用2x2的演示一下吧
我无话可说了…gif一直上传失败…
将就着看看图片吧
写在最后
感谢你看到了这里,新手博主给大家撒花💥 欢迎留言讨论哦😊😊😊
更多推荐
JavaScript初学-入门前端小游戏-超简单
发布评论