You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在main.js中监测Head实例的CSS位置变化并执行对应操作?

解决实时碰撞检测问题:无需监听CSS变化,直接在代码逻辑中处理

你现在的问题核心不是没法获取Head的位置,而是碰撞检测代码只执行了一次——在页面加载完成的瞬间,之后Head每500ms移动一次,但没有再触发位置判断。而且完全不需要用jQuery监听CSS变化,因为位置变化是我们自己的代码主动触发的,直接在移动逻辑里加入检测更高效可靠。

问题分析

看你的main.js,这段碰撞检测代码只在$(document).ready()里运行了一次:

let position = head.node.position();
if (position.top === apple.randomTop && position.left === apple.randomLeft) {
  this.endGame();
}

而Head的位置是每隔500ms通过move()方法更新的,所以页面加载后的位置变化根本不会触发这段判断。

解决方案

有两种简单可靠的方式实现实时碰撞检测:

方案1:在Head的move()方法中加入碰撞检测

每次Head移动完成后,立刻检查是否和Apple位置重合。这种方式最直接,因为移动逻辑本身就控制着位置变化:

class Head {
  constructor($el, apple) {
    this.node = $('<div id="head"></div>');
    this.currentDirection = 'right';
    this.SPEED = 500;
    this.apple = apple; // 接收传入的apple实例
    $el.append(this.node);
    this.node.css({ top: 0, left: 0 });
    this.toBeCleared = setTimeout(this.move.bind(this), this.SPEED);
  }

  move() {
    let direction = this.currentDirection;
    let position = this.node.position();
    
    // 原边界检测逻辑不变
    if (position.left === 700 || position.top === 700 || position.left === -50 || position.top === -50) {
      console.log('Game Over');
      this.endGame();
    }

    // 更新位置逻辑不变
    if (direction === 'right') {
      position.left += 50;
    } else if (direction === 'left') {
      position.left -= 50;
    } else if (direction === 'up') {
      position.top -= 50;
    } else if (direction === 'down') {
      position.top += 50;
    }
    this.node.css(position);
    
    // 新增:碰撞检测
    if (position.top === this.apple.randomTop && position.left === this.apple.randomLeft) {
      this.endGame();
    }
    
    this.toBeCleared = setTimeout(this.move.bind(this), this.SPEED);
  }

  endGame() {
    console.log('game has ended')
    clearTimeout(this.toBeCleared); // 修复:加上this访问实例属性
  }
}

然后在main.js初始化时把apple传给Head:

$(document).ready(function() {
  const apple = new Apple($('#board'));
  const head = new Head($('#board'), apple); // 传入apple实例
  
  // 原键盘事件逻辑不变
  $('body').on('keydown', function(e) {
    if (e.keyCode === 37) {
      console.log('pressed left');
      head.currentDirection = 'left';
    } else if (e.keyCode === 39) {
      console.log('pressed right');
      head.currentDirection = 'right';
    } else if (e.keyCode === 38) {
      console.log('pressed up');
      head.currentDirection = 'up';
    } else if (e.keyCode === 40) {
      console.log('pressed down');
      head.currentDirection = 'down';
    }
  });
});

方案2:在main.js中设置定时检测

如果不想修改Head类的结构,可以在main.js里设置一个和Head移动速度一致的定时器,每隔500ms检查一次位置:

$(document).ready(function() {
  const head = new Head($('#board'));
  const apple = new Apple($('#board'));
  
  // 原键盘事件逻辑不变
  $('body').on('keydown', function(e) {
    // ... 原代码不变
  });
  
  // 新增定时检测
  const checkCollision = setInterval(() => {
    let position = head.node.position();
    if (position.top === apple.randomTop && position.left === apple.randomLeft) {
      head.endGame();
      clearInterval(checkCollision); // 碰撞后清除定时器
    }
  }, 500); // 和Head的移动速度保持一致
});

这种方式不需要修改Head类,但要记得在游戏结束时清除定时器,避免不必要的后台执行。

额外修复:endGame方法的bug

你的endGame()方法里clearTimeout(toBeCleared)会报错,因为toBeCleared是Head实例的属性,必须用this.toBeCleared来访问,已经在方案1里修复了这个问题。

为什么不推荐监听CSS变化?

监听DOM的CSS变化(比如用MutationObserver或者jQuery的老方法)属于被动监听,不仅效率低,而且容易出现延迟或者不必要的触发。既然我们的代码主动控制着Head的移动,直接在移动逻辑中加入检测是最简洁、高效的方案。

内容的提问来源于stack exchange,提问作者tryingCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 07:22:42