• Content Count

  • Joined

  • Last visited

Posts posted by lucbloom

  1. My solution to this was to simply extend Phaser.BitmapText with an anchor point.


    3 lines of code, problem solved.

    I tried to merge this with the official build, but Rich does not want to mix the sprite "anchor" concept, because BitmapText is a group of multiple sprites and that may cause some misunderstanding, and he's probably right. So I use it just for myself, and I'm happy with it :)


    Regardless of implementation concept, all objects that have a clear width & height should have an anchor point, *especially* when the TTF counterpart *does* have one.


    If you use it, and I use it, and I've seen other people use it, it's probably u useful feature.

    I don't see what there is to confuse? You'd use a property on an object the same way and get the same results for 2 kinds of objects. For me, this is the opposite of confusing. It would be confusing if I'd have to set one property on a TTF object and do something else on a BM font label object to get the same thing.


    PS: Would you mind positing your solution?

  2. In all seriousness, regardless of what internal structure an object has, I want to set its anchor point. Imagine a list of numbers, for instance a high score list. I want the back of the numbers to align.


    Now if these labels are TTF text or bitmap font texts are not important to me. I want to be able to align them the same way.


    In my vision, "align" doesn't address this issue because that specifies how the text should be aligned _within_ the label and therefore only has effect on labels with *multiple lines*.


    As one game engine developer (c++) to another (JS), I highly recommend adding the "anchor" property on every type of visual world object with a width & height.


    PS: how can I change the 'Newbie' status above my profile picture without having to make too much posts? :-)

  3. Better solution:


    Paste this somewhere in your 'extensions.js' (after loading phaser-min.js) and it'll work.


    Object.defineProperty(Phaser.BitmapText.prototype, 'anchor', {    get: function() {        return this._anchor;    },    set: function(anchor) {        this._anchor = anchor;        this.dirty = true;        this.updateTransform();    }});PIXI.BitmapText.prototype.updateText = function(){    var data = PIXI.BitmapText.fonts[this.fontName];    if (!data)    {        console.error("Bitmap font not found: '" + this.fontName + "'");        return;    }         var pos = new PIXI.Point();    var prevCharCode = null;    var chars = [];    var maxLineWidth = 0;    var lineWidths = [];    var line = 0;    var scale = this.fontSize / data.size;        for(var i = 0; i < this.text.length; i++)    {        var charCode = this.text.charCodeAt(i);        if(/(?:\r\n|\r|\n)/.test(this.text.charAt(i)))        {            lineWidths.push(pos.x);            maxLineWidth = Math.max(maxLineWidth, pos.x);            line++;            pos.x = 0;            pos.y += data.lineHeight;            prevCharCode = null;            continue;        }        var charData = data.chars[charCode];        if(!charData) continue;        if(prevCharCode && charData[prevCharCode])        {            pos.x += charData.kerning[prevCharCode];        }        chars.push({texture:charData.texture, line: line, charCode: charCode, position: new PIXI.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)});        pos.x += charData.xAdvance;        prevCharCode = charCode;    }    lineWidths.push(pos.x);    maxLineWidth = Math.max(maxLineWidth, pos.x);    var lineAlignOffsets = [];    for(i = 0; i <= line; i++)    {        var alignOffset = 0;        if( === 'right')        {            alignOffset = maxLineWidth - lineWidths[i];        }        else if( === 'center')        {            alignOffset = (maxLineWidth - lineWidths[i]) / 2;        }        lineAlignOffsets.push(alignOffset);    }    var lenChildren = this._pool.length;    var lenChars = chars.length;    var tint = this.tint || 0xFFFFFF;    for(i = 0; i < lenChars; i++)    {        var c = this._pool[i];        if (c) c.setTexture(chars[i].texture); // check if got one before.        else        {            c = new PIXI.Sprite(chars[i].texture); // if no create new one.            this._pool.push(c);        }        c.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale;        c.position.y = chars[i].position.y * scale;        c.scale.x = c.scale.y = scale;        c.tint = tint;        if (!c.parent) this.addChild(c);    }    // remove unnecessary children.    // and put their into the pool.    for (var i = lenChars; i < this._pool.length; ++i)    {        this.removeChild(this._pool[i]);    }    /**     * [read-only] The width of the overall text, different from fontSize,     * which is defined in the style object     *     * @property textWidth     * @type Number     */    this.textWidth = maxLineWidth * scale;    /**     * [read-only] The height of the overall text, different from fontSize,     * which is defined in the style object     *     * @property textHeight     * @type Number     */    this.textHeight = (pos.y + data.lineHeight) * scale;    if (this._anchor)    {        for(i = 0; i < lenChars; i++)        {            var c = this._pool[i];            c.position.x -= this.textWidth * this._anchor.x;            c.position.y -= this.textHeight * this._anchor.y;        }    }};

  4. Here is the solution:


    Object.defineProperty(Phaser.BitmapText.prototype, 'anchor', {    get: function() {        return this._anchor;    },    set: function(anchor) {        this._anchor = anchor;        this.dirty = true;        this.updateTransform();                if (!this.textBitmapSpritesParent)        {            this.textBitmapSpritesParent = new Phaser.Group(;            this.addChild(this.textBitmapSpritesParent);        }        this.textBitmapSpritesParent.x = -this.textWidth * this.anchor.x;        this.textBitmapSpritesParent.y = -this.textHeight * this.anchor.y;                for (var i = 0; i < this.children.length;)        {            if (this.children[i] == this.textBitmapSpritesParent)            {                ++i;            }            else            {                this.textBitmapSpritesParent.add(this.children[i]);            }        }     }});


    PS: rich, this would work better (more reliable) if BitmapText would use an internal dedicated array for its Glyph sprites.

  5. You don't have to use Phaser's built-in tweening engine if you don't want to. Phaser has no complex update requirements, you simply change properties over time in most cases and things happen as expected. GSAP is an alternative that has a lot of very cool features including advanced tween timeline management.


    That framework is really cool. I guess I had to get used to how loose JavaScript actually is, combining frameworks like that.

    Now my code is:

        if (!halo.timeline)    {        halo.timeline = new TimelineLite();        halo.timeline            .to(halo.scale, 0, {x:0, y:0})            .to(halo, 0, {alpha:1})            .to(halo.scale, duration/1000, {x:scale, y:scale, ease:Bounce.easeOut})            .to(halo, duration*2/1000, {alpha:0});    }    halo.timeline.restart();

    Finishing, reverting and cancelling is also in there, so yeah, exactly what I wanted.

    TimelineLite.prototype.finish = function(){    this.progress(1, false);}

  6. I have a question about the tweening system in Phaser. If I perform a complex animation with multiple sprites (or a simple animation involving only 1 sprite but with scale and alpha) I have to write something like this:
        this.halo.scale = {x:0, y:0};    this.halo.alpha = 1;    if (this.halo.scaleTween)    {        this.halo.scaleTween.stop();    }    if (this.halo.alphaTween)    {        this.halo.alphaTween.stop();        this.halo.alphaTween = null;    }    this.halo.scaleTween = game.add.tween(this.halo.scale)    this.halo.scaleTween        .to({x:1, y:1}, 1000, Phaser.Easing.Bounce.Out)        .start()        .onComplete.addOnce(function() {            this.halo.alphaTween = game.add.tween(this.halo).to({alpha:0}, 1000).start();        }, this);
    When I'd rather write something like this:
    game.stop.tween("halo bounce"); // No error if not foundgame.add.tween("halo bounce")    .then(this.halo.scale, {x:1, y:1}, 1000, Phaser.Easing.Bounce.Out)    .then(this.halo, {alpha:0}, 1000)    .start();

    Is this sort of system possible at all? Am I using the existing Phaser API wrong?

    Additionally, in our C++ engine, we had an 'also' function as well. This would allow you to add new tweens in the dot chain, but they got added at the same point as the previous one:
    game.add.tween("game over")                                         // The name is optional. Anonymous tweens are the default    .then(1000)                                                     // Delay before starting    .then(, {alpha:1}, 100)    .also(, {x:1, y:1}, 100)                         // This one runs ALONGSIDE the 'alpha' tween    .then(function() { this.openScoreScreen(this.stats); }, this);  // This one runs at the END of the 'scale' tween

    If this system looks exciting (I think it is, we've shipped a lot of triple-A casual games on all platforms (except HTML5) with it...) I would be happy to work together to add it to Phaser.



    Luc Bloom



  7. I have fixed a bug. This is how to repro it:


    At startup:

    this.sprite.loadTexture("walk.png"); // Sprite sheet 3x4 frames


    Some time later:

    this.sprite.loadTexture("dead.png"); // Single frame


    My game sets this.sprite.frame each update. If the object is 'dead', the frame number is 0.


    The BUG is: the old frameData in this.sprite.animations resets the texure to walk.png's first frame.

    I SOLVED this by executing


    in the "cache.isSpritesheet == false" part of Phaser.Sprite.prototype.loadTexture