PIXI vs Bitmap Text Pros & Cons

Kino

EIS Game Dev
Veteran
Joined
Nov 27, 2015
Messages
556
Reaction score
794
First Language
English
Primarily Uses
RMMV
Introduction
Today PIXI text and RMMV's bitmap text go head to head, going through the pros and cons of both. We're going to be more technical today and lay out the pros and cons of both choices. We're going to see when and where they're useful.

PIXI Text
PIXI text is an awesome solution for drawing text, but it is a sprite and not native RPGMakerMV code. It does not have the same support functions like other classes in MV have. However, it has more advantages if you want simple text to extremely stylish text and word wrap support.

Pros

  • Wordwrap
  • Drop shadow support
  • Gradient & Masking support
  • Can be updated/changed easily
  • Can swap text styles painlessly'
Cons

  • Can't draw icons natively
  • No text code support
  • Not static
  • Can't have multiple text styles in a single string


Bitmap Text
Bitmap text is the default drawing method for text in RPGMakerMV; each character is drawn one at a time and checked for potential text codes. It also has support for all the classes where it's used in MV. This is a great choice for anyone who wants to do heavy text processing; adding colors to words, drawing icons in your text, searching for important information in the text.

Pros

  • Text code support
  • static (doesn't need to be drawn every frame)
  • Can easily color text
  • Overlay on top of the bitmap
  • Multiple text styles in a single string
  • Less performance intensive when multiple styles required
Cons

  • No drop shadow support
  • No word wrap support
  • Does not support gradients out of the box
  • Not updated easily or styles easily swappable
  • Any changes to text must be redrawn completely
Details, Details
The key difference between both text options is how they're handled. PIXI text is a sprite based solution; RPGMakerMV's text solution is all bitmap. People say that PIXI text has better performance over RPGMakerMV's text options, but that is subjective depending on where and how it's used.

Being a sprite based solution, PIXI text's actual text is a single element with a single style option; this means you can't have multicolor text in the MV style or have to painstakingly adapt it to essentially be a bitmap option defeating the purpose. It would be a complicated process to create a PIXI text instance with multiple styles. You may have to create multiple instances of a PIXI text sprite to get the job done and that will be a huge performance hit if you're consistently drawing them to the screen. Unlike the bitmap.

The bitmap option doesn't have word wrap support but is not a sprite based solution. As a bitmap, you can change, modify, tint, all the text at once, or one character at a time. They do not come with an update function in the literal sense and can be drawn once and then exist on screen. The real problem with bitmaps is that they're not easily modifiable because they're drawn to a canvas and must be erased completely before drawing anything else.

The Verdict
Both choices have their fair share of problems. The important thing to consider is when they're useful. In RPGMakerMV PIXI text is useful when you want stylized text for headings or a simple text solution with word wrap support for your windows. Bitmap text is suited for text that may want icon support, different colored words in a string, and more.
 

Jonforum

Veteran
Veteran
Joined
Mar 28, 2016
Messages
1,623
Reaction score
1,439
First Language
French
Primarily Uses
RMMV
I work on the proceed to use several colors, styles.
I choose a system, of imbrication CHILD.
a masterPixiContainer with multiple pixi.text
is very fast render for now.
am working at the cacult of the mutiple lines.
When i add {wordWrap: ,wordWrapWidth:} for mutiples styles color

Do not forget that pixi is rendered by GPU,

So this greatly reduces the cpu load done by javascript.
can easily have 500 pixi.text a screen with fluid engine

is good idea for icon, i will maybe try to add it in pixi.text, with a canvas container




pixyMultiple style can olding all default styles

Code:
    align: 'right',
    breakWords: false, //Break words between any two letters on wordWrap
    dropShadow: false,
    dropShadowAngle: Math.PI / 6,
    dropShadowBlur: 0,
    dropShadowColor: '#000000',
    dropShadowDistance: 5,
    fill: 'black',
    fillGradientType: TEXT_GRADIENT.LINEAR_VERTICAL,
    fontFamily: 'Arial',
    fontSize: 26,
    fontStyle: 'normal', //normal|italic|oblique|initial|inherit
    fontVariant: 'normal', //normal|small-caps|initial|inherit
    fontWeight: 'normal', //normal|bold|bolder|lighter|number|initial|inherit|900|600|400
    letterSpacing: 2.2,
    lineHeight: 12,
    lineJoin: 'miter', //"bevel|round|miter"
    miterLimit: 10,
    padding: 0,
    stroke: 'black',
    strokeThickness: 4,
    textBaseline: 'alphabetic', //"alphabetic|top|hanging|middle|ideographic|bottom"
    wordWrap: false,
    wordWrapWidth: 100,
 
Last edited:

Jonforum

Veteran
Veteran
Joined
Mar 28, 2016
Messages
1,623
Reaction score
1,439
First Language
French
Primarily Uses
RMMV
  • Can't have multiple text styles in a single string.
I got it lol!
All alignment works flawlessly.
And baseLine too.
with the wordWrap

 

Kino

EIS Game Dev
Veteran
Joined
Nov 27, 2015
Messages
556
Reaction score
794
First Language
English
Primarily Uses
RMMV
That's pretty awesome! Honestly, that would change the way we handle text quite a bit.
Did you implement it with a parent container that has multiple PIXI.Text instances inside?
 

Jonforum

Veteran
Veteran
Joined
Mar 28, 2016
Messages
1,623
Reaction score
1,439
First Language
French
Primarily Uses
RMMV
That's pretty awesome! Honestly, that would change the way we handle text quite a bit.
Did you implement it with a parent container that has multiple PIXI.Text instances inside?
yes is like this
awecfvaevaee.jpg
 

Kino

EIS Game Dev
Veteran
Joined
Nov 27, 2015
Messages
556
Reaction score
794
First Language
English
Primarily Uses
RMMV
Nice job; I'm glad you got it working for you! It's great to know the idea is possible and definitely accomplishable. :yhappy:
 

Jonforum

Veteran
Veteran
Joined
Mar 28, 2016
Messages
1,623
Reaction score
1,439
First Language
French
Primarily Uses
RMMV
The part that calculates the multi styles and multipleline is the following.
It was especially the regex which was very difficult.

PHP:
//□▼↓▼□═════════════════════════════════════□□═════════════════════════════════════════════════════════□↓↓↓
// MULTISTYLES □──────────────────────────-PROTOTYPE-───────────────────────────────────────────────┐
// ¦ □ setupMultiStyle □ addNewChildPixiTxt □ outLimitCalculation □ pixiTxtPositioning
// └─────────────────────────────────────────□□□□□□□□───────────────────────────────────────────────┘
MVPixi_Text.prototype.setupMultiStyle = function(txt,style) {
    // before ALL, check if is a wordWrap multistyles or not ? (wordWrap detection work only in .default obj)
    if(style.default.wordWrap){
        this.masterMultiPixiTxt.style._wordWrap = true;
        this.masterMultiPixiTxt.style._wordWrapWidth = style.default.wordWrapWidth;
    };
    this.masterMultiPixiTxt.style._lineStyle = style.default.lineStyle||'top'; // setLineStyle 'top'||'middle'||'bottom'
    this.masterMultiPixiTxt.style._align = style.default.align||'left'; // setLineStyle 'top'||'middle'||'bottom'
    // PREPART CURRENT STYLES FOR MATCHING
    // Convert  attrname to _attrname (similar to MVPixi_Text.initialize) (pixi.text use _underscoring propriety)
        for (var tag in style) {console.log('%c tag '+tag, 'background: red; color: white; display: block;');
            for (var attrname in style[tag]) {
                console.log('attrname: ', style[tag][attrname]);
                style[tag]['_'+attrname] = style[tag][attrname];
            }
            style[tag] = new PIXI.TextStyle(style[tag]); // add missing pixi.style (security prevent error)
        }
    // INITIALISE MATCHING
    console.log('%c ↓↓↓   INITIALISE MATCHING   ↓↓↓                       ', 'background: Coral; color: white; display: block;');
    var re = /<s+\d\>(.*?)<\/s+\d>/, Match; //regexr
    console.log('%cSearch In Text: ','color: red; display: block; font-weight: bold;', txt);
    while ((Match = re.exec(txt)) !== null) {
        // if styles TAG was found!↓ ???
        var n = Match[0].match(/\d+/)[0]; // GET numberID (reference) in the style Tag: <s???>
        console.log('%cMatch <s'+n+'> was found index: '+Match.index, 'color: Coral;', Match);
        var textBefore = Match.input.slice(0,Match.index); // get string beforeMatch (is a defaultStyle txt);
        this.result.push({txt:textBefore,style:style.default,isTag:false}); // push the text beforeMatch (not TAGED);
        this.result.push({txt:Match[1],style:style['s'+n],isTag:'s'+n});// push text from Match (<>TAGED);
        txt=txt.slice((Match.index)+(Match[0].length)); // slice current txt for loop again Match;
    }
    this.result.push({txt:txt,style:style.default}); // push the last string(sliced) remaining (not TAGED);
    console.log('%cRESULT Sequential Match ', 'color: Fuchsia;font-weight: bold;', this.result);
    // ADD FINAL RESULT IN ALL CHILD OF masterPixiTxt
    this.addNewChildPixiTxt(); // see MVPixi_Text.prototype.addNewChildPixiTxt;
    console.log('%cRESULT masterPixiTxt.children', 'color: Fuchsia ; display: block;font-weight: bold;',this.masterMultiPixiTxt.children);
    return this.masterMultiPixiTxt; // return pixi object with all children (ready for calculation) see ↑↑↑ MVPixi_Text.prototype.addMultiText
};

MVPixi_Text.prototype.addNewChildPixiTxt = function() {
        console.log('%cADD CHILDREN AND CHECK WIDTH EXEED _wordWrapWidth            ', 'background: blue; color: white; display: block;');
        var inScopeHeight = 0, inScopeWidth = 0, needNewLine = false;
        for(var r=R=0;r<this.result.length;r++,R++){
            console.log('R: ', R);
            if(needNewLine){ // reset NEWlINE _listTxtWidth to 0 at start all line
                this.lineIndex++; this._listTxtHeight.push([0]); this._listTxtWidth.push([0]);this._childByIndex.push([]);
                needNewLine=false,inScopeWidth = 0,R=0;
            };
            this.result[r]._xy = [this._listTxtWidth[this.lineIndex][R],this._listTxtHeight[this.lineIndex][R]]; // add to result curent xy
            this.result[r]._line = (this.lineIndex);
            console.log('%c___this.result:___ [r]: ','background: blue; color: white; display: block;font-weight: bold;',r,this.result[r],' lineindex: ',this.lineIndex);
            var childTxt = new PIXI.Text(this.result[r].txt,this.result[r].style);
            // IF WORDWRAP ONLY
            if(this.masterMultiPixiTxt.style._wordWrap){
                console.log('%c↓↓↓Wordwrap are need, CHECKING THE _wordWrapWidth::↓↓↓_wordWrapWidth:=> ','background: DimGray;color: white; display: block;font-weight: bold;',this.masterMultiPixiTxt.style._wordWrapWidth);
                if(inScopeWidth+childTxt.width>this.masterMultiPixiTxt.style._wordWrapWidth){
                    // inScopeWidth reach outLimit of wordWrap
                    needNewLine = this.outLimitCalculation(childTxt,inScopeWidth,r); // setup this child, and return true or false
                }else{ console.log('inScopeWidth+childTxt.width: ', inScopeWidth+childTxt.width);console.log('%cWORDWRAP LIMIT REATCH □false□ at inScopeWidth: ','background: LightGray;color: Red; display: block;font-weight: bold;',inScopeWidth);}
            }
            // global update
            inScopeWidth+=childTxt.width; // fast scope calculation word array
            console.log('childTxt.width: ', childTxt.width);
            console.log('inScopeWidth: ', inScopeWidth);
            if(needNewLine){this._maxLineWidth.push(inScopeWidth)}; // storing the max line width
            this._listTxtHeight[this.lineIndex].push(childTxt.height); //store Height, see MVPixi_Text.prototype.initialize
            this._listTxtWidth[this.lineIndex].push(childTxt.width); //store Width, see MVPixi_Text.prototype.initialize
            //end add
            this._childByIndex[this.lineIndex].push(childTxt);
            this.masterMultiPixiTxt.addChild(childTxt);
        }
        this._maxLineWidth.push(inScopeWidth); // storing the last max line width
};

MVPixi_Text.prototype.outLimitCalculation = function(childTxt,inScopeWidth,r) {
    // now we need calculate the width of all letter
    var txtWidth = childTxt.width;
    console.log('%ctxtWidth=childTxt.width: ','color: Green; display: block;font-weight: bold;', txtWidth);
    var outLimit = this.masterMultiPixiTxt.style._wordWrapWidth;
    console.log('%coutLimit=inScopeWidth-this.masterMultiPixiTxt.style._wordWrapWidth: ','color: Green; display: block;font-weight: bold;', outLimit);
    var txtLenght = childTxt._text.length;
    console.log('%ctxtLenght=childTxt._text.length: ','color: Green; display: block;font-weight: bold;', txtLenght);
    var letterWidth = txtWidth/txtLenght;
    console.log('%cletterWidth=txtWidth/txtLenght: ','color: Green; display: block;font-weight: bold;', letterWidth);
    console.log('letterWidth*txtLenght:?? ', letterWidth*txtLenght);
    console.log('%cWE NEE TO MATCH ALL WORD IN THIS CHILD AND CHECK IF THE WORD NEED TO SPLIT','background: Coral; color: white; display: block;font-weight: bold;', childTxt._text);
    console.log('this.result: ', this.result, 'we are at R: ',r,' result[r]: ',this.result[r]);
    var currentLineResult = '';
    var afterLineResult = {txt:'',style:this.result[r].style,isTag:this.result[r].isTag};
    var inWordWidth = 0;
    var re = /\s\w+\s|\w+\s|\S+/g, Match; //regexr (match all word + any ,')
    //if(this._listTxtWidth.length>2){return} // break for freeze
    while ((Match = re.exec(childTxt._text)) !== null) {
        console.log('%cMatch found!: ','color: Green; display: block;font-weight: bold;', Match);
        inWordWidth=(Match[0].length+currentLineResult.length)*letterWidth;
        if((inWordWidth+inScopeWidth)>outLimit){
            afterLineResult.txt = Match.input.slice(Match.index);
            break;
        }else{
            currentLineResult+=Match[0];
        }
    }
    // redefine current child with currentLineResult (for same line)
    console.log(' END this.result[r]: ', this.result[r]);
    childTxt.text = currentLineResult;
    this.result[r].txt = currentLineResult;
    this.result.splice((r+1), 0, afterLineResult); // ADD AFTER this.result A NEW ARRAY TO CHECK
    //var thisword_width = (Match[0].length*letterWidth);
    return true;
};

MVPixi_Text.prototype.pixiTxtPositioning = function() { // END STEP
    console.log('this._childByIndex',this._childByIndex);
    //// NOW POSITIONING WIDTH & HEIGHT ON EATCH LINE ////
    console.log('%c ___________POSITIONING ALL CHILD____________:\nCalculation of all masterPixiTxt.children:=> ',
    'background: black; color: white; display: block;', this.masterMultiPixiTxt.children,' this._childByIndex:', this._childByIndex);
    var lineStyle = this.masterMultiPixiTxt.style._lineStyle; // setLineStyle 'top'||'middle'||'bottom'
    if(lineStyle==='middle'){lineStyle = 0.5;}else if(lineStyle==='bottom'){lineStyle = 1;}else{lineStyle = 0;}; //.anchor._y
    var align = this.masterMultiPixiTxt.style._align; // setLineStyle 'top'||'middle'||'bottom'
    var biggestWidthLine = Math.max.apply(null, this._maxLineWidth); // get the biggest width line for 'center'
    for(var L=Y=alX=0,maxL=this._childByIndex.length;L<maxL;L++){
        if(align==='center'){ alX=(biggestWidthLine-this._maxLineWidth[L])/2; }
        else if (align==='right'){alX=(biggestWidthLine-this._maxLineWidth[L]); };
        for(var C=X=0,maxC=this._childByIndex[L].length;C<maxC;C++){
            X += this._listTxtWidth[L][C];
            this._childByIndex[L][C].x = X+alX;
            this._childByIndex[L][C].y = Y;
            this._childByIndex[L][C].anchor._y = lineStyle;
        }
        Y += Math.max.apply(null, this._listTxtHeight[L]); // jump line
    }
    };
 
Last edited:

Jonforum

Veteran
Veteran
Joined
Mar 28, 2016
Messages
1,623
Reaction score
1,439
First Language
French
Primarily Uses
RMMV
Cons
  • Can't draw icons natively
is work now lol
And is very fast rendering , with true pixi sprite icon and not a bitmap canvas

ex: with a string , for add icon id 6 , i use {i6}
Code:
var txtString = 'Hello World !, This is a MultiStyles text with <s0>PIXI.JS</s0>, work with <s1>all property</s1>. <s0>in default object</s0> ...<s2>multieline wordWrap!</s2> Is very cool. And also work with true pixi icon render {i5} , and those {i6} {i7} , can be put anywhere';


i make a preCache builder with the spritSheet you when use for icon
PHP:
// PRELOAD ICON CACHE
    var that = this;
    var txtIcon_DirFileName = ['sheetTxtIcons','img/system/IconSet.png'];  //accesName,+ spriteSheet filename (full dir)
    var iconSize = [32,32]; // size icon in spritSheets
    this.txtIcon = []; // container of all preCache icons for pixiTextMultipleStyles
    // LOADING AND BUILD ICONS CACHE
    var loader = PIXI.loader.add(txtIcon_DirFileName[0],txtIcon_DirFileName[1])
    .load(setup); // callback=>(setup) when loader has cached the spriteSheets
    function setup() { // the callback setup
        var textureCache = PIXI.utils.BaseTextureCache.sheetTxtIcons; // accesCache by Name to spritsheets texture
        // make Data based on spriteSheet textureCache
        var _Width = textureCache.width, _Height = textureCache.height;
        var _lineLimit = _Width/iconSize[0]; // when reach, jump next line Y
        var _lenght = (_Width/iconSize[0])*(_Height/iconSize[1]);
        // prebuild all icon from spritesheet and add it to Gamefall.PixiText.txtIcon[]
        for (var i=0,x=0,y=0;i<_lenght;i++,x++){
            var rectangle = new Rectangle(iconSize[0]*x, iconSize[1]*y, iconSize[0], iconSize[1]);
            var texture = new PIXI.Texture(textureCache,rectangle);
            var icon = new PIXI.Sprite(texture);
            icon.interactive = true; // allow interactivity with mouse ?
            //icon.mouseover = function() { console.log("over"); } // not work ?
            //icon.on("mouseover", function() {console.log(555555555);}); // not work ?
            that.txtIcon.push(icon);
            if(!((i+1)%_lineLimit)){x=-1,y++};
        }
    }

but am only not understant 1 thing , i dont know if you can told me why.
if a turn true the

Code:
icon.interactive = true; // allow interactivity with mouse ?
am not able to make the sprite icon interactive ???
Code:
//icon.mouseover = function() { console.log("over"); } // not work ?
//icon.on("mouseover", function() {console.log(555555555);}); // not work ?
is it a pixi Bug in Rmmv ?
 

Jonforum

Veteran
Veteran
Joined
Mar 28, 2016
Messages
1,623
Reaction score
1,439
First Language
French
Primarily Uses
RMMV
OMG lol it was very long..
this is a great example, what you can do with pixi.text

Before, I had a loss of more than 40 fps !!.
Now about 200 Ms !!! No frames lost !
It only remains to do the backup system (save), but this is not important at this point.
But, I build the codes, to make this step easier
i make a random test and is very stable and isane performance.

 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Profile Posts

Do you Find Tilesetting or Looking for Tilesets/Plugins more fun? Personally I like making my tileset for my Game (Cretaceous Park TM) xD
How many parameters is 'too many'??
Yay, now back in action Happy Christmas time, coming back!






Back in action to develop the indie game that has been long overdue... Final Fallacy. A game that keeps on giving! The development never ends as the developer thinks to be the smart cookie by coming back and beginning by saying... "Oh bother, this indie game has been long overdue..." How could one resist such? No-one c
So I was playing with filters and this looked interesting...

Versus the normal look...

Kind of gives a very different feel. :LZSexcite:

Forum statistics

Threads
105,855
Messages
1,017,007
Members
137,563
Latest member
MinyakaAeon
Top