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

Phaser3结合Matterjs如何在函数外部访问Sprite属性

问题根源

MatterJS作为刚体物理引擎,和Arcade物理引擎的逻辑有本质区别:Matter默认会给所有刚体施加空气阻尼,同时会对长时间不受力的刚体触发睡眠机制来节省性能。你在create阶段或者非update时序里给刚体设置初始速度后,没有持续的速度输入,刚体会因为阻尼逐渐减速直到停止,甚至直接进入睡眠状态不再运动,这是引擎默认机制,不是代码逻辑错误。

你原有代码还存在两个容易触发报错的隐患:

  • 定义obstacle变量时未加let/const声明,变量会泄漏到全局作用域,很容易被其他逻辑覆盖,触发你遇到的Cannot read properties of undefined (reading 'setVelocityX')报错。
  • 使用原生setInterval做定时生成逻辑,不受Phaser游戏主时序控制,游戏切后台、暂停时定时器仍会运行,极易出现this指向错乱、对象生成时序不对的问题,应该替换为Phaser自带的时间事件API。
实现方案

根据需求二选一即可:

方案1:在update循环中统一设置组内障碍物速度(最稳定,推荐)

不需要在创建sprite时设置速度,直接在每帧update中遍历障碍物组统一赋值速度,完全规避刚体阻尼、睡眠带来的停止问题,也不需要单独维护每个sprite的引用。
首先修改create函数中的逻辑:

// create 函数内
this.obstacles = this.add.group();

const addObstacle = (x, y) => { 
    // 用const声明局部变量,避免全局污染
    const obstacle = this.matter.add.sprite(x, y, 'barrel').setScale(0.2);
    obstacle.setIgnoreGravity(true);
    // 标记障碍物类型,方便后续逻辑判断
    obstacle.setData('type', 'obstacle');
    this.obstacles.add(obstacle);
    // 创建时无需设置速度
}

let space = 7;
let vary = Phaser.Math.Between(800, 1000);

// 替换原生setInterval为Phaser内置时间事件
this.time.addEvent({
    delay: 5000,
    loop: true,
    callback: () => {
        for (let i = 0; i < 4; i++) {
            if (i != space && i != space + 1) { 
                addObstacle(this.scale.width + 400, i * 60 + vary);
            }
        }
        // 每次生成后重新随机缺口位置,避免缺口固定
        vary = Phaser.Math.Between(800, 1000);
    }
});

然后在update函数中添加速度设置逻辑:

update() {
    // 遍历所有存活的障碍物
    this.obstacles.getChildren().forEach(obstacle => {
        obstacle.setVelocityX(-30);
        // 可选:障碍物移出屏幕后自动销毁,避免内存占用过高
        if (obstacle.x < -obstacle.displayWidth) {
            obstacle.destroy();
        }
    });
}

这个方案完全遵循Phaser+Matter的运行时序,不会出现速度衰减、对象undefined的问题,稳定性最高。

方案2:修改刚体默认属性,单次设置速度即可持续运动

如果不想在update中写每帧逻辑,可以在创建刚体时关闭空气阻尼和自动睡眠机制,设置一次速度就可以让障碍物持续匀速运动:

const addObstacle = (x, y) => { 
    const obstacle = this.matter.add.sprite(x, y, 'barrel', {
        friction: 0,
        frictionAir: 0, // 关闭空气阻尼,速度不会衰减
        inertia: Infinity, // 禁止刚体碰撞后旋转
        sleepThreshold: Infinity // 关闭自动睡眠,刚体不会停止运动
    }).setScale(0.2);
    obstacle.setIgnoreGravity(true);
    this.obstacles.add(obstacle);
    obstacle.setVelocityX(-30);
}

这个方案代码更简洁,但修改了刚体的物理参数,如果后续需要障碍物参与碰撞交互,可能会出现碰撞效果不符合预期的问题,适合纯装饰、无复杂交互的障碍场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 23:33:21