# phaser-matter-collision-plugin

> A plugin for making it easier to manage collisions with Phaser + Matter.js

Latest version **1.0.0** (published 2021-08-06) · MIT license · 0 weekly downloads

## Install

```sh
npm install phaser-matter-collision-plugin
pnpm add phaser-matter-collision-plugin
yarn add phaser-matter-collision-plugin
bun add phaser-matter-collision-plugin
```

## Health

**Score 20/100 (F)** — status: abandoned.

Positive: has types; no vulnerabilities.

Warnings: low downloads; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.0.0 |
| Published | 2021-08-06 |
| First published | 2018-08-15 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | CommonJS |
| Dependencies | 0 |
| Unpacked size | 98.3 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 99 |
| Author | Michael Hadley |
| Maintainers | mikewesthad |
| Keywords | matter.js, phaser, collision detection, game engine, physics engine |

## Links

- npm: https://www.npmjs.com/package/phaser-matter-collision-plugin
- Repository: https://github.com/mikewesthad/phaser-matter-collision-plugin
- Homepage: https://github.com/mikewesthad/phaser-matter-collision-plugin/workspaces/plugin#readme
- Issues: https://github.com/mikewesthad/phaser-matter-collision-plugin/issues
- npm.io page: https://npm.io/package/phaser-matter-collision-plugin

## Recent versions

- 1.0.0 (latest) — 2021-08-06
- 1.0.0-beta.0 (beta) — 2021-08-06
- 0.10.2 — 2019-02-19
- 0.10.1 — 2018-11-17
- 0.10.0 — 2018-08-18
- 0.9.2 — 2018-08-17
- 0.9.1 — 2018-08-17
- 0.9.0 — 2018-08-15

## README

# Phaser Matter Collision Plugin 💥 <!-- omit in toc -->

A plugin for making it easier to manage collisions with the [Phaser](https://phaser.io/) game engine and the [Matter.js](http://brm.io/matter-js/) physics engine.

Matter is one of the cool physics engine choices you have in Phaser 3. Phaser has a thin wrapper over Matter's API, so you need to dig into Matter's native collision event system if you want to detect and respond to collisions. That system just gives you a dump of all the pairs of bodies that collided in a tick of the engine. This plugin wraps up that collision logic in a more useful way:

```js
const player = this.matter.add.sprite(0, 0, "player");
const trapDoor = this.matter.add.sprite(200, 0, "door");

this.matterCollision.addOnCollideStart({
  objectA: player,
  objectB: trapDoor,
  callback: () => console.log("Player touched door!")
});
```

Or in a slightly more complicated example:

[![](./doc-source-assets/collision-simple-demo.gif)](https://raw.githubusercontent.com/mikewesthad/phaser-matter-collision-plugin/master/doc-source-assets/collision-simple-demo.gif)
_See interactive versions of that example on CodeSandbox in [JavaScript](https://codesandbox.io/s/0o0917m23l) or [TypeScript](https://codesandbox.io/s/my3oyyqj39)._

If you are reading this on Github or NPM, check out the HTML documentation [here](https://www.mikewesthad.com/phaser-matter-collision-plugin/docs/manual/README.html).

- [Installation](#installation)
  - [As a Module](#as-a-module)
  - [As a Script](#as-a-script)
- [Usage](#usage)
  - [Initial Setup](#initial-setup)
  - [Usage in Scene](#usage-in-scene)
    - [Tracking Collisions](#tracking-collisions)
    - [Stop Tracking Collisions](#stop-tracking-collisions)
- [Examples](#examples)
- [Tips](#tips)
- [Changelog](#changelog)
- [Development](#development)
  - [Scripts](#scripts)
  - [Tests](#tests)
  - [New Releases](#new-releases)

## Installation

You can install this plugin locally as a module using your bundler of choice, or globally as a script.

### As a Module

Install via npm:

```
npm install --save phaser-matter-collision-plugin
```

Then import the plugin into your project:

```js
import PhaserMatterCollisionPlugin from "phaser-matter-collision-plugin";
```

See [usage](#usage) for how to use the plugin.

### As a Script

Grab the desired version from the [releases](https://github.com/mikewesthad/phaser-matter-collision-plugin/releases) page and include it as a script in your HTML. E.g. it might look like:

```html
<script src="./phaser-matter-collision-plugin.min.js"></script>
```

Or use the jsdelivr CDN:

```html
<script src="//cdn.jsdelivr.net/npm/phaser-matter-collision-plugin"></script>
```

Now you can use the global `PhaserMatterCollisionPlugin`. See [usage](#usage) for how to use the plugin.

## Usage

### Initial Setup

When setting up your game config, add the plugin:

```js
const config = {
  // ...
  physics: {
    default: "matter"
  },
  // Install the scene plugin
  plugins: {
    scene: [
      {
        plugin: PhaserMatterCollisionPlugin, // The plugin class
        key: "matterCollision", // Where to store in Scene.Systems, e.g. scene.sys.matterCollision
        mapping: "matterCollision" // Where to store in the Scene, e.g. scene.matterCollision
      }
    ]
  }
};

const game = new Phaser.Game(config);
```

Now, within a scene, you can use `this.matterCollision` to access the plugin instance.

### Usage in Scene

#### Tracking Collisions

The plugin has `addOnCollideStart`, `addOnCollideActive` and `addOnCollideEnd` methods which allow you to listen to collisions between "objects" in your scene. Those objects can be: a native Matter body, a tile, a Matter sprite, any object with a `body` property, or an array of any of those.

For example, game object vs game object collisions:

```js
const player = this.matter.add.sprite(0, 0, "player");
const trapDoor = this.matter.add.image(200, 0, "door");

this.matterCollision.addOnCollideStart({
  objectA: player,
  objectB: trapDoor,
  callback: function(eventData) {
    // This function will be invoked any time the player and trap door collide.
    const { bodyA, bodyB, gameObjectA, gameObjectB, pair } = eventData;
    // bodyA & bodyB are the Matter bodies of the player and door respectively.
    // gameObjectA & gameObjectB are the player and door respectively.
    // pair is the raw Matter pair data.
  },
  context: this // Optional context to apply to the callback function.
});
```

If you omit the `objectB` property, you'll get all collisions involving `objectA`:

```js
const player = this.matter.add.sprite(0, 0, "player");

this.matterCollision.addOnCollideStart({
  objectA: player,
  callback: eventData => {
    const { bodyB, gameObjectB } = eventData;
    console.log("Player touched something.");
    // bodyB will be the matter body that the player touched.
    // gameObjectB will be the game object that owns bodyB, or undefined if there's no game object
    // (e.g. the player hitting an invisible Matter body acting as a wall).
  }
});
```

Game object vs Matter sensor:

```js
const player = this.matter.add.sprite(0, 0, "player");
const sensor = this.matter.world.add.rectangle(100, 0, 50, 50, { isStatic: true, isSensor: true });

this.matterCollision.addOnCollideStart({
  objectA: player,
  objectB: sensor,
  callback: eventData => console.log("Player touched hidden sensor")
});
```

Game object vs array of objects:

```js
const player = this.matter.add.sprite(0, 0, "player");
const enemy1 = this.matter.add.sprite(100, 0, "enemy");
const enemy2 = this.matter.add.sprite(200, 0, "enemy");
const enemy3 = this.matter.add.sprite(300, 0, "enemy");

this.matterCollision.addOnCollideStart({
  objectA: player,
  objectB: [enemy1, enemy2, enemy3],
  callback: eventData => {
    console.log("Player hit an enemy");
    // eventData.gameObjectB will be the specific enemy that was hit!
  }
});
```

Or, array vs array:

```js
this.matterCollision.addOnCollideStart({
  objectA: [player1, player2],
  objectB: [enemy1, enemy2, enemy3],
  callback: eventData => {
    console.log("A player hit an enemy");
    // eventData.gameObjectA will be the specific player involved in the collision
    // eventData.gameObjectB will be the specific enemy involved in the collision
  }
});
```

You can listen for collisions vs a single tile (or an array of tiles), but it's likely more useful to do something like:

```js
this.matterCollision.addOnCollideStart({
  objectA: player,
  callback: eventData => {
    const { bodyB, gameObjectB } = eventData;

    if (gameObjectB instanceof Phaser.Tilemaps.Tile) {
      // Now you know that gameObjectB is a Tile, so you can check the index, properties, etc.
      if (gameObjectB.properties.isDeadly) console.log("Stepped on deadly tile");
      else if (gameObjectB.index === 32) console.log("Stepped on the tile with index 32");
    }
  }
});
```

The plugin also exposes two sets of events via the `this.matterCollision.events` event emitter:

- "collisionstart", "collisionactive", "collisionend" - these match the Matter events. They emit a single parameter `event`. Aside from the normal Matter data in `event`, each pair in `event.pairs` has a `gameObjectA` and `gameObjectB` property that points to the game object that owns each body (if one exists).
- "paircollisionstart", "paircollisionactive", "paircollisionend" - these are similar to the above, except they fire once for each pair. They have one parameter that looks like this: `{ bodyA, bodyB, gameObjectA, gameObjectB, pair }`

You can listen to them via `this.matterCollision.events.on("collisionstart", ...)`.

#### Stop Tracking Collisions

You can stop tracking a collision via `removeOnCollideStart`, `removeOnCollideActive` and `removeOnCollideEnd`. They take the same parameters as `addOnCollideStart`. E.g.:

```js
function onCollide() {
  console.log("A player hit an enemy");
}

// ... after addOnCollideStart has been used

this.matterCollision.removeOnCollideStart({
  objectA: [player1, player2],
  objectB: [enemy1, enemy2, enemy3],
  callback: onCollide
});
```

In addition, the addOnCollide methods will also return a function that automatically unsubscribes from the collision event (which can be useful if you use arrow functions):

```js
const unsubscribe = this.matterCollision.addOnCollideStart({
  objectA: player,
  objectB: trapDoor,
  callback: eventData => {
    // Do something, like dropping the door out underneath the player
    // Then unsubscribe so this callback is never called again
    unsubscribe();
  }
});
```

If you want to remove all listeners that have been added - not just one colliding pair - there are also the following methods:

- `removeAllCollideStartListeners`
- `removeAllCollideActiveListeners`
- `removeAllCollideEndListeners`
- `removeAllCollideListeners` - removes start, active and end listeners

## Examples

![](./doc-source-assets/collision-plugin-demo.gif)

This repo includes two example projects:

- [JavaScript](./workspaces/javascript-example)
- [TypeScript](./workspaces/typescript-example)

You can also check out versions of those example projects on CodeSandbox:

- [JavaScript](https://codesandbox.io/s/0o0917m23l)
- [TypeScript](https://codesandbox.io/s/my3oyyqj39)

You can also poke around the ["tests" folder](https://github.com/mikewesthad/phaser-matter-collision-plugin/tree/master/tests) of this repository for usage examples.

## Tips

- Trying to apply a force during collision? See [@alrdebugne's](https://github.com/alrdebugne) note in this [issue](https://github.com/mikewesthad/phaser-matter-collision-plugin/issues/5#issuecomment-752780477) on how to do that.

## Changelog

- 1.0.0 (2021-08-06)
  - Conversion to TypeScript.
  - Update all dependencies.
  - Add named export for PhaserMatterCollisionPlugin (in addition to existing default export).
  - Fix removeOnCollideXX methods so that all config parameters are used when matching.
- 0.10.2 (2019-02-19)
  - Bug: fixed a bug in `addOnCollide()` that threw an error when the user didn't supply a callback, from [@jvanroose](https://github.com/jvanroose).
- 0.10.1 (2018-11-17)
  - Bug: fixed a bug in the removeOnCollideXXXX methods of the plugin, from [@Fantasix](https://github.com/Fantasix).
- 0.0.0 - 0.9.2 (2018-08-17)
  - Initial releases.

## Development

To set up the project for local development make sure you have node and npm installed. You can grab them bundled together [here](https://nodejs.org/en/). Clone/download the repository and run `npm i` from a terminal within the folder.

### Scripts

The project is controlled by npm scripts and uses cypress & jest for testing. Cypress is used for end-to-end verification that the plugin works as expected with Phaser. Jest is used for unit testing the plugin (via heavy mocking since Phaser headless mode is not complete).

- The `watch` and `build` tasks will build the plugin source in library/ or the projects in tests/
- The `serve` task opens the whole project (starting at the root) in a server
- The `dev` task will build & watch the library, tests and open up the server. This is useful for creating tests and updating the library.
- The `dev:cypress` task will build & watch the library & tests, as well as open up cypress in headed mode. This is useful for checking out individual tests and debugging them.
- The `test:cypress` task will build the tests and run cypress in headless mode to check all end-to-end tests.
- The `test:jest` will run the jest tests.

### Tests

The cypress tests rely on a particular structure:

- Each test game inside of "tests/" should have an "index.html" file as the entry point. "src/js/index.js" will be compiled to "build/js/index.js" by webpack. (Cypress doesn't support `type="module"` on scripts, so this is necessary if we need modules.)
- Each test has access to `test-utils.js` which provides `startTest`, `passTest` and `failTest` methods. Call `startTest` at the beginning and pass/fail when the test passes/fails. This manipulates in the DOM in a way that cypress is expecting.
- Each test in "cypress/integration/" simply loads up the specified URL and waits for it to pass or timeout. (Technically, startTest and failTest are ignored, but they are useful for visual inspection of a test.)

The jest unit tests rely on a simple mocking of Phaser and Matter. They are stored inside "src/". Once Phaser headless is available, this testing structure could be re-evaluated.

### New Releases

To prepare a new release, verify that all tests pass with `yarn test:jest` and `yarn test:cypress`, update the changelog, and then:

```
yarn npm login
yarn npm publish
```

---
_Source: https://npm.io/package/phaser-matter-collision-plugin · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
