diff --git a/src/Drawable.js b/src/Drawable.js index dec9c9e..999108d 100644 --- a/src/Drawable.js +++ b/src/Drawable.js @@ -69,9 +69,8 @@ class Drawable { * Dispose of this Drawable. Do not use it after calling this method. */ dispose () { - if (this._id >= 0) { - delete Drawable[this._id]; - } + // Use the setter: disconnect events + this.skin = null; } /** diff --git a/src/RenderConstants.js b/src/RenderConstants.js index 9492432..a76497c 100644 --- a/src/RenderConstants.js +++ b/src/RenderConstants.js @@ -21,5 +21,11 @@ module.exports = { * TODO: Remove this in favor of falling back on a built-in skin. * @type {string} */ - DEFAULT_SKIN: DEFAULT_SKIN + DEFAULT_SKIN: DEFAULT_SKIN, + + /** + * Optimize for fewer than this number of Drawables sharing the same Skin. + * Going above this may cause middleware warnings or a performance penalty but should otherwise behave correctly. + */ + SKIN_SHARE_SOFT_LIMIT: 300 }; diff --git a/src/RenderWebGL.js b/src/RenderWebGL.js index d2c20ea..2caa6ec 100644 --- a/src/RenderWebGL.js +++ b/src/RenderWebGL.js @@ -135,16 +135,27 @@ class RenderWebGL { } /** - * Create a new skin by loading a bitmap or vector image from a URL. + * Create a skin by loading a bitmap or vector image from a URL, or reuse an existing skin created this way. * WARNING: This method is deprecated and will be removed in the near future. * Use `createBitmapSkin` or `createSVGSkin` instead. * @param {!string} skinUrl The URL of the skin. - * @param {!int} [costumeResolution] Optionally, a resolution for the skin. Bitmap only. - * @returns {!int} The ID of the new Skin. + * @param {!int} [costumeResolution] Optional: resolution for the skin. Ignored unless creating a new Bitmap skin. + * @returns {!int} The ID of the Skin. * @deprecated */ createSkinFromURL (skinUrl, costumeResolution) { + if (this._skinUrlMap.hasOwnProperty(skinUrl)) { + const existingId = this._skinUrlMap[skinUrl]; + + // Make sure the "existing" skin hasn't been destroyed + if (this._allSkins[existingId]) { + return existingId; + } + } + const skinId = this._nextSkinId++; + this._skinUrlMap[skinUrl] = skinId; + let newSkin; let isVector; @@ -660,12 +671,15 @@ class RenderWebGL { */ updateDrawableProperties (drawableID, properties) { const drawable = this._allDrawables[drawableID]; + if (!drawable) { + // TODO: fix whatever's wrong in the VM which causes this, then add a warning or throw here. + // Right now this happens so much on some projects that a warning or exception here can hang the browser. + return; + } // TODO: remove this after fully deprecating URL-based skin paths if ('skin' in properties) { const {skin, costumeResolution} = properties; - const skinId = this._skinUrlMap.hasOwnProperty(skin) ? - this._skinUrlMap[skin] : - this._skinUrlMap[skin] = this.createSkinFromURL(skin, costumeResolution); + const skinId = this.createSkinFromURL(skin, costumeResolution); drawable.skin = this._allSkins[skinId]; } if ('skinId' in properties) { diff --git a/src/Skin.js b/src/Skin.js index 8386f3b..a307134 100644 --- a/src/Skin.js +++ b/src/Skin.js @@ -37,6 +37,8 @@ class Skin extends EventEmitter { */ u_skin: null }; + + this.setMaxListeners(RenderConstants.SKIN_SHARE_SOFT_LIMIT); } /**