零、体验游戏
http://aring.3vfree.net/game/Chimpanzee-Test/index.html
一、实现效果
二、实现过程
看上图实现效果,大致的思路梳理:
1.设定一个表格,初始隐藏所有单元格
2.随机给单元格赋值以及添加边框
3.根据游戏难度等级循环赋值单元格
4.赋值完毕后为单元格添加点击事件以判断点击结果
5.判定尝试次数以及继续游戏/重新游戏功能
梳理好思路开始写脚本:
第一步
实现让单元格随机显示在表格中,如下图
首先,获取所有<td>标签,然后随机指定需要赋值的td,我这里做了30个单元格所以随机0~29
const td = document.getElementsByTagName("td") // 单元格
// 随机指定需要赋值的td
function randomTd() {
const tdIndex = Math.floor(Math.random() * 29)
return td[tdIndex]
}
然后根据等级循环给td赋值
循环获取上文随机得到的td,然后给td设定文本为i,即第几次循环,td的文本就是几
然后给td加上设定好的边框class
最后,给每个td单独添加一个点击事件,并传参循环次数i 和该td本身,用以判断点击时的结果
let level = 6 // 等级
// 根据等级循环给td赋值
function tdAssignment() {
for (let i = 1; i < level; i++) {
let slTd = randomTd()
slTd.innerText = i
slTd.classList.add("td-border")
}
}
但是这上文会出现一个问题,假如随机的td重复了怎么办呢?
为了解决这个问题可以循环判断td 当前文本不为空,即:假设td当前的文本已经被赋值,则再次随机,用循环是为了重复判断
for (let i = 0; slTd.innerText != ""; i++) { // 将要赋值的td如果不为空,则再次随机td的index
slTd = randomTd()
}
将该判断到tdAssignment()中
// 根据等级循环给td赋值
function tdAssignment() {
for (let i = 1; i < level; i++) {
let slTd = randomTd()
for (let i = 0; slTd.innerText != ""; i++) { // 将要赋值的td如果不为空,则再次随机td的index
slTd = randomTd()
}
slTd.innerText = i
slTd.classList.add("td-border")
}
}
因此开始游戏按钮中的函数直接执行上文两个函数即可
// 游戏开始
function gameStart() {
randomTd()
tdAssignment()
}
第二步
上文所说已经为td赋值了文本,接下来是定义td的点击事件
开始理思路:
1.给td 赋值的同时,添加点击事件
2.将td 赋的值和自身传给结果判断的函数中
即
slTd.onclick = function() { // 为每个td添加点击事件
gameResult(i, this)
}
3.定义一个点击次数的变量,初始为1,意为第一次点击
4.开始写判断结果的函数,很简单,得到传过来的参数 i ,将参数 i 和 count对比,如果是相同的,就隐藏对应的 td,并且将点击次数+1
// 点击后判断结果
function gameResult(index, obj) {
if (index == count) { // 判断td的值是否等于点击次数
obj.classList.add("hidden")
}
count++ // 每次点击完,点击次数+1
}
5.然后判断是否过关,即点击完所有数字,加一个判断,当参数 i == 等级时,就是正确点击了最后一个数字
顺便加上失败判断,以及切换结果页的函数goResult
// 点击后判断结果
function gameResult(index, obj) {
if (index == count) { // 判断td的值是否等于点击次数
obj.classList.add("hidden")
if (index == level - 1) {
// 胜利
isSuc = 1
goResult()
}
} else {
// 失败
isSuc = 0
tryCount++
goResult()
}
count++
}
6.开始第一次点击时,隐藏所有td ,采用遍历 td 将选中的td (判断其是否有边框即可) 为其添加一个新的class
加上level限制是为了第一次开始游戏时作为教程关卡不隐藏td
if (index == 1 && level > 6) { // 第一次点击时隐藏td(第一次开始游戏时不隐藏td)
for (let i of td) {
if (i.className == "td-border")
i.classList.add("td-shade")
}
}
第三步
结果页的效果如下图
都是一些简单的写入参数的操作,这里不赘述,结合上文定义一个尝试次数(tryCount),当尝试次数达到3次时改变按钮文本为重新开始即可
第四步
重置游戏/继续游戏(上图“继续”按钮的功能)
最后的功能完善,同时也需要配合完善上文函数中的细节
1.首先遍历每个td,清空其class、文本和点击事件
for (let i of td) { // 遍历td以重置td的class、文本和点击事件
i.classList.remove("td-border")
i.classList.remove("td-shade")
i.classList.remove("hidden")
i.innerText = ""
i.onclick = null // 清理td的点击事件
}
2.转到结果页面时,需要重置点击次数为1
3.判断尝试次数是否达到3次,如是,重置到开始页面;
如不是,根据是否胜利,胜利则加大难度/重置尝试次数 开始游戏,失败则保持当前难度继续 开始游戏
完整代码如下
// 重置游戏(继续/重新开始)
function gameReset(isCheater) {
for (let i of td) { // 遍历td以重置td的class、文本和点击事件
i.classList.remove("td-border")
i.classList.remove("td-shade")
i.classList.remove("hidden")
i.innerText = ""
i.onclick = null // 清理td的点击事件
}
count = 1 // 重置点击次数
if (tryCount == 3) { // 尝试次数达到最高次数
result.classList.add("hide")
cheater.classList.add("hide")
info.classList.remove("hide")
level = 6
tryCount = 0
} else {
if (isSuc == 1) { // 如果胜利
level++
tryCount = 0
gameStart()
} else
gameStart()
}
}