UNPKG

planck-js

Version:

2D JavaScript/TypeScript physics engine for cross-platform HTML5 game development

192 lines (157 loc) 7.25 kB
## Fixture Shapes only have geometrical coordinates, they don't have physical properties and don't know about the body's transformation, so may be used independently of the physics simulation. The `Fixture` class is used to attach shapes to bodies. A body may have zero or more fixtures. A body with multiple fixtures is sometimes called a *compound body.* Fixtures hold the following: - a single shape - broad-phase proxies - density, friction, and restitution - collision filtering flags - back pointer to the parent body - user data - sensor flag These are described in the following sections. ### Fixture Creation Fixtures are created by initializing a fixture definition and then passing the definition to the parent body. ```js let myFixture = myBody.createFixture({ shape: myShape, density: 1, }); ``` This creates the fixture and attaches it to the body. You do not need to store the fixture pointer since the fixture will automatically be destroyed when the parent body is destroyed. You can create multiple fixtures on a single body. You can destroy a fixture on the parent body. You may do this to model a breakable object. Otherwise you can just leave the fixture alone and let the body destruction take care of destroying the attached fixtures. ```js myBody.destroyFixture(myFixture); ``` ### Density The fixture density is used to compute the mass properties of the parent body. The density can be zero or positive. You should generally use similar densities for all your fixtures. This will improve stacking stability. The mass of a body is not adjusted when you set the density. You must call resetMassData for this to occur. ```js fixture.setDensity(5); body.resetMassData(); ``` ### Friction Friction is used to make objects slide along each other realistically. Planck.js supports static and dynamic friction, but uses the same parameter for both. Friction is simulated accurately in Planck.js and the friction strength is proportional to the normal force (this is called Coulomb friction). The friction parameter is usually set between 0 and 1, but can be any non-negative value. A friction value of 0 turns off friction and a value of 1 makes the friction strong. When the friction force is computed between two shapes, Planck.js must combine the friction parameters of the two parent fixtures. This is done with the geometric mean: ```js function mixFriction(friction1, friction2) { return Math.sqrt(friction1 * friction2); } ``` So if one fixture has zero friction then the contact will have zero friction. You can override the default mixed friction using `contact.setFriction`. This is usually done in the contact listener callback. ### Restitution Restitution is used to make objects bounce. The restitution value is usually set to be between 0 and 1. Consider dropping a ball on a table. A value of zero means the ball won't bounce. This is called an inelastic collision. A value of one means the ball's velocity will be exactly reflected. This is called a perfectly elastic collision. Restitution is combined using the following formula. ```js function mixRestitution(restitution1, restitution2) { return Math.max(restitution1, restitution2); } ``` Restitution is combined this way so that you can have a bouncy super ball without having a bouncy floor. You can override the default mixed restitution using `contact.setRestitution`. This is usually done in the contact listener callback. When a shape develops multiple contacts, restitution is simulated approximately. This is because Planck.js uses an iterative solver. Planck.js also uses inelastic collisions when the collision velocity is small. This is done to prevent jitter. See `Settings.velocityThreshold`. ### Filtering Collision filtering allows you to prevent collision between fixtures. For example, say you make a character that rides a bicycle. You want the bicycle to collide with the terrain and the character to collide with the terrain, but you don't want the character to collide with the bicycle (because they must overlap). Planck.js supports such collision filtering using categories and groups. Planck.js supports 64 [todo?] collision categories. For each fixture you can specify which category it belongs to. You also specify what other categories this fixture can collide with. For example, you could specify in a multiplayer game that all players don't collide with each other and monsters don't collide with each other, but players and monsters should collide. This is done with masking bits. For example: ```js let playerFixtureDef = { filterCategoryBits: parseInt('010', 2), filterMaskBits: parseInt('100', 2), }; let monsterFixtureDef = { filterCategoryBits: parseInt('100', 2), filterMaskBits: parseInt('010', 2), }; ``` Here is the rule for a collision to occur: ```js let catA = fixtureA.filterCategoryBits; let maskA = fixtureA.filterMaskBits; let catB = fixtureB.filterCategoryBits; let maskB = fixtureB.filterMaskBits; if ((catA & maskB) !== 0 && (catB & maskA) !== 0) { // fixtures can collide } ``` Collision groups let you specify an integral group index. You can have all fixtures with the same group index always collide (positive index) or never collide (negative index). Group indices are usually used for things that are somehow related, like the parts of a bicycle. In the following example, `fixture1` and `fixture2` always collide, but `fixture3` and `fixture4` never collide. ```js fixture1Def.filterGroupIndex = 2; fixture2Def.filterGroupIndex = 2; fixture3Def.filterGroupIndex = -8; fixture4Def.filterGroupIndex = -8; ``` Collisions between fixtures of different group indices are filtered according to the category and mask bits. In other words, group filtering has higher precedence than category filtering. Note that additional collision filtering occurs in Planck.js. Here is a list: - A fixture on a static body can only collide with a dynamic body. - A fixture on a kinematic body can only collide with a dynamic body. - Fixtures on the same body never collide with each other. - You can optionally enable/disable collision between fixtures on bodies connected by a joint. Sometimes you might need to change collision filtering after a fixture has already been created. You can get and set the Filter structure on an existing fixture using fixture.getFilterData and fixture.setFilterData. Note that changing the filter data will not add or remove contacts until the next time step (see the World class). ### Sensors Sometimes game logic needs to know when two fixtures overlap yet there should be no collision response. This is done by using sensors. A sensor is a fixture that detects collision but does not produce a response. You can flag any fixture as being a sensor. Sensors may be static, kinematic, or dynamic. Remember that you may have multiple fixtures per body and you can have any mix of sensors and solid fixtures. Also, sensors only form contacts when at least one body is dynamic, so you will not get a contact for kinematic versus kinematic, kinematic versus static, or static versus static. Sensors do not generate contact points. There are two ways to get the state of a sensor: 1. `contact.isTouching()` 2. `begin-contact` and `end-contact` events