-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
v4 Gotchas
There are a handful of use-cases in PixiJS which you might, some-day encounter. In most cases, these were created because they fall outside of the majority of use-cases, because a lack of developer time, or because of some other necessity related to performance.
Anchor has a meaning only for Sprite-based objects. There are hacks that can help achieve an anchor for other DisplayObjects.
Container width
and height
properties based on getLocalBounds()
function that calculates bounds of all children and messes with transforms. It is ok to make your own container or override pixi behaviour to make it project-dependent. Custom container example with dock based on forum post
DisplayObject absolute transform is the result of multiplication of all local transforms of its parents. If we change object parent, it will change absolute position. This code prevents saves the position:
newParent.toLocal(new PIXI.Point(0,0), bunny, bunny.position);
newParent.addChild(bunny);
For example, in the snippet below, the blur does not render:
const app = new PIXI.Application();
app.stage.filters = [new PIXI.filters.BlurFilter()]; // <-- does not show up
Workaround: Nest a container within the stage:
const app = new PIXI.Application();
const root = new PIXI.Container();
app.stage.addChild(root);
root.filters = [new PIXI.filters.BlurFilter()];
@ivanpopelyshev: Sometimes this workaround works in other corner cases: cacheAsBitmap, ParticleContainer.
The addHole
API is designed to draw holes, or "windows", within Graphics objects. Yet, it only works with primitive drawing commands and does not work with other convenience shapes (e.g., drawCircle
, drawRect
). The hole and the main Graphic cannot be shapes.
const graphic = new PIXI.Graphics()
.beginFill(0xFF0000)
.drawRect(0, 0, 110, 110)
.drawRect(50, 50, 10, 10)
.addHole(); // <-- hole does not show-up
Workaround: Use moveTo
, lineTo
, arcTo
, bezierCurveTo
and quadraticCurveTo
to render the hole and the main polygon.
const graphic = new PIXI.Graphics()
.beginFill(0xFF0000)
.moveTo(0, 0)
.lineTo(110, 0)
.lineTo(110, 110)
.lineTo(0, 110)
.moveTo(50, 50)
.lineTo(60, 50)
.lineTo(60, 60)
.lineTo(50, 60)
.addHole();
Graphics supports only line width and color. To use dashes, you have to learn the Workaround
In v4 its not possible to fill an area with a texture, and TilingSprite+mask is not performant enough. Provided workaround works if your texture is POW2 and does not belong to an atlas.
The following objects do not support Texture objects that are part of a Spritesheet shared with other Texture objects or where the Texture's frame is not the entire size of the BaseTexture. Using a Spritesheet with one of these classes will cause the transforms to render incorrectly.
- Sprite-based masks Π
- Filters with sprite inputs (e.g., DisplacementFilter)
- PIXI.mesh.Mesh β
- PIXI.mesh.Plane β
- PIXI.mesh.Rope β
- PIXI.mesh.NineSlicePlane β
- PIXI.extras.TilingSprite β‘
Π Supports texture regions since 4.6.0
β Supports texture regions since 4.5.0
β‘ Supports texture regions since 4.1.0
PIXI.loader.add('atlas', 'atlas.json')
.load((loader, resources) => {
const sprite = new PIXI.Sprite(
resources.atlas.textures.myTexture
);
someContainer.addChild(sprite);
someContainer.mask = sprite; // <-- won't work
});
Workaround: If you intend to use any of these advanced DisplayObjects, make sure they are loaded as standalone images and are not part of a bundled Spritesheet.
PIXI.loader.add('atlas', 'atlas.json')
.add('myMask', 'myMask.png')
.load((loader, resources) => {
const mesh = new PIXI.Sprite(
resources.myMask.texture
);
someContainer.addChild(sprite);
someContainer.mask = sprite;
});
Formats for video, and whether the video can be transparent, depend on browser. Sometimes there are bugs. See the thread.
Filters are very expensive when implemented on a CanvasRenderer
and PixiJS does not support the use-case here. Performance would simply be too poor. Therefore, Filters only work with WebGLRenderer and will be ignored on platforms that do not support WebGL (e.g., Internet Explorer, Android 4, etc).
const stage = new PIXI.Container();
const renderer = new PIXI.CanvasRenderer();
stage.filters = [new PIXI.filters.BlurFilter()]; // <-- won't render
renderer.render(stage);
Tip: While there's no workaround, you should make sure that you test your PixiJS content on non-WebGL platforms if you intend to use filters.
WebGL supports only NORMAL
, ADD
, MULTIPLY
and SCREEN
blend modes. Advanced blend modes like OVERLAY
are only supported by canvas renderer (at least until WebGL updates up to OpenGL ES 4.0).
Workaround: Check out the PixiJS plugin pixi-picture to add advanced blend mode support for WebGL.
Numbers from 20 are free, you can use composition modes that absent in CanvasRenderer
renderer.blendModes[20] = 'destination-out';
sprite.blendMode = 20;
You cannot specify blend mode for a normal Container.
Workaround: Using a VoidFilter, PixiJS will render everything inside container into separate framebuffer and then render whole layer with a blending mode of your choice. See example.
var myBlend = new PIXI.filters.VoidFilter();
myBlend.blendMode = PIXI.BLEND_MODES.ADD;
container.filters = [myBlend];
You cannot use custom WebGL blend modes in vanilla PixiJS.
Workaround: Example of 'clearing' the surface, but there is no guarantee that it works on mobile devices. Example #2 adds SUBTRACT blend mode!
Sometimes there's a lag when your app shows a sprite of particular base texture first time.
Manually, you can upload a texture to webgl memory using this:
renderer.textureManager.updateTexture(myTexture);
You may pass any texture of particular atlas to upload whole atlas.
When you change the stage, most of the time you dont remember which resources you need for next stage and which ones can be destroyed. There's also huge problem with generated resources.
GC solves that easily, it removes all textures that weren't used in last two minutes from videomemory. But it can be a headache if you want to show particular animation every three minutes - first frame will have lag. In that case, if you are ready to take responsibility, you can switch it off
renderer.textureGC.GC_MODE = PIXI.GC_MODES.MANUAL;
Or just switch it off globally for all renderers to be created later
PIXI.settings.GC_MODE = PIXI.GC_MODES.MANUAL;
Use prepare API to make sure that all textures of particular stage are uploaded to videomemory. Beware, the method is asynchronous!
Videomemory upload is not the only operation that causes lag. Browser's PNG->RGBA conversion also does it, its synchronous pain. After some time, browser removes RGBA buffer from regular memory, that helps in low-memory devices. We have no control over it, except new function createImageBitmap that solves this issue.
createImageBitmap method will be used in pixi-v5.
Fortunately, for v4, there is the snippet from forum thread that enables createImageBitmap in case you load resources with fromImage
.
InteractionManager instance is created for every renderer instance automagically. See renderer.plugins.interaction
If you do any transformations on canvas, there's no guarantee that InteractionManager calculates correct coordinates, see https://jsfiddle.net/r3fktwkk/ - pixi thinks that sprite is in top-left corner.
Please override mapPositionToPoint
Do it either in a class
PIXI.interaction.InteractionManager.prototype.mapPositionToPoint= function(point, x, y) { ... }
either in a particular instance
renderer.plugins.interaction.mapPositionToPoint= function(point, x, y) { ... }
For some cases its easier to perform operations that are easily handled through renderer plugin.
If you want to use extra textures for a filter, please look here:
Full example: https://github.com/pixijs/pixi-plugin-example
Shortcut: https://github.com/TazOen/createShaderPlugin , http://www.html5gamedevs.com/topic/31704-createshaderplugin-helper-function/
PIXI.extract have no params to make a certain area of the stage. But its possible to use generateTexture
directly:
var myArea = renderer.screen; // rectangle that you want to make a screenshot
var tempTexture = renderer.generateTexture(stage, undefined, undefined, myArea);
var pixels = renderer.extract.pixels(tempTexture);
tempTexture.destroy(true);
Those lines are required for mobile devices, and WebGL can crash if you dont add them in 'head' tag of HTML page
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimum-scale=1, width=device-width, height=device-height">
<meta name="apple-mobile-web-app-capable" content="yes">
This one by @Exca, for android devices with big screens:
<meta name="viewport" content="width=device-width, target-densitydpi=device-dpi, maximum-scale=1.0, user-scalable=no">
If canvas is blinking, try different params for renderer:
- antialias
- preserveDrawingBuffer
- transparent
Those are defaults:
new PIXI.WebGLRenderer(800, 600, {antialias: false, transparent: true});
Sometimes antialias
helps to stabilize framebuffer behaviour:
new PIXI.WebGLRenderer(800, 600, {antialias: true});
For Amazon Kindle its necessary to turn on preserveDrawingBuffer
. Yes, this parameters slows everything down, but we have no choice:
new PIXI.WebGLRenderer(800, 600, {preserveDrawingBuffer: true});
Some versions of chrome dont like transparent canvases, so try to turn it off:
new PIXI.WebGLRenderer(800, 600, {transparent: false});
// or this one
new PIXI.WebGLRenderer(800, 600, {transparent: 'notMultiplied'});
The accessibility plugin is primarily used to allow you to use the keyboard to interact with on screen elements. However, by it's nature of putting a html div element correctly over the top of a pixi element, it can also be useful for debugging information. https://github.com/pixijs/pixi.js/issues/4526 is a PR that details one such usage with clever usage of the accessibleTitle property on display objects, and the attr property on html elements
If your app isn't stable 60FPS on some devices, its good to add 30FPS option to your app, by changing PIXI.settings.TARGET_FPMS
to 0.03
(its FPS divided by 1000).
Here's the list of resources for advanced management: