UNPKG

pixi.js

Version:

<p align="center"> <a href="https://pixijs.com" target="_blank" rel="noopener noreferrer"> <img height="150" src="https://files.pixijs.download/branding/pixijs-logo-transparent-dark.svg?v=1" alt="PixiJS logo"> </a> </p> <br/> <p align="center">

1,126 lines (1,123 loc) 36.2 kB
import EventEmitter from 'eventemitter3'; import { Color } from '../../color/Color.mjs'; import { cullingMixin } from '../../culling/cullingMixin.mjs'; import { extensions } from '../../extensions/Extensions.mjs'; import { Matrix } from '../../maths/matrix/Matrix.mjs'; import { RAD_TO_DEG, DEG_TO_RAD } from '../../maths/misc/const.mjs'; import { ObservablePoint } from '../../maths/point/ObservablePoint.mjs'; import { uid } from '../../utils/data/uid.mjs'; import { deprecation, v8_0_0 } from '../../utils/logging/deprecation.mjs'; import { BigPool } from '../../utils/pool/PoolGroup.mjs'; import { cacheAsTextureMixin } from './container-mixins/cacheAsTextureMixin.mjs'; import { childrenHelperMixin } from './container-mixins/childrenHelperMixin.mjs'; import { collectRenderablesMixin } from './container-mixins/collectRenderablesMixin.mjs'; import { effectsMixin } from './container-mixins/effectsMixin.mjs'; import { findMixin } from './container-mixins/findMixin.mjs'; import { getFastGlobalBoundsMixin } from './container-mixins/getFastGlobalBoundsMixin.mjs'; import { bgr2rgb, getGlobalMixin } from './container-mixins/getGlobalMixin.mjs'; import { measureMixin } from './container-mixins/measureMixin.mjs'; import { onRenderMixin } from './container-mixins/onRenderMixin.mjs'; import { sortMixin } from './container-mixins/sortMixin.mjs'; import { toLocalGlobalMixin } from './container-mixins/toLocalGlobalMixin.mjs'; import { RenderGroup } from './RenderGroup.mjs'; import { assignWithIgnore } from './utils/assignWithIgnore.mjs'; "use strict"; const defaultSkew = new ObservablePoint(null); const defaultPivot = new ObservablePoint(null); const defaultScale = new ObservablePoint(null, 1, 1); const UPDATE_COLOR = 1; const UPDATE_BLEND = 2; const UPDATE_VISIBLE = 4; const UPDATE_TRANSFORM = 8; class Container extends EventEmitter { constructor(options = {}) { super(); /** * unique id for this container * @internal */ this.uid = uid("renderable"); /** @private */ this._updateFlags = 15; // the render group this container owns /** @private */ this.renderGroup = null; // the render group this container belongs to /** @private */ this.parentRenderGroup = null; // the index of the container in the render group /** @private */ this.parentRenderGroupIndex = 0; // set to true if the container has changed. It is reset once the changes have been applied // by the transform system // its here to stop ensure that when things change, only one update gets registers with the transform system /** @private */ this.didChange = false; // same as above, but for the renderable /** @private */ this.didViewUpdate = false; // how deep is the container relative to its render group.. // unless the element is the root render group - it will be relative to its parent /** @private */ this.relativeRenderGroupDepth = 0; /** * The array of children of this container. Each child must be a Container or extend from it. * * The array is read-only, but its contents can be modified using Container methods. * @example * ```ts * // Access children * const firstChild = container.children[0]; * const lastChild = container.children[container.children.length - 1]; * ``` * @readonly * @see {@link Container#addChild} For adding children * @see {@link Container#removeChild} For removing children */ this.children = []; /** * The display object container that contains this display object. * This represents the parent-child relationship in the display tree. * @example * ```ts * // Basic parent access * const parent = sprite.parent; * * // Walk up the tree * let current = sprite; * while (current.parent) { * console.log('Level up:', current.parent.constructor.name); * current = current.parent; * } * ``` * @readonly * @see {@link Container#addChild} For adding to a parent * @see {@link Container#removeChild} For removing from parent */ this.parent = null; // used internally for changing up the render order.. mainly for masks and filters // TODO setting this should cause a rebuild?? /** @private */ this.includeInBuild = true; /** @private */ this.measurable = true; /** @private */ this.isSimple = true; // / /////////////Transform related props////////////// // used by the transform system to check if a container needs to be updated that frame // if the tick matches the current transform system tick, it is not updated again /** @internal */ this.updateTick = -1; /** * Current transform of the object based on local factors: position, scale, other stuff. * This matrix represents the local transformation without any parent influence. * @example * ```ts * // Basic transform access * const localMatrix = sprite.localTransform; * console.log(localMatrix.toString()); * ``` * @readonly * @see {@link Container#worldTransform} For global transform * @see {@link Container#groupTransform} For render group transform */ this.localTransform = new Matrix(); /** * The relative group transform is a transform relative to the render group it belongs too. It will include all parent * transforms and up to the render group (think of it as kind of like a stage - but the stage can be nested). * If this container is is self a render group matrix will be relative to its parent render group * @readonly * @advanced */ this.relativeGroupTransform = new Matrix(); /** * The group transform is a transform relative to the render group it belongs too. * If this container is render group then this will be an identity matrix. other wise it * will be the same as the relativeGroupTransform. * Use this value when actually rendering things to the screen * @readonly * @advanced */ this.groupTransform = this.relativeGroupTransform; /** * Whether this object has been destroyed. If true, the object should no longer be used. * After an object is destroyed, all of its functionality is disabled and references are removed. * @example * ```ts * // Cleanup with destroy * sprite.destroy(); * console.log(sprite.destroyed); // true * ``` * @default false * @see {@link Container#destroy} For destroying objects */ this.destroyed = false; // transform data.. /** * The coordinate of the object relative to the local coordinates of the parent. * @internal */ this._position = new ObservablePoint(this, 0, 0); /** * The scale factor of the object. * @internal */ this._scale = defaultScale; /** * The pivot point of the container that it rotates around. * @internal */ this._pivot = defaultPivot; /** * The skew amount, on the x and y axis. * @internal */ this._skew = defaultSkew; /** * The X-coordinate value of the normalized local X axis, * the first column of the local transformation matrix without a scale. * @internal */ this._cx = 1; /** * The Y-coordinate value of the normalized local X axis, * the first column of the local transformation matrix without a scale. * @internal */ this._sx = 0; /** * The X-coordinate value of the normalized local Y axis, * the second column of the local transformation matrix without a scale. * @internal */ this._cy = 0; /** * The Y-coordinate value of the normalized local Y axis, * the second column of the local transformation matrix without a scale. * @internal */ this._sy = 1; /** * The rotation amount. * @internal */ this._rotation = 0; // / COLOR related props ////////////// // color stored as ABGR /** @internal */ this.localColor = 16777215; /** @internal */ this.localAlpha = 1; /** @internal */ this.groupAlpha = 1; // A /** @internal */ this.groupColor = 16777215; // BGR /** @internal */ this.groupColorAlpha = 4294967295; // ABGR // / BLEND related props ////////////// /** @internal */ this.localBlendMode = "inherit"; /** @internal */ this.groupBlendMode = "normal"; // / VISIBILITY related props ////////////// // visibility // 0b11 // first bit is visible, second bit is renderable /** * This property holds three bits: culled, visible, renderable * the third bit represents culling (0 = culled, 1 = not culled) 0b100 * the second bit represents visibility (0 = not visible, 1 = visible) 0b010 * the first bit represents renderable (0 = not renderable, 1 = renderable) 0b001 * @internal */ this.localDisplayStatus = 7; // 0b11 | 0b10 | 0b01 | 0b00 /** @internal */ this.globalDisplayStatus = 7; /** * A value that increments each time the containe is modified * eg children added, removed etc * @ignore */ this._didContainerChangeTick = 0; /** * A value that increments each time the container view is modified * eg texture swap, geometry change etc * @ignore */ this._didViewChangeTick = 0; /** * property that tracks if the container transform has changed * @ignore */ this._didLocalTransformChangeId = -1; this.effects = []; assignWithIgnore(this, options, { children: true, parent: true, effects: true }); options.children?.forEach((child) => this.addChild(child)); options.parent?.addChild(this); } /** * Mixes all enumerable properties and methods from a source object to Container. * @param source - The source of properties and methods to mix in. * @deprecated since 8.8.0 */ static mixin(source) { deprecation("8.8.0", "Container.mixin is deprecated, please use extensions.mixin instead."); extensions.mixin(Container, source); } // = 'default'; /** * We now use the _didContainerChangeTick and _didViewChangeTick to track changes * @deprecated since 8.2.6 * @ignore */ set _didChangeId(value) { this._didViewChangeTick = value >> 12 & 4095; this._didContainerChangeTick = value & 4095; } /** @ignore */ get _didChangeId() { return this._didContainerChangeTick & 4095 | (this._didViewChangeTick & 4095) << 12; } /** * Adds one or more children to the container. * The children will be rendered as part of this container's display list. * @example * ```ts * // Add a single child * container.addChild(sprite); * * // Add multiple children * container.addChild(background, player, foreground); * * // Add with type checking * const sprite = container.addChild<Sprite>(new Sprite(texture)); * sprite.tint = 'red'; * ``` * @param children - The Container(s) to add to the container * @returns The first child that was added * @see {@link Container#removeChild} For removing children * @see {@link Container#addChildAt} For adding at specific index */ addChild(...children) { if (!this.allowChildren) { deprecation(v8_0_0, "addChild: Only Containers will be allowed to add children in v8.0.0"); } if (children.length > 1) { for (let i = 0; i < children.length; i++) { this.addChild(children[i]); } return children[0]; } const child = children[0]; const renderGroup = this.renderGroup || this.parentRenderGroup; if (child.parent === this) { this.children.splice(this.children.indexOf(child), 1); this.children.push(child); if (renderGroup) { renderGroup.structureDidChange = true; } return child; } if (child.parent) { child.parent.removeChild(child); } this.children.push(child); if (this.sortableChildren) this.sortDirty = true; child.parent = this; child.didChange = true; child._updateFlags = 15; if (renderGroup) { renderGroup.addChild(child); } this.emit("childAdded", child, this, this.children.length - 1); child.emit("added", this); this._didViewChangeTick++; if (child._zIndex !== 0) { child.depthOfChildModified(); } return child; } /** * Removes one or more children from the container. * When removing multiple children, events will be triggered for each child in sequence. * @example * ```ts * // Remove a single child * const removed = container.removeChild(sprite); * * // Remove multiple children * const bg = container.removeChild(background, player, userInterface); * * // Remove with type checking * const sprite = container.removeChild<Sprite>(childSprite); * sprite.texture = newTexture; * ``` * @param children - The Container(s) to remove * @returns The first child that was removed * @see {@link Container#addChild} For adding children * @see {@link Container#removeChildren} For removing multiple children */ removeChild(...children) { if (children.length > 1) { for (let i = 0; i < children.length; i++) { this.removeChild(children[i]); } return children[0]; } const child = children[0]; const index = this.children.indexOf(child); if (index > -1) { this._didViewChangeTick++; this.children.splice(index, 1); if (this.renderGroup) { this.renderGroup.removeChild(child); } else if (this.parentRenderGroup) { this.parentRenderGroup.removeChild(child); } if (child.parentRenderLayer) { child.parentRenderLayer.detach(child); } child.parent = null; this.emit("childRemoved", child, this, index); child.emit("removed", this); } return child; } /** @ignore */ _onUpdate(point) { if (point) { if (point === this._skew) { this._updateSkew(); } } this._didContainerChangeTick++; if (this.didChange) return; this.didChange = true; if (this.parentRenderGroup) { this.parentRenderGroup.onChildUpdate(this); } } set isRenderGroup(value) { if (!!this.renderGroup === value) return; if (value) { this.enableRenderGroup(); } else { this.disableRenderGroup(); } } /** * Returns true if this container is a render group. * This means that it will be rendered as a separate pass, with its own set of instructions * @advanced */ get isRenderGroup() { return !!this.renderGroup; } /** * Calling this enables a render group for this container. * This means it will be rendered as a separate set of instructions. * The transform of the container will also be handled on the GPU rather than the CPU. * @advanced */ enableRenderGroup() { if (this.renderGroup) return; const parentRenderGroup = this.parentRenderGroup; parentRenderGroup?.removeChild(this); this.renderGroup = BigPool.get(RenderGroup, this); this.groupTransform = Matrix.IDENTITY; parentRenderGroup?.addChild(this); this._updateIsSimple(); } /** * This will disable the render group for this container. * @advanced */ disableRenderGroup() { if (!this.renderGroup) return; const parentRenderGroup = this.parentRenderGroup; parentRenderGroup?.removeChild(this); BigPool.return(this.renderGroup); this.renderGroup = null; this.groupTransform = this.relativeGroupTransform; parentRenderGroup?.addChild(this); this._updateIsSimple(); } /** @ignore */ _updateIsSimple() { this.isSimple = !this.renderGroup && this.effects.length === 0; } /** * Current transform of the object based on world (parent) factors. * * This matrix represents the absolute transformation in the scene graph. * @example * ```ts * // Get world position * const worldPos = container.worldTransform; * console.log(`World position: (${worldPos.tx}, ${worldPos.ty})`); * ``` * @readonly * @see {@link Container#localTransform} For local space transform */ get worldTransform() { this._worldTransform || (this._worldTransform = new Matrix()); if (this.renderGroup) { this._worldTransform.copyFrom(this.renderGroup.worldTransform); } else if (this.parentRenderGroup) { this._worldTransform.appendFrom(this.relativeGroupTransform, this.parentRenderGroup.worldTransform); } return this._worldTransform; } /** * The position of the container on the x axis relative to the local coordinates of the parent. * * An alias to position.x * @example * ```ts * // Basic position * container.x = 100; * ``` */ get x() { return this._position.x; } set x(value) { this._position.x = value; } /** * The position of the container on the y axis relative to the local coordinates of the parent. * * An alias to position.y * @example * ```ts * // Basic position * container.y = 200; * ``` */ get y() { return this._position.y; } set y(value) { this._position.y = value; } /** * The coordinate of the object relative to the local coordinates of the parent. * @example * ```ts * // Basic position setting * container.position.set(100, 200); * container.position.set(100); // Sets both x and y to 100 * // Using point data * container.position = { x: 50, y: 75 }; * ``` * @since 4.0.0 */ get position() { return this._position; } set position(value) { this._position.copyFrom(value); } /** * The rotation of the object in radians. * * > [!NOTE] 'rotation' and 'angle' have the same effect on a display object; * > rotation is in radians, angle is in degrees. * @example * ```ts * // Basic rotation * container.rotation = Math.PI / 4; // 45 degrees * * // Convert from degrees * const degrees = 45; * container.rotation = degrees * Math.PI / 180; * * // Rotate around center * container.pivot.set(container.width / 2, container.height / 2); * container.rotation = Math.PI; // 180 degrees * ``` */ get rotation() { return this._rotation; } set rotation(value) { if (this._rotation !== value) { this._rotation = value; this._onUpdate(this._skew); } } /** * The angle of the object in degrees. * * > [!NOTE] 'rotation' and 'angle' have the same effect on a display object; * > rotation is in radians, angle is in degrees. @example * ```ts * // Basic angle rotation * sprite.angle = 45; // 45 degrees * * // Rotate around center * sprite.pivot.set(sprite.width / 2, sprite.height / 2); * sprite.angle = 180; // Half rotation * * // Reset rotation * sprite.angle = 0; * ``` */ get angle() { return this.rotation * RAD_TO_DEG; } set angle(value) { this.rotation = value * DEG_TO_RAD; } /** * The center of rotation, scaling, and skewing for this display object in its local space. * The `position` is the projection of `pivot` in the parent's local space. * * By default, the pivot is the origin (0, 0). * @example * ```ts * // Rotate around center * container.pivot.set(container.width / 2, container.height / 2); * container.rotation = Math.PI; // Rotates around center * ``` * @since 4.0.0 */ get pivot() { if (this._pivot === defaultPivot) { this._pivot = new ObservablePoint(this, 0, 0); } return this._pivot; } set pivot(value) { if (this._pivot === defaultPivot) { this._pivot = new ObservablePoint(this, 0, 0); } typeof value === "number" ? this._pivot.set(value) : this._pivot.copyFrom(value); } /** * The skew factor for the object in radians. Skewing is a transformation that distorts * the object by rotating it differently at each point, creating a non-uniform shape. * @example * ```ts * // Basic skewing * container.skew.set(0.5, 0); // Skew horizontally * container.skew.set(0, 0.5); // Skew vertically * * // Skew with point data * container.skew = { x: 0.3, y: 0.3 }; // Diagonal skew * * // Reset skew * container.skew.set(0, 0); * * // Animate skew * app.ticker.add(() => { * // Create wave effect * container.skew.x = Math.sin(Date.now() / 1000) * 0.3; * }); * * // Combine with rotation * container.rotation = Math.PI / 4; // 45 degrees * container.skew.set(0.2, 0.2); // Skew the rotated object * ``` * @since 4.0.0 * @type {ObservablePoint} Point-like object with x/y properties in radians * @default {x: 0, y: 0} */ get skew() { if (this._skew === defaultSkew) { this._skew = new ObservablePoint(this, 0, 0); } return this._skew; } set skew(value) { if (this._skew === defaultSkew) { this._skew = new ObservablePoint(this, 0, 0); } this._skew.copyFrom(value); } /** * The scale factors of this object along the local coordinate axes. * * The default scale is (1, 1). * @example * ```ts * // Basic scaling * container.scale.set(2, 2); // Scales to double size * container.scale.set(2); // Scales uniformly to double size * container.scale = 2; // Scales uniformly to double size * // Scale to a specific width and height * container.setSize(200, 100); // Sets width to 200 and height to 100 * ``` * @since 4.0.0 */ get scale() { if (this._scale === defaultScale) { this._scale = new ObservablePoint(this, 1, 1); } return this._scale; } set scale(value) { if (this._scale === defaultScale) { this._scale = new ObservablePoint(this, 0, 0); } typeof value === "number" ? this._scale.set(value) : this._scale.copyFrom(value); } /** * The width of the Container, setting this will actually modify the scale to achieve the value set. * > [!NOTE] Changing the width will adjust the scale.x property of the container while maintaining its aspect ratio. * > [!NOTE] If you want to set both width and height at the same time, use {@link Container#setSize} * as it is more optimized by not recalculating the local bounds twice. * @example * ```ts * // Basic width setting * container.width = 100; * // Optimized width setting * container.setSize(100, 100); * ``` */ get width() { return Math.abs(this.scale.x * this.getLocalBounds().width); } set width(value) { const localWidth = this.getLocalBounds().width; this._setWidth(value, localWidth); } /** * The height of the Container, * > [!NOTE] Changing the height will adjust the scale.y property of the container while maintaining its aspect ratio. * > [!NOTE] If you want to set both width and height at the same time, use {@link Container#setSize} * as it is more optimized by not recalculating the local bounds twice. * @example * ```ts * // Basic height setting * container.height = 200; * // Optimized height setting * container.setSize(100, 200); * ``` */ get height() { return Math.abs(this.scale.y * this.getLocalBounds().height); } set height(value) { const localHeight = this.getLocalBounds().height; this._setHeight(value, localHeight); } /** * Retrieves the size of the container as a [Size]{@link Size} object. * * This is faster than get the width and height separately. * @example * ```ts * // Basic size retrieval * const size = container.getSize(); * console.log(`Size: ${size.width}x${size.height}`); * * // Reuse existing size object * const reuseSize = { width: 0, height: 0 }; * container.getSize(reuseSize); * ``` * @param out - Optional object to store the size in. * @returns - The size of the container. */ getSize(out) { if (!out) { out = {}; } const bounds = this.getLocalBounds(); out.width = Math.abs(this.scale.x * bounds.width); out.height = Math.abs(this.scale.y * bounds.height); return out; } /** * Sets the size of the container to the specified width and height. * This is more efficient than setting width and height separately as it only recalculates bounds once. * @example * ```ts * // Basic size setting * container.setSize(100, 200); * * // Set uniform size * container.setSize(100); // Sets both width and height to 100 * ``` * @param value - This can be either a number or a [Size]{@link Size} object. * @param height - The height to set. Defaults to the value of `width` if not provided. */ setSize(value, height) { const size = this.getLocalBounds(); if (typeof value === "object") { height = value.height ?? value.width; value = value.width; } else { height ?? (height = value); } value !== void 0 && this._setWidth(value, size.width); height !== void 0 && this._setHeight(height, size.height); } /** Called when the skew or the rotation changes. */ _updateSkew() { const rotation = this._rotation; const skew = this._skew; this._cx = Math.cos(rotation + skew._y); this._sx = Math.sin(rotation + skew._y); this._cy = -Math.sin(rotation - skew._x); this._sy = Math.cos(rotation - skew._x); } /** * Updates the transform properties of the container. * Allows partial updates of transform properties for optimized manipulation. * @example * ```ts * // Basic transform update * container.updateTransform({ * x: 100, * y: 200, * rotation: Math.PI / 4 * }); * * // Scale and rotate around center * sprite.updateTransform({ * pivotX: sprite.width / 2, * pivotY: sprite.height / 2, * scaleX: 2, * scaleY: 2, * rotation: Math.PI * }); * * // Update position only * button.updateTransform({ * x: button.x + 10, // Move right * y: button.y // Keep same y * }); * ``` * @param opts - Transform options to update * @param opts.x - The x position * @param opts.y - The y position * @param opts.scaleX - The x-axis scale factor * @param opts.scaleY - The y-axis scale factor * @param opts.rotation - The rotation in radians * @param opts.skewX - The x-axis skew factor * @param opts.skewY - The y-axis skew factor * @param opts.pivotX - The x-axis pivot point * @param opts.pivotY - The y-axis pivot point * @returns This container, for chaining * @see {@link Container#setFromMatrix} For matrix-based transforms * @see {@link Container#position} For direct position access */ updateTransform(opts) { this.position.set( typeof opts.x === "number" ? opts.x : this.position.x, typeof opts.y === "number" ? opts.y : this.position.y ); this.scale.set( typeof opts.scaleX === "number" ? opts.scaleX || 1 : this.scale.x, typeof opts.scaleY === "number" ? opts.scaleY || 1 : this.scale.y ); this.rotation = typeof opts.rotation === "number" ? opts.rotation : this.rotation; this.skew.set( typeof opts.skewX === "number" ? opts.skewX : this.skew.x, typeof opts.skewY === "number" ? opts.skewY : this.skew.y ); this.pivot.set( typeof opts.pivotX === "number" ? opts.pivotX : this.pivot.x, typeof opts.pivotY === "number" ? opts.pivotY : this.pivot.y ); return this; } /** * Updates the local transform properties by decomposing the given matrix. * Extracts position, scale, rotation, and skew from a transformation matrix. * @example * ```ts * // Basic matrix transform * const matrix = new Matrix() * .translate(100, 100) * .rotate(Math.PI / 4) * .scale(2, 2); * * container.setFromMatrix(matrix); * * // Copy transform from another container * const source = new Container(); * source.position.set(100, 100); * source.rotation = Math.PI / 2; * * target.setFromMatrix(source.localTransform); * * // Reset transform * container.setFromMatrix(Matrix.IDENTITY); * ``` * @param matrix - The matrix to use for updating the transform * @see {@link Container#updateTransform} For property-based updates * @see {@link Matrix#decompose} For matrix decomposition details */ setFromMatrix(matrix) { matrix.decompose(this); } /** Updates the local transform. */ updateLocalTransform() { const localTransformChangeId = this._didContainerChangeTick; if (this._didLocalTransformChangeId === localTransformChangeId) return; this._didLocalTransformChangeId = localTransformChangeId; const lt = this.localTransform; const scale = this._scale; const pivot = this._pivot; const position = this._position; const sx = scale._x; const sy = scale._y; const px = pivot._x; const py = pivot._y; lt.a = this._cx * sx; lt.b = this._sx * sx; lt.c = this._cy * sy; lt.d = this._sy * sy; lt.tx = position._x - (px * lt.a + py * lt.c); lt.ty = position._y - (px * lt.b + py * lt.d); } // / ///// color related stuff set alpha(value) { if (value === this.localAlpha) return; this.localAlpha = value; this._updateFlags |= UPDATE_COLOR; this._onUpdate(); } /** * The opacity of the object relative to its parent's opacity. * Value ranges from 0 (fully transparent) to 1 (fully opaque). * @example * ```ts * // Basic transparency * sprite.alpha = 0.5; // 50% opacity * * // Inherited opacity * container.alpha = 0.5; * const child = new Sprite(texture); * child.alpha = 0.5; * container.addChild(child); * // child's effective opacity is 0.25 (0.5 * 0.5) * ``` * @default 1 * @see {@link Container#visible} For toggling visibility * @see {@link Container#renderable} For render control */ get alpha() { return this.localAlpha; } set tint(value) { const tempColor = Color.shared.setValue(value ?? 16777215); const bgr = tempColor.toBgrNumber(); if (bgr === this.localColor) return; this.localColor = bgr; this._updateFlags |= UPDATE_COLOR; this._onUpdate(); } /** * The tint applied to the sprite. * * This can be any valid {@link ColorSource}. * @example * ```ts * // Basic color tinting * container.tint = 0xff0000; // Red tint * container.tint = 'red'; // Same as above * container.tint = '#00ff00'; // Green * container.tint = 'rgb(0,0,255)'; // Blue * * // Remove tint * container.tint = 0xffffff; // White = no tint * container.tint = null; // Also removes tint * ``` * @default 0xFFFFFF * @see {@link Container#alpha} For transparency * @see {@link Container#visible} For visibility control */ get tint() { return bgr2rgb(this.localColor); } // / //////////////// blend related stuff set blendMode(value) { if (this.localBlendMode === value) return; if (this.parentRenderGroup) { this.parentRenderGroup.structureDidChange = true; } this._updateFlags |= UPDATE_BLEND; this.localBlendMode = value; this._onUpdate(); } /** * The blend mode to be applied to the sprite. Controls how pixels are blended when rendering. * * Setting to 'normal' will reset to default blending. * > [!NOTE] More blend modes are available after importing the `pixi.js/advanced-blend-modes` sub-export. * @example * ```ts * // Basic blend modes * sprite.blendMode = 'add'; // Additive blending * sprite.blendMode = 'multiply'; // Multiply colors * sprite.blendMode = 'screen'; // Screen blend * * // Reset blend mode * sprite.blendMode = 'normal'; // Normal blending * ``` * @default 'normal' * @see {@link Container#alpha} For transparency * @see {@link Container#tint} For color adjustments */ get blendMode() { return this.localBlendMode; } // / ///////// VISIBILITY / RENDERABLE ///////////////// /** * The visibility of the object. If false the object will not be drawn, * and the transform will not be updated. * @example * ```ts * // Basic visibility toggle * sprite.visible = false; // Hide sprite * sprite.visible = true; // Show sprite * ``` * @default true * @see {@link Container#renderable} For render-only control * @see {@link Container#alpha} For transparency */ get visible() { return !!(this.localDisplayStatus & 2); } set visible(value) { const valueNumber = value ? 2 : 0; if ((this.localDisplayStatus & 2) === valueNumber) return; if (this.parentRenderGroup) { this.parentRenderGroup.structureDidChange = true; } this._updateFlags |= UPDATE_VISIBLE; this.localDisplayStatus ^= 2; this._onUpdate(); } /** @ignore */ get culled() { return !(this.localDisplayStatus & 4); } /** @ignore */ set culled(value) { const valueNumber = value ? 0 : 4; if ((this.localDisplayStatus & 4) === valueNumber) return; if (this.parentRenderGroup) { this.parentRenderGroup.structureDidChange = true; } this._updateFlags |= UPDATE_VISIBLE; this.localDisplayStatus ^= 4; this._onUpdate(); } /** * Controls whether this object can be rendered. If false the object will not be drawn, * but the transform will still be updated. This is different from visible, which skips * transform updates. * @example * ```ts * // Basic render control * sprite.renderable = false; // Skip rendering * sprite.renderable = true; // Enable rendering * ``` * @default true * @see {@link Container#visible} For skipping transform updates * @see {@link Container#alpha} For transparency */ get renderable() { return !!(this.localDisplayStatus & 1); } set renderable(value) { const valueNumber = value ? 1 : 0; if ((this.localDisplayStatus & 1) === valueNumber) return; this._updateFlags |= UPDATE_VISIBLE; this.localDisplayStatus ^= 1; if (this.parentRenderGroup) { this.parentRenderGroup.structureDidChange = true; } this._onUpdate(); } /** * Whether or not the object should be rendered. * @advanced */ get isRenderable() { return this.localDisplayStatus === 7 && this.groupAlpha > 0; } /** * Removes all internal references and listeners as well as removes children from the display list. * Do not use a Container after calling `destroy`. * @param options - Options parameter. A boolean will act as if all options * have been set to that value * @example * ```ts * container.destroy(); * container.destroy(true); * container.destroy({ children: true }); * container.destroy({ children: true, texture: true, textureSource: true }); * ``` */ destroy(options = false) { if (this.destroyed) return; this.destroyed = true; let oldChildren; if (this.children.length) { oldChildren = this.removeChildren(0, this.children.length); } this.removeFromParent(); this.parent = null; this._maskEffect = null; this._filterEffect = null; this.effects = null; this._position = null; this._scale = null; this._pivot = null; this._skew = null; this.emit("destroyed", this); this.removeAllListeners(); const destroyChildren = typeof options === "boolean" ? options : options?.children; if (destroyChildren && oldChildren) { for (let i = 0; i < oldChildren.length; ++i) { oldChildren[i].destroy(options); } } this.renderGroup?.destroy(); this.renderGroup = null; } } extensions.mixin( Container, childrenHelperMixin, getFastGlobalBoundsMixin, toLocalGlobalMixin, onRenderMixin, measureMixin, effectsMixin, findMixin, sortMixin, cullingMixin, cacheAsTextureMixin, getGlobalMixin, collectRenderablesMixin ); export { Container, UPDATE_BLEND, UPDATE_COLOR, UPDATE_TRANSFORM, UPDATE_VISIBLE }; //# sourceMappingURL=Container.mjs.map