CSS关键帧动画执行时调用JS函数检测游戏角色碰撞问题
解决敌人碰撞检测的时机与逻辑问题
首先,咱们先说说你当前代码里的两个核心问题:碰撞检测逻辑太严格和检测时机太稀疏,这俩加起来就是你碰不到碰撞触发的主要原因。
1. 先修复碰撞检测逻辑
你现在用==来判断位置,这在连续动画里几乎不可能触发——敌人是平滑移动的,刚好让$("#enemy").position().top + $("#enemy").height()等于玩家top的瞬间太罕见了。而且你只检测了垂直方向,完全没考虑水平方向的重叠,就算垂直位置对上了,敌人在别的车道也不算碰撞啊!
咱们把碰撞检测改成范围判断,同时覆盖水平和垂直两个方向:
function checkCollision() { const enemy = $("#enemy"); const player = $("#player"); const enemyPos = enemy.position(); const enemyWidth = enemy.width(); const enemyHeight = enemy.height(); const enemyBottom = enemyPos.top + enemyHeight; const enemyRight = enemyPos.left + enemyWidth; const playerPos = player.position(); const playerWidth = player.width(); const playerHeight = player.height(); const playerBottom = playerPos.top + playerHeight; const playerRight = playerPos.left + playerWidth; // 碰撞条件:两个元素在水平和垂直方向都有重叠区域 const verticalOverlap = enemyBottom > playerPos.top && enemyPos.top < playerBottom; const horizontalOverlap = enemyRight > playerPos.left && enemyPos.left < playerRight; if (verticalOverlap && horizontalOverlap) { console.log("碰撞发生了!"); // 这里可以加碰撞后的逻辑,比如游戏结束、扣分、播放音效等 } }
2. 选择正确的检测时机
你之前只在每2秒切换动画的时候检测一次,这中间敌人一直在移动,大部分碰撞瞬间都会被漏掉。咱们有两个更合适的选择:
选项A:用requestAnimationFrame(推荐)
这是浏览器专门为动画/实时交互设计的API,会在浏览器每次重绘前执行,性能更好,能保证每帧都检测一次:
// 定义循环检测函数 function collisionDetectionLoop() { checkCollision(); // 递归调用自己,保持持续检测 requestAnimationFrame(collisionDetectionLoop); } // 在页面加载完成后启动循环 $(document).ready(function() { // ... 你原来的其他代码 ... // 启动碰撞检测循环 collisionDetectionLoop(); });
选项B:用短间隔的setInterval
如果觉得requestAnimationFrame不好理解,也可以用16ms左右的间隔(接近60帧的刷新率):
$(document).ready(function() { // ... 你原来的其他代码 ... // 每16ms检测一次,接近屏幕刷新率 setInterval(checkCollision, 16); });
3. 整合到你的现有代码里
把上面的checkCollision函数放到你的myScript.js里,然后启动检测循环就行。另外,你原来myTimer里的碰撞判断可以删掉了,因为我们已经在持续检测了。
修改后的完整JS代码大概是这样:
$(document).ready(function() { //posiziona macchina in fondo al container $('#player').css("top", ($("#container").height() - $("#player").height() + "px")); var verticalSteps = "159.475"; var horizontalSteps = "300"; $('#music').prop("muted", false); $('#music').prop("loop", true); $(document).keydown(function() { $("#music")[0].play(); }) $(document).keydown(function(e) { // ... 你原来的键盘控制代码保持不变 ... }) // 碰撞检测函数 function checkCollision() { const enemy = $("#enemy"); const player = $("#player"); const enemyPos = enemy.position(); const enemyWidth = enemy.width(); const enemyHeight = enemy.height(); const enemyBottom = enemyPos.top + enemyHeight; const enemyRight = enemyPos.left + enemyWidth; const playerPos = player.position(); const playerWidth = player.width(); const playerHeight = player.height(); const playerBottom = playerPos.top + playerHeight; const playerRight = playerPos.left + playerWidth; const verticalOverlap = enemyBottom > playerPos.top && enemyPos.top < playerBottom; const horizontalOverlap = enemyRight > playerPos.left && enemyPos.left < playerRight; if (verticalOverlap && horizontalOverlap) { console.log("碰撞发生了!"); // 这里添加碰撞后的处理逻辑 } } // 启动碰撞检测循环 function collisionDetectionLoop() { checkCollision(); requestAnimationFrame(collisionDetectionLoop); } collisionDetectionLoop(); var imagesArray = ["images/240z.png", "images/civicSi.png", "images/porsche.png", "images/r32.png", "images/s2000.png"]; function myTimer() { toggleAnimation(); $("#enemy").attr("src", imagesArray[(Math.floor(Math.random() * imagesArray.length))]); } var myVar = setInterval(myTimer, 2000); function toggleAnimation() { // ... 你原来的切换动画代码保持不变 ... } })
额外小提示
- 如果你担心
requestAnimationFrame在页面隐藏时还在运行,可以加个判断,或者用cancelAnimationFrame在需要的时候停止检测。 - 可以给碰撞检测加个小“缓冲”,比如稍微缩小一点检测范围,避免边缘的误触,或者根据你的游戏手感调整参数。
内容的提问来源于stack exchange,提问作者ripperoni ripperoni
相关产品推荐
相关产品推荐

