matter-js
matter-js copied to clipboard
Properly attaching user data / metadata to a body when using TypeScript
Hello!
First of all, thank you for this great library! ❤️ I enjoy playing around with it so far.
Used dependencies
-
"matter-js": "^0.18.0"
-
"@types/matter-js": "^0.17.7"
Background
I'm coming from a Box2D background. And in my previous games, I heavily took advantage of the capability to attach userData to each body, for use-cases such as:
- assigning a type
- giving direct access to the model-class / sprite owning this body
- theoretically one could even store all the relevant fields of a game-object in there
So far I used the options
one can pass when creating a Body
, such as:
export default class SomeGameObject {
private readonly _body: Matter.Body
private readonly _markedForDeletion: boolean
constructor(x: number, y: number) {
this._body = Matter.Bodies.rectangle(x, y, 16, 16, {
inertia: Infinity,
restitution: 0.8,
isSomeGameObject: true, // <-- custom boolean type check
instance: this // <-- custom user data
})
}
update(delta: number): void {
// ...
}
markDelete(): void {
this._markedForDeletion = true
}
get markedForDeletion() {
return this._markedForDeletion
}
get body() {
return this._body
}
}
And then this data can for example be used when iterating through all bodies to update them in the game controller:
Matter.Composite.allBodies(this._engine.world).forEach(body => {
if (body.isSomeGameObject) {
body.instance.update(delta)
const collidesWithSomethingElse = true // some pseudo collision check
if (collidesWithSomethingElse) {
body.instance.markedForDeletion()
}
}
})
This works fine 🙃
However, after enabling typescript type definitions using "@types/matter-js": "^0.17.7"
, my custom properties are violating the interface contract of IBodyDefinition
.
From reading the docs, what I could figure out that instead of using a type specific isXXX
boolean flag, I could use the IBodyDefinition#type field. But I'm not sure why to use for other general custom user data, e.g. provided as a generic object
, or anything of type any
.
I've also seen IBodyDefinition.plugin, but the word reserved in the docs make me skeptical whether they are intended for something completely else which I should not fiddle around:
An object reserved for storing plugin-specific properties.
Questions
- What is the recommended way to store user-data (metadata, custom properties, ...) as part of the body?
- Out of intuition, I would have been looking for something like
userData
,data
ormetadata
. - The TypeScript definition file of Phaser has a BodyDefinition#gameObject field which is internally used for that. I'm however using raw
matter-js
. And am not sure whether it is a good idea to use Phaser's phaser/matter.d.ts instead.
- Out of intuition, I would have been looking for something like
- Or would you discourage to store or reference user-data as part of the body?
- Can I safely use
plugin
? - Or do you have a hint or workaround that one at least would not need to add
@ts-ignore
in various places.
If this is a missing capability, or is only possible with a workaround, I'm happy to contribute to this project if you agree this would be something valuable.
Thx for your help in advance!
From reading the docs, what I could figure out that instead of using a type specific
isXXX
boolean flag, I could use the IBodyDefinition#type field.
I just tried that, and it looks like when I use anything else than the default value of type: "body"
causes that these objects are not updated anymore when updating the simulation using Matter.Engine.update(this.engine, delta)
.
So is the type
field also meant to be not modified by the user?
I think definitely use your own wrapper object with a property e.g. entity.body
and entity.someFlag
, especially if your project is strictly typed, but for a back reference you can use something like body.plugin.myGame = { instance }
though you probably want to do this after Body.create(options)
since this does a deep clone of the options
.
The body.type
property is definitely reserved for internal use. The typescript bindings are a separate project that is maintained by users, so you might want to check in with them too if the above isn't working!
Thank you for your reply. That answered my question.