整体思路
1.设置一个游戏界面main(最外面一圈方框)
2.main内部放置一个容器container,容器非常长,且容器底部位于main的顶部
3.将容器内的黑块和白块事先处理好,并将黑块存储在黑块数组中
容器黑白块处理:①生成一行的黑白块 ②遍历生成一整个容器的黑白块
4.点击开始按钮后,容器开始向下移动,使黑白块随之下落
容器超出main的部分均会被隐藏
5.点击黑块,黑块变白,并清除黑块数组中的值
6.当黑块数组中任意一个黑块触碰到mai底部时,游戏结束
补充:难度不同速度不同,对于速度的控制:
setInterval(moveContainerDown, 20);每隔20毫秒调用下落函数
下落函数里获取当前容器的top值(var top = parseInt(container.style.top) || initialTop;)
再更新容器的top值,使容器向下移动(container.style.top = top + speed + "px";)
改进
我是将所有的黑白块一开始就生成好放在容器里,容器高度设置非常高;
然后让容器整个往下降,超过main的部分隐藏,实现看起来下落的效果,但这样负担较大
理想中应该是容器内的每一行依次下降(而不是容器下降),
最底部一行越界消失,顶部则新增一行,但是我无法实现
完整代码
// bcbk.html<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>别踩白块</title><link rel="stylesheet" href="bcbk.css">
</head><body><audio id="audioPlayer"><source src="点击.mp3" type="audio/mpeg"></audio><div id="main"><div id="container"></div></div><div class="choose"><select id="difficulty"><option value="easy">初级</option><option value="medium">中级</option><option value="hard">高级</option></select><button id="startbt">开始游戏</button><div id="scoreDisplay">分数: 000</div></div><script src="bcbk.js"></script></body></html>
// bcbk.css* {margin: 0;padding: 0;font-size: 30px;border-collapse: collapse;/* 去除单元格之间的间隙 */box-sizing: border-box;/* 让边框宽度计入方块尺寸 */
}/* 最外面那层游戏框 */
#main {width: 400px;height: 450px;border: 1px solid black;margin: 0 auto;overflow: hidden;margin-top: 60px;position: relative;
}/* 所有的内部方块构成的整体容器 */
#container {width: 400px;position: absolute;
}/* 选择难度 和 开始按钮 的父盒子 */
.choose {display: flex;align-items: center;/* 子元素垂直居中 */justify-content: center;/* 子元素水平居中 */margin: 10px auto;width: 400px;height: 50px;font-size: 20px;
}/* 选择难度按钮 */
#difficulty {margin-right: 10px;
}/* 分数 */
#scoreDisplay {margin-left: 10px;
}/* 方块:默认白色 */
.cell {width: 100px;height: 100px;float: left;background-color: white;/* border: 0.1px solid black; */}/* 黑块 */
.cellblack {background-color: black;
}/* 白块 */
.cellbwhite {background-color: white;
}/* 黑块放大动画 */
@keyframes grow {0% {transform: scale(1);opacity: 1;/* 完全不透明 */}100% {transform: scale(1.4);/* 放大1.4倍数 */opacity: 0;/* 完全透明 */}
}
// bcbk.jsdocument.addEventListener('DOMContentLoaded', function () {//获取容器和主容器元素var container = document.getElementById("container");var main = document.getElementById("main");// 获取开始游戏按钮// var startButton = document.getElementById("startbt");var rowCount = 50;//方块行数var initialTop = -5000;// 初始位置距离页面顶部的高度=rowCount * cell.widthvar blackBlocks = [];//存储黑块的数组var gameStart = false;//游戏开始标志var intervalID;//定时器var score;//分数var scoreDisplay = document.getElementById("scoreDisplay");//分数显示var audioPlayer = document.getElementById("audioPlayer");//点击音效//------更新分数function updateScore() {score += 5; //点一次黑块加5分if (score < 10) {scoreDisplay.textContent = "分数: 00" + score;}else if (score < 100) {scoreDisplay.textContent = "分数: 0" + score;}else {scoreDisplay.textContent = "分数: " + score;}//最原始的方法保证分数是三位数,因为肯定玩不到1000分}//------点击开始游戏按钮,游戏开始document.getElementById("startbt").addEventListener("click", function () {startGame(); // 调用开始游戏函数});//------点击黑块则变白,并更新得分function clickBlackBlock() {if (this.classList.contains("cellblack")) {audioPlayer.play();//添加放大渐变消失动画this.style.animation = "grow 0.4s forwards";//将当前元素应用名为 "grow" 的动画,持续0.4秒,并且动画执行完毕后保持最终状态(不回到初始状态)this.classList.remove("cellblack");//移除该黑块// this.classList.add("cellwhite");//之前写的是把黑块变成白块,而不是移除黑块,会出现://黑块变白块后,再点击该白块,又变黑块,需要设置clicked棋子,很麻烦,还是直接移除的好var index = blackBlocks.indexOf(this);if (index !== -1) {blackBlocks.splice(index, 1);//清除 已点击黑块 在 blackBlocks中的索引}updateScore();//更新分数}}//------生成初始黑块的索引function generateInitialBlackIndices() {var indices = [];//存储黑块的索引位置var blackCount = Math.floor(Math.random() * 3 + 1);//黑块个数1-3(没有4,一行全黑太难了)for (var i = 0; i < blackCount; i++) {var index = Math.floor(Math.random() * 4);//黑块索引位置indices.push(index);}return indices;}//------生成一行黑白块(包含四个块,四个块里有随机个数的黑块)function createRow() {var row = document.createElement("div");//一行方块row.className = "row";//这行方块的类名叫rowvar init = generateInitialBlackIndices();//返回包含了随机生成的初始黑块索引的数组for (var i = 0; i < 4; i++) {//一行内的四个方块迭代var cell = document.createElement("div");//小方块cell.className = "cell";if (init.includes(i)) {// 是否为黑块索引cell.classList.add("cellblack");//是黑块索引,就变成黑块cell.addEventListener("click", clickBlackBlock);//点击黑块变白块blackBlocks.push(cell);//把黑块加到blackBlocks数组}row.appendChild(cell);//将创建的方块元素添加到当前行}return row;}//------生成所有黑白块function geneRows() {for (var i = 0; i < rowCount; i++) {container.appendChild(createRow());}console.log("已生成黑白块");}//------重置函数function resetGame() {// 清除容器中的所有方块元素container.innerHTML = '';score = 0;var diff = document.getElementById("difficulty");if (diff.value === "easy") {speed = 3;} else if (diff.value === "medium") {speed = 5;} else if (diff.value === "hard") {speed = 7;}console.log(speed);// 重新生成方块行geneRows();}//------开始游戏function startGame() {resetGame();// 将容器移动到初始位置container.style.top = initialTop + "px";//------方块下落、判断游戏结束function moveContainerDown() {// 获取当前容器的 top 值var top = parseInt(container.style.top) || initialTop;// 更新容器的 top 值,使容器向下移动container.style.top = top + speed + "px";//获取 main 的底部位置: main 元素顶部距离文档顶部的偏移量加上 main 元素自身的可见高var mainBottom = main.offsetTop + main.clientHeight;//遍历所有的黑块,任一黑块的底部>=main的底部,则游戏结束for (var i = 0; i < blackBlocks.length; i++) {if (blackBlocks[i].getBoundingClientRect().bottom >= mainBottom + 15) {//bla...tom 是黑块元素相对于浏览器窗口顶部的距离加上其自身的高度=黑块元素底部距离浏览器窗口顶部的距离//我也不知道为什么要+15,如果不+,那么黑块离底部还有一段距离的时候就会判断游戏结束gameOver();return; //结束函数,避免继续执行下面的代码}}}//一定要清除之前的定时器,否则速度会叠加,越来越快clearInterval(intervalID);//每隔20毫秒调用下落函数,实现容器持续向下移动intervalID = setInterval(moveContainerDown, 20);}//------游戏结束function gameOver() {gameStart = false;var restart = confirm("游戏结束!您的得分是:" + score + " 分。是否重新开始?");if (restart) {startGame();} else {alert("掰掰");}}});