Flappy Bird管道动画克隆后随机间隙失效问题及解决问询
多组Flappy Bird管道随机间隙失效的原因与修复方案
问题原因
- ID重复导致操作仅作用于原元素:你克隆的所有管道和间隙都沿用了原元素的
id="block"和id="hole",但DOM中ID必须唯一,getElementById只会返回第一个匹配的元素。后续的事件绑定和样式修改都只影响了最初的那个管道和间隙,克隆出来的完全没被处理。 - 克隆结构错误:你把克隆的block append到原block内部,导致管道嵌套在一起,而不是并排生成。正确的做法应该是把每个克隆的管道添加到
#blokhold容器中,和原管道同级。 - 间隙克隆与事件绑定逻辑混乱:代码里克隆hole后,却把原hole重复append到容器里,根本没用到克隆的holeClone;而且事件监听器只绑在了原hole上,克隆的间隙没有触发随机位置的逻辑。
- 动画未做差异化处理:所有管道用了相同的动画,没有延迟,会导致它们完全重叠,看起来像一个管道,自然看不出间隙差异。
修复方案与代码实现
1. 调整HTML结构(改用类名)
把原ID改为类名,避免重复:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div id="game"> <div id="blokhold"> <div class="block"> <div class="hole"></div> </div> </div> <div id="character"></div> </div>
2. 修改CSS(适配类选择器)
把原ID选择器改为类选择器,并调整管道初始位置:
body { text-align: center; position: fixed; width: 100%; height: 100%; } * { padding: 0; margin: 0; } #game { width: 100%; height: 500px; border: 1px solid red; margin: auto; overflow: hidden; } /* 管道改为类选择器 */ .block { width: 60px; height: 500px; background-color: green; background-image: url("https://l.dropbox.com/s/4jz7uq4e25o8su5/sketch-1664244879.png?dl=0"); background-size: cover; position: absolute; left: 100px; animation: block 5s infinite linear; } /* 间隙改为类选择器 */ .hole { width: 60px; height: 210px; background-color: red; position: absolute; left: 0px; background-image: url("https://dldropbox.com/s/j7enawgtuepj7au/sketch-166428805830.png?dl=0"); background-size: cover; } #character { width: 40px; height: 40px; background-color: red; position: absolute; top: 100px; left: 40px; z-index: 1; } #overlay { position: fixed; display: none; width: 100%; height: 100%; top: 0; left: 0; right: 0; bottom: 0; background-color: black; cursor: none; opacity: 0.3; text-align: center; } .mainoverlay { position: fixed; display: block; width: 100%; height: 100%; top: 0; left: 0; right: 0; bottom: 0; cursor: none; opacity: 0; } @keyframes block { 0% { left: 100%; /* 从右侧进入 */ } 100% { left: -60px; /* 完全移出左侧 */ } }
3. 修正JavaScript逻辑
正确克隆管道、绑定事件、设置动画延迟:
const blokhold = document.getElementById("blokhold"); const originalBlock = document.querySelector(".block"); const pipeCount = 4; // 总共生成的管道数 for (let i = 0; i < pipeCount; i++) { let blockClone; if (i === 0) { // 第一个用原管道 blockClone = originalBlock; } else { // 后续克隆新管道 blockClone = originalBlock.cloneNode(true); blokhold.appendChild(blockClone); } // 设置动画延迟,避免管道重叠 blockClone.style.animationDelay = `${i * 1.5}s`; // 获取当前管道的间隙 const hole = blockClone.querySelector(".hole"); // 初始化随机位置 setRandomHolePosition(hole); // 绑定动画循环事件,每次循环重置间隙位置 blockClone.addEventListener('animationiteration', () => { setRandomHolePosition(hole); }); } // 封装随机位置函数 function setRandomHolePosition(hole) { const randomTop = -((Math.random() * 300) + 150); hole.style.top = `${randomTop}px`; }
关键改进点
- 用类名替代ID,解决DOM元素选择冲突
- 管道挂载到
#blokhold容器,保持正确的同级结构 - 为每个管道的间隙独立绑定随机位置逻辑
- 添加动画延迟,让管道按顺序生成,视觉上更合理
内容的提问来源于stack exchange,提问作者Hi there
相关产品推荐
相关产品推荐

