Changing collision box with Matter

Hi all,

I’ve just started playing around with Phaser 3, and I’m having trouble adjusting a sprite’s collision box. I’m rotating entities, so I have to use the Matter engine (which sucks, as approximately 100% of the examples use Arcade)

My code’s a mess (I’m still in the can I do this? phase), but basically I have:

Preload

this.load.spritesheet(
	'ship',
	'assets/ship.png',
	{
		frameWidth:100,
		frameHeight:208
	}
);

The “ship” is a 2 frame sprite - frame 1 has just the ship, frame 2 has the ship with exhaust. I’m trying to adjust the collision box so the exhaust portion of the sprite doesn’t collide with anything.

Create

window.player = this.matter.add.sprite(
        this.cameras.main.width/4,
        this.cameras.main.height/2,
        'ship'
    )
    // this moves the rotation point to the middle of the ship
    // instead of the middle of the sprite
    .setOrigin(0.5,0.2);

// I thought this should do it, but the pink box doesn't change
window.player.setSize(200,200);

How do I change the collision box? I know I can change the initial frame height when loading the sprite sheet, but that clips off the exhaust.

Here’s a screenshot of what I have, without the exhaust: https://imgur.com/a/kWHntCU. I’d like the pink pox to be snug to the ship, but allow the exhaust to still be seen.

Any other tips would also be helpful. Documentation on Phaser 3 + Matter.js seems pretty non-existent.

For a simple box that you want to change for a frame, I think the easiest solution is to change the vertices of the box and/or position of the box when this frame is active.

You can change the collision box position with: window.player.body.position.x and y
You can change the vertices with window.player.body.vertices[0] to [3], 0 being the top left.

Some links of use:
https://rexrainbow.github.io/phaser3-rex-notes/docs/site/matterjs-world/ <- has more pages with matter info.
https://medium.com/@michaelwesthadley/modular-game-worlds-in-phaser-3-tilemaps-1-958fc7e6bbd6 <- excellent 4 part tutorial on using phaser and matter
https://www.codeandweb.com/physicseditor/tutorials/how-to-create-physics-shapes-for-phaser-3-and-matterjs <- Using PhysicsEditor tutorial
https://photonstorm.github.io/phaser3-docs/Phaser.Physics.Matter.html <- Phaser 3 docs
https://brm.io/matter-js/docs/ <- Full matter docs
https://labs.phaser.io/index.html?dir=physics/matterjs/&q= <- Lots of examples using matter

I can’t play around with your solution right now as I’m at work, but I’ll take a look when I get home. Thanks for the advice & links.

Neither of those suggestions worked. Setting the position changed the position of the whole object. I wasn’t able to get any tweaking of the vertices to produce anything usable.

However, your links convinced me to bite the bullet and use PhysicsEditor and TexturePacker. Creating an atlas with TexturePacker, then explicitly setting the frame (as opposed to an animation), resulted in the box being snug to the graphic.

Thanks.

I have use PhysicsEditor and TexturePacker in my game. Can I ask how you implemented what you mean when you say “setting the frame” instead of an animation? I have an animation, but I want the sprite’s body/hitbox to stay “snug” like you said with the image

“setting the frame” didn’t make the box snug, using an atlas did. As to why - I can’t say. My guess is the atlas sets the source size (ie, size of the sprite) when the sprite is initially created, and setting the frame later doesn’t update the physics box.

To create my sprite I did:

let Ship = this.matter.add.sprite(
    xCoord,
    yCoord,
    'ship-atlas.png',
    'initial-ship-frame.png'
);

That was enough to make the box snug. Later, to set the frame when accelerating, I do:

this.setFrame('exhaust-ship-frame.png');

Does that help?

Do you know if this works when using animations?

I don’t know. I believe you can specify animations in TexturePacker, so maybe referring to the atlas for your animations will have the same affect.

@roberto257

Ok, I did a little experiment this afternoon and I got it working.

Here’s the sprite sheet I used to test. It’s kind of hard to see on a white background, but the 2nd & 4th frames have a little yellow exhaust.
sprites

The frame names are, in order:

  1. 1.png
  2. 2.png
  3. 1A.png
  4. 2A.png

Here’s the JSON atlas:

{
	"textures": [
		{
			"image": "sprites.png",
			"format": "RGBA8888",
			"size": {
				"w": 16,
				"h": 72
			},
			"scale": 1,
			"frames": [
				{
					"filename": "1.png",
					"rotated": false,
					"trimmed": false,
					"sourceSize": {
						"w": 16,
						"h": 16
					},
					"spriteSourceSize": {
						"x": 0,
						"y": 0,
						"w": 16,
						"h": 16
					},
					"frame": {
						"x": 0,
						"y": 0,
						"w": 16,
						"h": 16
					},
					"anchor": {
						"x": 0.5,
						"y": 0.5
					}
				},
				{
					"filename": "1A.png",
					"rotated": false,
					"trimmed": false,
					"sourceSize": {
						"w": 16,
						"h": 20
					},
					"spriteSourceSize": {
						"x": 0,
						"y": 0,
						"w": 16,
						"h": 20
					},
					"frame": {
						"x": 0,
						"y": 16,
						"w": 16,
						"h": 20
					},
					"anchor": {
						"x": 0.5,
						"y": 0.4
					}
				},
				{
					"filename": "2.png",
					"rotated": false,
					"trimmed": false,
					"sourceSize": {
						"w": 16,
						"h": 16
					},
					"spriteSourceSize": {
						"x": 0,
						"y": 0,
						"w": 16,
						"h": 16
					},
					"frame": {
						"x": 0,
						"y": 36,
						"w": 16,
						"h": 16
					},
					"anchor": {
						"x": 0.5,
						"y": 0.5
					}
				},
				{
					"filename": "2A.png",
					"rotated": false,
					"trimmed": false,
					"sourceSize": {
						"w": 16,
						"h": 20
					},
					"spriteSourceSize": {
						"x": 0,
						"y": 0,
						"w": 16,
						"h": 20
					},
					"frame": {
						"x": 0,
						"y": 52,
						"w": 16,
						"h": 20
					},
					"anchor": {
						"x": 0.5,
						"y": 0.4
					}
				}
			]
		}
	]
}


You’ll see the frames without exhaust are 16x16, and the frames with exhaust are 16x20. That different frame size is reflected in the individual frames’ sourceSize property.

It appears the physics box is set by the size of the first frame in the animation. Here’s my setup code (which is in a class that extends the basic Phaser.Scene class, hence the usage of this)

this.player = this.matter.add.sprite(400,300,'sprite-atlas','1.png');
this.anims.create({
	key:'still',
	frames:this.anims.generateFrameNames('sprite-atlas',{
		start:1,
		end:2,
		suffix:'.png'
	}),
	frameRate:8,
	repeat:-1
});

this.anims.create({
	key:'moving',
	frames:this.anims.generateFrameNames('sprite-atlas',{
		start:1,
		end:2,
		suffix:'A.png'
	}),
	frameRate:8,
	repeat:-1
});

this.player.anims.play('still');

If I modified the creation line to:

this.player = this.matter.add.sprite(400,300,'sprite-atlas','1A.png');

Then the physics box was 20 pixels high - since that’s the size of the 1A.png frame.

Finally, I had to adjust the anchor/pivot points because the *A.png frames were taller, so 0.5 was at 10 pixels, not 8 (why those anchor points are decimals rather than actual pixel values is a mystery to me).

After all that, I can toggle between the “still” and “moving” animations and the physics box will stay just around the ship - the exhaust is displayed outside the physics box.

Hopefully that helps.

1 Like