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

如何让PixiJS中交互容器移到指针下时触发mouseover事件?

问题

开发PixiJS 8.1.1游戏时碰到个交互问题:

  • 原本逻辑是靠mouseover事件记录选中的瓦片,点击后平台移动到选中的瓦片位置
  • 但平台移动时,要是新的可点击瓦片滑到静止的鼠标指针下方,mouseover事件不会自动触发
  • 不想用“移动后手动把屏幕坐标转成瓦片坐标”的方案,想找更简便的触发方式

附示例代码:矩形悬停会变绿,点击后会滑向屏幕左侧,要是指针不动,矩形滑到指针下方时不会触发mouseover

const { Application, Container, Assets, Sprite, Graphics, RenderTexture, GraphicsContext } = PIXI;

const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
let app, renderer, platform;

const trailGraphics = new Graphics();

window.onload = async () => {
  renderer = await PIXI.autoDetectRenderer({});
  const app = new Application();
  await app.init({ background: '#9cc3ff', width: windowWidth, height: windowHeight, antialias: true, autoDensity: true, resolution: window.devicePixelRatio });
  document.body.appendChild(app.canvas);

  const g = new Graphics()
    .beginFill(`#ff0000`)
    .drawRect(0, 0, 300, 200)
    .endFill();
  const container = new Container();
  container.interactive = true;
  container.buttonMode = true;
  container.x = 0;
  container.y = 0;
  container.addChild(g);
  app.stage.addChild(container);

  container.addListener(`mouseover`, function () {
    this.tint = `#00ff00`;
  });
  container.addListener(`mouseout`, function () {
    this.tint = `#ff0000`;
  });
  container.addListener(`click`, function () {
    container.x = 500;
    this.tint = `#ff0000`;
  });

  app.ticker.add(time => {
    if (container.x > 0) {
      container.x -= 5;
    }
  });
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/8.1.1/pixi.min.js"></script>

解决方案

方法1:主动触发交互检测(推荐)

利用PixiJS内置的交互插件,在每帧或平台移动完成后,手动检测鼠标位置下的交互元素,然后触发对应的mouseover/mouseout事件,不用自己转坐标。

修改后的代码示例:

const { Application, Container, Graphics } = PIXI;

const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
let app, currentHoveredElement = null;

window.onload = async () => {
  const app = new Application();
  await app.init({ background: '#9cc3ff', width: windowWidth, height: windowHeight, antialias: true, autoDensity: true, resolution: window.devicePixelRatio });
  document.body.appendChild(app.canvas);

  const g = new Graphics()
    .beginFill(`#ff0000`)
    .drawRect(0, 0, 300, 200)
    .endFill();
  const container = new Container();
  container.interactive = true;
  container.buttonMode = true;
  container.x = 0;
  container.y = 0;
  container.addChild(g);
  app.stage.addChild(container);

  // 保留原事件监听
  container.addListener(`mouseover`, function () {
    this.tint = `#00ff00`;
    currentHoveredElement = this;
  });
  container.addListener(`mouseout`, function () {
    this.tint = `#ff0000`;
    currentHoveredElement = null;
  });
  container.addListener(`click`, function () {
    container.x = 500;
    this.tint = `#ff0000`;
    currentHoveredElement = null;
  });

  // 获取交互插件实例
  const interaction = app.renderer.plugins.interaction;
  
  app.ticker.add(() => {
    if (container.x > 0) {
      container.x -= 5;
    }

    // 手动检测当前鼠标位置的交互元素
    const mousePos = interaction.pointer.global;
    // 从舞台开始检测,拿到最顶层的交互元素
    const hitElement = interaction.hitTest(mousePos, app.stage);

    // 对比当前悬停元素和检测到的元素,触发对应事件
    if (hitElement !== currentHoveredElement) {
      if (currentHoveredElement) {
        currentHoveredElement.emit('mouseout');
      }
      if (hitElement) {
        hitElement.emit('mouseover');
      }
    }
  });
};

方法2:平台移动完成后一次性检测

如果平台是一次性移动到位(不是逐帧滑动),可以不用每帧检测,只在平台移动完成后执行一次检测逻辑,性能更好。

比如在判断平台停止移动时执行:

// 加入到ticker的回调中
if (container.x <= 0) {
  // 平台停止移动,执行一次检测
  const mousePos = interaction.pointer.global;
  const hitElement = interaction.hitTest(mousePos, app.stage);
  if (hitElement) {
    hitElement.emit('mouseover');
  }
}

内容的提问来源于stack exchange,提问作者phil-daniels

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:52:14