Jump to content

Destroy Pixi.CocoonText Pixi.DisplayText


vbrepo
 Share

Recommended Posts

Hey, 

I am new to Pixi and that's probably the real issue :-) We created a game called blobber.io and have an enourmous memory leak with pixi.CocoonText not releasing its memory. Is probably a destroy that is not called but I can't find and see how and where to actually set it. We have a simple gameloop and at the beginning we call the graph.clear(). Within this gameloop we call the drawPlayers functions which is calling the setText in renderer.js. I am completely lost here. I tried everything but am really blocked here. 

 

export default () => {
  const scale = window.innerHeight / vars.screenHeight;
  graph.clear();
  const textStyle = {
    font: '30px bold sans-serif',
    fill: playerConfig.textColor,
    stroke: playerConfig.textBorder,
    x: vars.screenWidth / 2,
    y: vars.screenHeight / 2,
  };

  if (!vars.disconnected) {
    if (vars.gameStart) {
      renderer.setText(vars.died ? 'You died!' : '', 'state', textStyle);
      renderer.ground.tilePosition.set(
        -player.x * scale,
        -player.y * scale
      );

       if (vars.borderDraw) {
        drawborder();
      }

      const orderMass = [];
      // console.log(`Users: ${objs.users.length}`);
      for (let i = 0; i < objs.users.length; i++) {
        if (objs.users.type === 'player') {
          orderMass.push(i);
        }
      }

      if (objs.playerCells.length > 0) {
        // calcViewZoom();
        let c = 0;
        let a = 0;
        for (let i = 0; i < objs.playerCells.length; i++) {
          // playerCells.updatePos();
          a += objs.playerCells.x / objs.playerCells.length;
          c += objs.playerCells.y / objs.playerCells.length;
        }
        // vars.posX = a;
        // vars.posY = c;
        // vars.posSize = vars.viewZoom;
        vars.nodeX = (vars.nodeX + a) / 2;
        vars.nodeY = (vars.nodeY + c) / 2;
      } else {
        // vars.nodeX = (29 * vars.nodeX + vars.posX) / 30;
        // vars.nodeY = (29 * vars.nodeY + vars.posY) / 30;
        // vars.viewZoom = (9 * vars.viewZoom + vars.posSize * viewRange()) / 10;
      }
      drawPlayers(orderMass);
    }

    if (vars.died) {
      renderer.setText('Game Over!', 'state', textStyle);
    }
  } else {
    graph.beginFill(0x171717);
    graph.lineStyle(0);
    graph.drawRect(0, 0, vars.screenWidth, vars.screenHeight);
    graph.endFill();

    if (vars.kicked) {
      if (vars.reason !== '') {
        renderer.setText(`You were kicked for:\r\n${vars.reason}`, 'state', textStyle);
      } else {
        renderer.setText('You were kicked!', 'state', textStyle);
      }
    } else {
      renderer.setText('Disconnected!', 'state', textStyle);
    }
  }
  renderer && renderer.render();
};
 

in renderer.js

 

export default class Rendered {
  /**
   * @param {HTMLCanvasElement} canvas
   */
  constructor(canvas) {
    this.canvas = canvas;
    this.renderer = PIXI.autoDetectRenderer(innerWidth, innerHeight, {
      view: canvas,
      transparent: true,
      antialias: false
    });
    this.container = new PIXI.Container();
    this.stage = new PIXI.Container();
    this.graph = new PIXI.Graphics();
    this.graphInfo = new PIXI.Graphics();
    this.ground = new PIXI.extras.TilingSprite(LightGroundTexture);
    this.ground.uvRespectAnchor = true;
    this.ground.anchor.set(0.5,0.5);
    this.container.addChild(this.ground);
    this.container.addChild(this.graph);
    this.container.addChild(this.stage);
    this.container.addChild(this.graphInfo);
    this.stage.displayList = new PIXI.DisplayList();
    this._sprite = this.graphInfo;
    this.zoom = 1;
    this.render();
  }
  setText(...args) {
    SpriteProxyPrototype.setText.bind(this)(...args);
    for (let i in this) {
      if (i.startsWith('_text@') && this) {
        const textSprite = this;
        textSprite.scale.set(1);
        textSprite.resolution = 1;
        textSprite.position.x = this.renderer.width / 2;
        textSprite.position.y = this.renderer.height / 2;
      }
    }
  }
  render() {
    this._updateZoom();
    this.renderer.render(this.container);
  }

  static createSpriteFromeImage(src) {
    if (!textuteCache[src]) {
      const tmp = getTexture(src);
      if (tmp instanceof PIXI.Texture) {
        // console.log('MATCH SPRITE ' ,src)
        textuteCache[src] = tmp;
        return new PIXI.Sprite(tmp);
      } else if (tmp instanceof Promise) {
        // console.log('MATCH ASYNC SPRITE ' ,src)

        const sprite = new PIXI.Sprite();
        tmp.then(e => (textuteCache[src] = sprite.texture = e));
        return sprite;
      } else {
        // console.warn('MISSING SPRITE ALTATS:' +src)

        textuteCache[src] = PIXI.Texture.fromImage(src);
        return new PIXI.Sprite(textuteCache[src]);
      }
    } else {
      return new PIXI.Sprite(textuteCache[src]);
    }
  }

  set scale(value) {
    this._scale = value;
    this.stage.scale.set(this._scale);
  }

  get scale() {
    return this._scale;
  }

  set zoom(zoom) {
    if (this._zoom === undefined) {
      this.__zoom = this.___zoom = zoom;
    }
    this._zoom = zoom;
  }
  get zoom() {
    return this.___zoom || 1;
  }
  updateSkin() {
    const theme = getTheme();
    this.ground.texture = {
      'light': LightGroundTexture,
      'dark': DarkGroundTexture,
    }[theme];
  }

  _updateZoom() {
    this.___zoom += (this.__zoom - this.___zoom) * 0.5;
    this.__zoom += (this._zoom - this.__zoom) * 0.5;

    const zoom = this.zoom || 1;

    this.container.scale.set(zoom);
    this.container.position.set(
      this.renderer.width * (1 - zoom) * 0.5,
      this.renderer.height * (1 - zoom) * 0.5
    );
    this.ground.width = this.renderer.width / zoom;
    this.ground.height = this.renderer.height / zoom;
    this.ground.position.set(
      this.renderer.width * 0.5,
      this.renderer.height * 0.5
    );
  }
}

const SpriteProxyPrototype = {
  render(x, y, width, height, property = '_spriteImage') {
    this._sprite.position.set(x, y);
    this._sprite.zOrder = -width - height;
    // this._spriteImage.zOrder = -width - height
    if (this._spriteImage.width != width || this._spriteImage.height != height) {
      // console.log('setWidthHeight Run')
      this._spriteImage.width = width;
      this._spriteImage.height = height;
      if (this._maskSprite) {
        this._maskSprite.width = width;
        this._maskSprite.height = height;
      }
    }
  },
  setSrc(src, property = '_spriteImage') {
    if (!textuteCache[src]) {
      const tmp = getTexture(src);
      if (tmp instanceof PIXI.Texture) {
        // console.log('MATCH SPRITE ' ,src)
        textuteCache[src] = tmp;
        this[property].texture = tmp;
      } else if (tmp instanceof Promise) {
        // console.log('MATCH ASYNC SPRITE ' ,src)
        tmp.then(e => (textuteCache[src] = this[property].texture  = e));
      } else {
        // console.warn('MISSING SPRITE ALTATS:' +src)
        this[property].texture = textuteCache[src] = PIXI.Texture.fromImage(src);
      }
    } else if (this[property].texture != textuteCache[src]) {
      this[property].texture = textuteCache[src];
      // console.log('setSrc Run')
    }
  },
  setText(text, key, {
    font = 'bold 20px Arial',
    fill = '#ffffff',
    align = 'center',
    stroke = '#888888',
    thin = 2,
    x = 0,
    y = 0,
  } = {}) {
    const scale = (this._stage || this.stage).scale.x;
    const sym = `_text@${key}`;
    const textStyle = {
      font,
      fill,
      align,
      stroke,
      strokeThickness: thin
    };
    if (!text) {
      if (this[sym]) {
        this._sprite && this._sprite.removeChild(this[sym]);
        this[sym] = null;
      }
    } else if (!this[sym]) {
      const textSprite = new PIXI.cocoontext.CocoonText(text, textStyle);
        // console.log(textSprite);
      // var textSprite = new  PIXI.Text(text, textStyle);
      textSprite.resolution = scale * devicePixelRatio * 2;
      textSprite.anchor.set(0.5, 0.5);
      // textSprite.displayGroup = TextGroup;
      textSprite.position.set(x, y);
      this[sym] = textSprite;
      textSprite.scale.set(1 / scale);
      this._sprite && this._sprite.addChild(textSprite);
      // console.log(this._sprite && this._sprite.addChild(textSprite));
    } else {
      const textSprite = this[sym];
      let changeStyle = false;
      if (textSprite.text != text) {
        textSprite.text = text;
      }
      textSprite.position.set(x, y);
      for (const i in textStyle) {
        changeStyle = changeStyle || (textStyle != textSprite.style);
      }

      textSprite.style = textStyle;

      textSprite.scale.set(1 / scale);
      textSprite.resolution = scale * devicePixelRatio * 2;
    }
  },
  setMask(src) {
    if (src == '') {
      this._sprite.removeChild(this._maskSprite);
      this._spriteImage.mask = null;
      this._maskSprite = null;
    } else if (!this._maskSprite) {
      this._maskSprite = Rendered.createSpriteFromeImage(src);
      this._maskSprite.anchor.set(0.5);
      this._sprite.addChildAt(this._maskSprite, 0);
      this._spriteImage.mask = this._maskSprite;
      // console.log('set mask done',this._maskSprite)
    } else {
      this.setSrc(src, '_maskSprite');
    }
  }
};

export function onDel(e) {
  if (e && e.cells && Object.keys(e.cells).length) {
    for (const i in e.cells) {
      onDel(e.cells);
    }
  }
  if (e) {
    e._stage && e._sprite && e._stage.removeChild(e._sprite);
    e._sprite = null;
    e._spriteImage = null;
  }
}

/**
 * @param {PIXI.Container} stage
 * @param {String} imageSrc
 */
export function SpriteProxy(stage, imageSrc = '') {
  return {
    onNew(e) {
      const sprite = new PIXI.Sprite();
      const imageSprite =  Rendered.createSpriteFromeImage((e.sprite + '').endsWith('.png') ? e.sprite : imageSrc);
      imageSprite.anchor.set(0.5, 0.5);
      sprite.addChild(imageSprite);
      stage.addChild(sprite);
      for (const i in SpriteProxyPrototype) {
        e = SpriteProxyPrototype.bind(e);
      }
      e._stage = stage;
      e._sprite = sprite;
      e._spriteImage = imageSprite;
      e._sprite.displayGroup = ObjectGroup;
    },
    onDel(e) {
      onDel(e);
    },
    onChange(e) {}
  };
}
 

 

in draw.js

function drawName(name, cell) {
  const fontSize = Math.max(cell.radius / 3 | 0, 20) | 0;
  const textStyle = {
    font: `bold ${fontSize}px Arial`,
    fill: playerConfig.textColor,
    stroke: playerConfig.textBorder
  };
   cell.setText(!Config.toggleShowNameState ? name : '', 'name', textStyle);

  const massString = Config.toggleMassState !== 0  ? Math.round(cell.mass | 0) + '' : '';
  cell.setText(massString, 'mass', {
    ...textStyle,
    font: `bold ${fontSize * 0.7 | 0}px Arial`,
    y: fontSize,
   });
}

draw.js

gameLoop.js

renderer.js

Link to comment
Share on other sites

Does it even support pixi4? It was updated long time ago, you have to ask that guy on github and post it in their issues. I used some of his plugins, and i even based pixi-compressedTextures on his code.

Anyway, you have to call "destroy()" on every text that is removed and not used anymore.

In pixiv4, "renderer.textureGC" takes care of that, by default its enabled to run every two minutes or so, but there's no guarantee it works with old CocoonText object.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...