
在游戏开发中,我们通常会设置一个游戏循环(例如使用setinterval或requestanimationframe)来不断更新游戏状态和渲染画面。当需要根据游戏元素的位置或状态来触发某个事件(如得分)时,我们会在循环内部设置一个条件判断。
以马里奥跳跃管道的场景为例,当管道完全移出屏幕(pipePosition < 0)且马里奥处于跳跃状态(marioPosition >= 80)时,我们希望分数增加1。然而,由于setInterval每隔极短的时间(例如10毫秒)就会执行一次,如果满足得分条件的状态持续存在,scoreCount()函数会在条件持续满足的这段时间内被反复调用,导致分数在一次事件中多次累加,而非预期的单次加1。
原始代码片段中的问题在于:
const loop = setInterval(() => {
const pipePosition = pipe.offsetLeft;
const marioPosition = +window.getComputedStyle(mario).bottom.replace('px', '');
if (pipePosition < 0 && marioPosition >= 80) {
scoreCount(); // 问题所在:条件满足时,此函数会每10ms调用一次
}
// ... 其他游戏逻辑
}, 10)scoreCount()函数在setInterval的每次迭代中被调用,只要pipePosition < 0 && marioPosition >= 80这个条件为真,就会持续执行。
为了解决这种重复触发的问题,最常用的方法是引入一个布尔型状态标志(或称作“哨兵变量”)。这个标志用于记录某个事件是否已经处理过。
核心思想:
以下是应用状态标志后的JavaScript代码:
const mario = document.querySelector('.mario');
const pipe = document.querySelector('.pipe');
// 马里奥跳跃动画控制
const jump = () => {
mario.classList.add('jump');
setTimeout(() => {
mario.classList.remove('jump');
}, 500);
}
let score = 0;
// 引入状态标志:用于控制分数是否已在当前事件中增加
let scoreSet = false;
// 分数计算函数,现在加入了状态检查
function scoreCount() {
// 只有当scoreSet为false时,才允许增加分数
if (!scoreSet) {
score++; // 增加分数
scoreSet = true; // 设置标志为true,防止重复增加
}
document.querySelector('#score').innerHTML = `SCORE: ${score}`;
}
// 游戏主循环
const loop = setInterval(() => {
const pipePosition = pipe.offsetLeft;
const marioPosition = +window.getComputedStyle(mario).bottom.replace('px', '');
// 检查得分条件
if (pipePosition < 0 && marioPosition >= 80) {
scoreCount(); // 调用分数计算函数,它会自行处理重复问题
}
// 碰撞检测与游戏结束逻辑
// 当管道与马里奥碰撞时,游戏结束
if (pipePosition <= 120 && pipePosition > 0 && marioPosition < 80) {
pipe.style.animation = 'none';
pipe.style.left = `${pipePosition}px`;
mario.style.animation = 'none';
mario.style.bottom = `${marioPosition}px`;
mario.src = './marioImages/game-over.png';
mario.style.width = '75px';
mario.style.margin = '50px';
clearInterval(loop); // 清除游戏循环
}
}, 10); // 循环间隔10毫秒
// 监听键盘事件,触发跳跃
document.addEventListener('keydown', jump);
// 如果需要允许在后续事件中再次得分(例如通过下一个管道),
// 可以在适当的时机将 scoreSet 重置为 false。
// 例如,当一个管道完全通过并消失后,如果游戏有下一个管道出现,
// 可以在生成新管道时或者管道离开屏幕足够远时重置 scoreSet。
// 在这个马里奥跳跃管道的单次游戏中,通常在游戏结束前不会重置。HTML (mario.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">
<link rel="stylesheet" href="marioCSS/mario.css">
<script src="marioJS/mario.js" defer></script>
<title>Mario Jump</title>
</head>
<body>
<div class="game-board">
<h2 id="score">SCORE: 0</h2>
<img src="marioImages/clouds.png" class="clouds">
<img src="marioImages/mario.gif" class="mario">
<img src="marioImages/pipe.png" class="pipe">
</div>
</body>
</html>CSS (mario.css):
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#score {
font-family: 'Super Mario 256'; /* 确保字体文件路径正确 */
margin: 10px;
z-index: 3;
position: absolute; /* 使分数显示在游戏板上方 */
color: #fff; /* 示例:使分数更明显 */
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}
.game-board {
width: 100%;
max-width: 800px; /* 限制游戏板最大宽度 */
height: 500px;
border-bottom: 15px solid rgb(35, 160, 35);
margin: 0 auto;
position: relative;
overflow: hidden;
background: linear-gradient(#87CEEB, #E0F6FF);
}
.pipe {
position: absolute;
bottom: 0;
width: 80px;
animation: pipe-animation 1.5s infinite linear;
}
.mario {
position: absolute;
width: 150px;
bottom: 0;
z-index: 2;
}
.jump {
animation: jump 500ms ease-out;
}
.clouds {
position: absolute;
width: 500px;
animation: clouds-animation 4s infinite linear;
z-index: 1;
}
@keyframes pipe-animation {
from {
right: -80px;
}
to {
right: 100%; /* 管道从右侧移出到左侧 */
}
}
@keyframes jump {
0% {
bottom: 0;
}
40% {
bottom: 180px;
}
50% {
bottom: 180px;
}
60% {
bottom: 180px;
}
100% {
bottom: 0;
}
}
@keyframes clouds-animation {
from {
right: -500px;
}
to {
right: 100%;
}
}
/* 确保字体文件路径正确,例如:/marioFont/SuperMario256.ttf */
@font-face {
font-family: 'Super Mario 256';
src: url('/marioFont/SuperMario256.ttf');
}通过引入一个简单的布尔型状态标志,我们可以有效地解决在游戏循环中事件重复触发的问题,确保分数或其他游戏逻辑的精确执行。这种模式是游戏开发中常用的状态管理技巧,能够帮助开发者构建更稳定、更符合预期的游戏行为。理解并熟练运用这种模式,对于开发任何基于循环和条件判断的动态系统都非常有益。
以上就是精确控制游戏循环中的分数增量:基于状态标志的解决方案的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号