mcpField
P
physics-arcade

physics-arcade

github.com/phaserjs开发40.6k877 次安装10 周前更新
代码仓库

关于 physics-arcade

面向 Phaser 4 游戏开发者的 Arcade Physics 技能,涵盖物理体、运动、重力、碰撞、世界边界和碰撞筛选。

主要功能

  1. 01创建动态和静态物理体
  2. 02设置速度、加速度和重力
  3. 03注册碰撞与重叠检测
  4. 04配置世界边界和物理体形状
  5. 05用类别和掩码筛选碰撞
  6. 06暂停并配置物理世界

适用场景

  1. 01为玩家角色添加物理运动
  2. 02设置平台及可收集物的重叠检测
  3. 03将物理体限制在世界边界内
  4. 04选择允许相互碰撞的物理体类别

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/phaserjs/phaser --skill physics-arcade

安装后在 Claude Code 中输入/physics-arcade确认已加载。

详细介绍

Arcade Physics

在 Phaser 4 中设置和使用 Arcade Physics —— 在 GameConfig 中启用物理、创建启用物理的 sprite/image/group、速度、加速度、重力、碰撞(collide/overlap)、世界边界、body 属性以及碰撞分类。

关键源路径: src/physics/arcade/ArcadePhysics.js、src/physics/arcade/World.js、src/physics/arcade/Body.js、src/physics/arcade/StaticBody.js、src/physics/arcade/Factory.js、src/physics/arcade/components/、src/physics/arcade/events/ 相关技能: ../game-setup-and-config/SKILL.md、../sprites-and-images/SKILL.md、../tilemaps/SKILL.md、../groups-and-containers/SKILL.md

快速开始

class GameScene extends Phaser.Scene {
    create() {
        // Physics sprite (dynamic body, affected by gravity)
        this.player = this.physics.add.sprite(100, 300, 'player');
        this.player.setCollideWorldBounds(true);
        this.player.setBounce(0.2);

        // Static group (immovable platforms)
        this.platforms = this.physics.add.staticGroup();
        this.platforms.create(400, 568, 'ground').setScale(2).refreshBody();

        // Register a persistent collider (checked every frame automatically)
        this.physics.add.collider(this.player, this.platforms);

        this.cursors = this.input.keyboard.createCursorKeys();
    }

    update() {
        if (this.cursors.left.isDown) {
            this.player.setVelocityX(-160);
        } else if (this.cursors.right.isDown) {
            this.player.setVelocityX(160);
        } else {
            this.player.setVelocityX(0);
        }
    }
}

// Enable Arcade Physics in game config
const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: 300 },
            debug: false
        }
    },
    scene: GameScene
};

const game = new Phaser.Game(config);

核心概念

World(this.physics.world)

Phaser.Physics.Arcade.World 管理模拟中的所有 body。在 Scene 中通过 this.physics.world 访问。

  • gravity -- 每个步进应用于所有动态 body 的 Vector2。可通过配置或 this.physics.world.gravity.y = 300 设置。
  • bounds -- 定义世界边界的 Rectangle。默认值为游戏画布尺寸。
  • bodies -- 所有动态 Body 实例的 Set。
  • staticBodies -- 所有 StaticBody 实例的 Set。
  • colliders -- 已注册的 Collider 对象的 ProcessQueue(来自 this.physics.add.collider / this.physics.add.overlap)。
  • fps -- 每秒物理步进数(默认 60)。只读;可通过 world.setFPS(120) 更改。
  • fixedStep -- true(默认)使用固定时间步长;false 则同步到渲染 fps。
  • timeScale -- 缩放因子:1.0 = 正常,2.0 = 半速,0.5 = 双倍速度。
  • isPaused -- 为 true 时,不更新任何 body,也不运行任何 collider。可通过 world.pause() / world.resume() 切换。
  • useTree -- true(默认)对动态 body 使用 RTree 空间索引。对于 5000+ 个 body,请禁用。
  • drawDebug -- 为 true 时启用调试渲染。可通过配置 debug: true 设置。
Body(Body)

当你使用 this.physics.add.sprite() 或 this.physics.add.image() 时,会自动创建一个动态 body。可通过 gameObject.body 访问它。

关键属性(全部位于 Body 上):

  • velocity -- Vector2,像素/秒
  • acceleration -- Vector2,像素/秒^2
  • drag -- Vector2,减速度(仅在加速度为零时应用)
  • gravity -- Vector2,每个 body 的重力,会叠加到世界重力上
  • bounce -- Vector2,相对于 1 的回弹系数
  • friction -- Vector2,默认 (1, 0) -- 不可移动 body 传递给其上承载 body 的速度
  • maxVelocity -- Vector2,默认 (10000, 10000) | maxSpeed -- 标量上限,默认 -1(无)
  • mass -- 默认 1,影响碰撞动量交换
  • immovable -- false;若为 true,则永远不会被碰撞移动
  • pushable -- true;若为 false,则将速度反射给碰撞的 body
  • moves -- true;若为 false,则位置/旋转不会由物理更新
  • enable -- true;false 会将其从模拟中移除
  • useDamping -- false;为 true 时,drag 是乘数(0-1)而非线性值
  • collideWorldBounds -- false;onWorldBounds/onCollide/onOverlap -- false,设为 true 以发出事件

形状:isCircle(通过 setCircle 设置)、width/height、offset(Vector2)、center(只读中点)。

碰撞状态(只读,每个步进重置):touching / blocked / wasTouching -- { none, up, down, left, right }。embedded -- 两者重叠且速度为零。

角度:angularVelocity(度/秒)、angularAcceleration、angularDrag、maxAngular(默认 1000)、allowRotation(默认 true)。

静态刚体(StaticBody)

静态刚体永不移动,也不受重力或速度影响。它使用优化的 RTree 实现快速空间查询。

  • 通过 this.physics.add.staticSprite()、this.physics.add.staticImage() 或 this.physics.add.staticGroup() 创建。
  • 在更改父游戏对象的位置或缩放后,调用 body.reset() 或 gameObject.refreshBody() 进行同步。
  • 与动态刚体一样具有 collisionCategory 和 collisionMask。
  • 没有速度、加速度、阻力或重力属性。

常见模式

在现有游戏对象上启用物理
// Add a physics body to any existing Game Object
this.physics.add.existing(mySprite);           // dynamic body
this.physics.add.existing(mySprite, true);     // static body

// Or enable via the world directly
this.physics.world.enable(mySprite);           // dynamic
this.physics.world.enable(mySprite, Phaser.Physics.Arcade.STATIC_BODY);
创建物理精灵和图像
// Via the physics factory (this.physics.add)
const player = this.physics.add.sprite(100, 200, 'player');     // dynamic body
const coin = this.physics.add.image(300, 100, 'coin');          // dynamic body
const wall = this.physics.add.staticImage(400, 300, 'wall');    // static body
const platform = this.physics.add.staticSprite(400, 500, 'plat'); // static body

// Standalone bodies (no Game Object)
const sensor = this.physics.add.body(200, 200, 32, 32);        // dynamic Body
const zone = this.physics.add.staticBody(100, 100, 64, 64);    // static Body
速度和重力
// Direct velocity
player.setVelocity(200, -300);          // x=200 px/s, y=-300 px/s (upward)
player.setVelocityX(200);
player.body.velocity.set(200, -300);    // equivalent via Vector2

// Acceleration + max velocity
player.setAcceleration(100, 0);
player.setMaxVelocity(300, 600);

// Per-body gravity (added to world gravity)
player.body.gravity.y = 200;
player.body.allowGravity = false;       // exempt from world gravity

// Drag (applied only when acceleration is zero)
player.setDrag(300);                    // linear deceleration
player.body.useDamping = true;
player.setDrag(0.05);                   // damping mode: keeps 5% velocity/sec

// Bounce
player.setBounce(0.5);                  // both axes
player.setBounceY(1);                   // full vertical bounce
碰撞和重叠

两种方式:持久碰撞器(每帧自动检查)或一次性检查(在 update() 中调用)。

// --- Persistent Colliders (preferred) ---
// Created via this.physics.add.collider / this.physics.add.overlap
// Automatically checked every physics step

const collider = this.physics.add.collider(player, platforms);
const overlap = this.physics.add.overlap(player, coins, collectCoin, null, this);

function collectCoin (player, coin) {
    coin.disableBody(true, true); // disable physics and hide
}

// Collider management
collider.active = false;   // temporarily disable
collider.destroy();        // remove permanently

// With processCallback (must return boolean to allow collision)
this.physics.add.collider(player, enemies, onHit, canCollide, this);
function canCollide (player, enemy) {
    return !player.getData('invincible');
}

// --- One-shot checks (in update) ---
// Called manually each frame; no Collider object created

this.physics.collide(player, platforms);
this.physics.overlap(player, coins, collectCoin, null, this);

// Self-collision within a single group
this.physics.add.collider(enemies, enemies);
组
// Dynamic physics group -- members get dynamic bodies automatically
const bullets = this.physics.add.group({
    classType: Phaser.Physics.Arcade.Sprite,  // default: ArcadeSprite
    maxSize: 20,
    collideWorldBounds: true,
    bounceX: 1,
    bounceY: 1,
    velocityX: 200,
    velocityY: 0,
    allowGravity: false,
    immovable: false
});

// Static physics group -- members get static bodies
const platforms = this.physics.add.staticGroup();
platforms.create(400, 568, 'ground');
platforms.create(600, 400, 'ground');

// After modifying a static group member's transform, refresh:
platforms.create(400, 568, 'ground').setScale(2).refreshBody();

// Group velocity helpers
bullets.setVelocity(200, 0);       // all members
bullets.setVelocityX(200);
bullets.setVelocityY(0, 10);       // with step increment per member

PhysicsGroup 配置键(作为新成员的默认值应用):collideWorldBounds、bounceX/Y、accelerationX/Y、dragX/Y、gravityX/Y、frictionX/Y、velocityX/Y、angularVelocity、angularAcceleration、angularDrag、maxVelocityX/Y、maxSpeed、mass、immovable、allowDrag、allowGravity、allowRotation、useDamping、enable。

世界边界
// Set bounds size and which edges collide (left, right, up, down)
this.physics.world.setBounds(0, 0, 1600, 1200, true, true, false, true);
this.physics.world.setBoundsCollision(true, true, false, true); // edges only

// Per-body world bounds
player.setCollideWorldBounds(true);
player.body.setBoundsRectangle(new Phaser.Geom.Rectangle(100, 100, 600, 400));
player.body.worldBounce = new Phaser.Math.Vector2(0.5, 0.5);

// Detect world bounds hit via event (requires opt-in)
player.body.onWorldBounds = true;
this.physics.world.on('worldbounds', (body, up, down, left, right) => {
    console.log('Hit edge:', { up, down, left, right });
});
刚体属性
// Size and shape
player.body.setSize(24, 32, true);     // width, height, re-center on GO
player.body.setOffset(4, 0);           // offset from GO position
player.body.setCircle(16);             // circular body, radius 16
player.body.setCircle(16, 4, 4);       // circular with offset

// Collision behavior
player.body.setImmovable(true);        // not moved by collisions
player.body.setPushable(false);        // reflects velocity to collider
player.body.slideFactor.set(0, 0);     // Sokoban-style: stops after push
player.body.setMass(2);               // affects momentum exchange

// Enable / disable
player.disableBody(true, true);        // disable body + hide Game Object
player.enableBody(true, x, y, true, true); // re-enable at position + show

// Per-direction collision check
player.body.checkCollision.up = false; // don't collide from above
player.body.syncBounds = true;         // auto-sync size to texture
碰撞类别

碰撞类别让你可以使用位掩码值过滤哪些刚体可以相互碰撞。最多 32 个类别。

// Get unique category values from the physics plugin
const CAT_PLAYER = this.physics.nextCategory();   // 0x0002
const CAT_ENEMY  = this.physics.nextCategory();   // 0x0004
const CAT_BULLET = this.physics.nextCategory();   // 0x0008

// Assign categories to bodies or groups
player.setCollisionCategory(CAT_PLAYER);
enemy.setCollisionCategory(CAT_ENEMY);
bullet.setCollisionCategory(CAT_BULLET);

// Set what each body collides with
player.setCollidesWith([CAT_ENEMY]);              // player hits enemies only
enemy.setCollidesWith([CAT_PLAYER, CAT_BULLET]);  // enemies hit player + bullets
bullet.setCollidesWith([CAT_ENEMY]);              // bullets hit enemies only

// Add/remove individual categories from existing mask
player.addCollidesWith(CAT_BULLET);
player.removeCollidesWith(CAT_ENEMY);

// Check if a body will collide with a category
player.willCollideWith(CAT_ENEMY); // returns boolean

// Reset to default (collides with everything)
player.resetCollisionCategory();

// Works on Groups too
enemies.setCollisionCategory(CAT_ENEMY);
enemies.setCollidesWith([CAT_PLAYER, CAT_BULLET]);

默认:所有刚体的类别为 0x0001,collisionMask 为 1。一切仍然与一切碰撞,因为 (1 & 1) !== 0。PhysicsGroup 默认掩码为 2147483647(所有位)。在更改类别后,调用 resetCollisionCategory() 将掩码设置为所有位。

配置参考

ArcadeWorldConfig -- 通过 GameConfig 或 SceneConfig 中的 physics.arcade 传入:

属性默认值描述
fps60每秒物理步数
fixedSteptrue使用固定时间步长 vs 渲染同步
timeScale1模拟速度倍数
gravity{ x: 0, y: 0 }世界重力,单位为 px/sec
x, y0世界边界原点
width, height游戏尺寸世界边界尺寸
checkCollision全部 true{ up, down, left, right } 边缘碰撞
overlapBias4分离的重叠阈值
tileBias16瓦片重叠阈值
forceXfalse先水平分离
isPausedfalse启动时暂停模拟
debugfalse启用调试渲染
debugShowBody / debugShowStaticBody / debugShowVelocitytrue调试显示开关
debugBodyColor / debugStaticBodyColor / debugVelocityColor0xff00ff / 0x0000ff / 0x00ff00调试颜色
maxEntries16每个节点的 RTree 项数
useTreetrue对动态刚体使用 RTree
customUpdatefalse如果为 true,自行调用 world.update()

场景级配置会覆盖游戏级配置(合并)。

事件

所有事件都在 this.physics.world 上触发:

事件字符串条件回调参数
COLLIDE'collide'两个刚体碰撞且至少一个具有 onCollide = true(gameObject1, gameObject2, body1, body2)
OVERLAP'overlap'两个刚体重叠且至少一个具有 onOverlap = true(gameObject1, gameObject2, body1, body2)
WORLD_BOUNDS'worldbounds'刚体碰到世界边缘且具有 onWorldBounds = true(body, up, down, left, right)
TILE_COLLIDE'tilecollide'刚体与瓦片碰撞(gameObject, tile, body)
TILE_OVERLAP'tileoverlap'刚体与瓦片重叠(gameObject, tile, body)
WORLD_STEP'worldstep'每次物理步之后(delta)
PAUSE'pause'世界暂停无
RESUME'resume'世界恢复无

事件需要按刚体选择性启用:将 body.onCollide、body.onOverlap 或 body.onWorldBounds 设置为 true。

API 快速参考

场景插件(this.physics)
方法描述
this.physics.add.sprite(x, y, key, frame)创建带动态刚体的 sprite
this.physics.add.image(x, y, key, frame)创建带动态刚体的 image
this.physics.add.staticSprite(x, y, key, frame)带静态刚体的 Sprite
this.physics.add.staticImage(x, y, key, frame)带静态刚体的 Image
this.physics.add.group(config)动态物理组
this.physics.add.staticGroup(config)静态物理组
this.physics.add.existing(go, isStatic?)为现有 Game Object 添加刚体
this.physics.add.body(x, y, w?, h?)独立的动态 Body(无 GO)
this.physics.add.staticBody(x, y, w?, h?)独立的静态 Body(无 GO)
this.physics.add.collider(a, b, cb?, proc?, ctx?)持久碰撞器
this.physics.add.overlap(a, b, cb?, proc?, ctx?)持久重叠检测
this.physics.collide(a, b, cb?, proc?, ctx?)一次性碰撞检测
this.physics.overlap(a, b, cb?, proc?, ctx?)一次性重叠检测
this.physics.nextCategory()下一个碰撞类别位掩码
this.physics.pause() / resume()暂停/恢复模拟
this.physics.accelerateTo(go, x, y, spd?, maxX?, maxY?)向目标点加速
this.physics.moveTo(go, x, y, spd?, maxTime?)以指定速度向目标点移动
this.physics.velocityFromAngle(angle, speed?, vec2?)角度(度)转速度
this.physics.velocityFromRotation(rot, speed?, vec2?)旋转(弧度)转速度
this.physics.closest(source, targets?)查找最近的刚体
this.physics.furthest(source, targets?)查找最远的刚体
this.physics.overlapRect(x, y, w, h, dyn?, static?)查询矩形范围内的刚体
this.physics.overlapCirc(x, y, r, dyn?, static?)查询圆形范围内的刚体

此外还有:accelerateToObject、moveToObject、collideTiles、overlapTiles、enableUpdate、disableUpdate。

世界(this.physics.world)
方法描述
setBounds(x, y, w, h, left?, right?, up?, down?)设置边界 + 边缘检测
setBoundsCollision(left?, right?, up?, down?)设置哪些边缘参与碰撞
setFPS(framerate)更改物理步进速率
enable(object, bodyType?)为对象/组/数组启用物理
disable(object)为对象/组/数组禁用物理
add(body) / remove(body)从模拟中添加/移除 Body
addCollider / addOverlap创建 Collider(参数与工厂方法相同)
removeCollider(collider)移除 Collider
pause() / resume()暂停/恢复模拟
createDebugGraphic()创建调试渲染图形
Body 方法
方法描述
setVelocity(x, y) / setVelocityX / setVelocityY设置速度
setAcceleration(x, y) / setAccelerationX / Y设置加速度
setMaxVelocity(x, y) / setMaxSpeed(speed)速度上限
setBounce(x, y) / setDrag(x, y)弹性和阻力
setDamping(bool)启用阻尼模式
setFriction(x, y) / setGravity(x, y)摩擦力和每个刚体的重力
setMass(val) / setImmovable(bool) / setPushable(bool)质量和碰撞行为
setSize(w, h, center?) / setOffset(x, y)调整刚体尺寸/偏移
setCircle(radius, offX?, offY?)切换为圆形刚体
setCollideWorldBounds(val, bX?, bY?)与世界边界碰撞
setBoundsRectangle(rect)自定义边界矩形
setAllowGravity / setAllowDrag / setAllowRotation切换物理特性
setEnable(val)启用/禁用刚体
setCollisionCategory / setCollidesWith / addCollidesWith / removeCollidesWith类别过滤
resetCollisionCategory()重置为默认(全部)
reset(x, y) / stop()重置位置或将速度归零

注意事项

  1. 在生产环境中使用 debug: true —— 调试渲染开销很大。发布构建时务必禁用。

  2. 静态刚体变换的变更 —— 更改静态刚体的 Game Object 的位置、缩放或原点后,必须调用 body.reset() 或 gameObject.refreshBody()。静态刚体不会自动同步。

  3. collide 与 overlap —— collide 会执行分离(将刚体推开)。overlap 只检测相交,不会移动任何物体。对于拾取物之类的触发器,请使用 overlap。

  4. 持久 Collider 与一次性检测 —— this.physics.add.collider() 会创建一个每帧自动检查的 Collider。this.physics.collide() 是一次性检查,必须在 update() 中每帧调用。优先使用持久 Collider。

  5. 事件需要主动启用 —— 世界事件('collide'、'overlap'、'worldbounds')只有在相关刚体属性(onCollide、onOverlap、onWorldBounds)设置为 true 时才会触发。

  6. 碰撞类别的默认值 —— 默认情况下,所有刚体的类别为 0x0001,掩码为 1(PhysicsGroup 默认掩码为 2147483647)。调用 this.physics.nextCategory() 可获取新的类别值;总共最多 32 个类别。更改类别后,使用 resetCollisionCategory() 将掩码设置为所有位。

  7. Group 默认值仅在创建时生效 —— PhysicsGroup 的 defaults(如 velocityX、bounceY)会在成员被添加/创建时应用。之后更改 defaults 不会追溯更新已有成员。

  8. customUpdate 配置 —— 在 arcade 配置中设置 customUpdate: true 会阻止世界在 Scene UPDATE 事件上自动更新。你必须手动调用 this.physics.world.update(time, delta)。

  9. useDamping 阻力值 —— 当 useDamping 为 true 时,阻力值应该很小(例如 0.05),因为它们充当乘数。值为 0.05 意味着刚体每秒保留其速度的 5%。

  10. Immovable 与 pushable —— immovable = true 意味着刚体完全不会被碰撞移动。pushable = false 意味着刚体将速度反射回碰撞的刚体,但仍可被分离。

  11. 与 TilemapLayer 的 Overlap —— 当对 TilemapLayer 使用 overlapOnly 时,无论单个瓦片上的碰撞设置如何,每个瓦片都会被检查。

  12. RTree 阈值 —— RTree 空间索引(默认启用)在动态刚体数量非常多时重建开销会很大。对于 5000+ 动态刚体,考虑设置 useTree: false。

源文件映射

文件用途
src/physics/arcade/ArcadePhysics.js场景插件(this.physics)——collide、overlap、moveTo、accelerateTo、nextCategory
src/physics/arcade/World.js物理世界——body、重力、边界、碰撞器、步进循环、setBounds、addCollider
src/physics/arcade/Body.js动态 body——速度、加速度、反弹、阻力、重力、质量、不可移动、可推动
src/physics/arcade/StaticBody.js静态 body——不可移动、无速度、优化的 RTree 查找
src/physics/arcade/Factory.jsthis.physics.add——sprite、image、group、staticGroup、body、existing、collider、overlap
src/physics/arcade/Collider.js碰撞器对象——带回调的持久碰撞/重叠检测
src/physics/arcade/PhysicsGroup.js动态物理组,支持按成员设置默认值
src/physics/arcade/StaticPhysicsGroup.js静态物理组,支持自动刷新
src/physics/arcade/components/index.jsBody 组件混入——Acceleration、Angular、Bounce、Collision、Debug、Drag、Enable、Friction、Gravity、Immovable、Mass、Pushable、Size、Velocity
src/physics/arcade/components/Collision.js碰撞类别/掩码方法——setCollisionCategory、setCollidesWith、addCollidesWith、removeCollidesWith
src/physics/arcade/events/事件常量——COLLIDE、OVERLAP、WORLD_BOUNDS、TILE_COLLIDE、TILE_OVERLAP、WORLD_STEP、PAUSE、RESUME
src/physics/arcade/typedefs/ArcadeWorldConfig.jsarcade 物理配置选项的 TypeDef

评论

支持 Markdown