Animated sprites in UI

Hello!

So I have a use-case where I need to combine text as well as animated sprites in a single object. Now, Text is only available as a UI-Element, while animated sprites are not available as UI-Element. This seems like an oversight? Or am I missing something?

I noticed that ElementComponent has a spriteFrame property and made a quick script to update it based on an fps attribute:

var UiSpriteAnim = pc.createScript('uiSpriteAnim');

UiSpriteAnim.attributes.add('fps', {type: 'number', default: 15});
UiSpriteAnim.attributes.add('delay', {type: 'number', default: 0});
UiSpriteAnim.attributes.add('loop', {type: 'boolean', default: true});

UiSpriteAnim.prototype.initialize = function() {
    this._frameCount = this.entity.element.sprite.frameKeys.length;
    this._interval = 1.0/this.fps;
    this.restart();
};

UiSpriteAnim.prototype.update = function(dt) {
    if (this._isComplete) 
        return;
    
    this._timer += dt;
    if (this._timer > this._interval) {
        var nextFrame = this.entity.element.spriteFrame + 1;
        if (nextFrame >= this._frameCount)
        {
            if (this.loop === true)
                nextFrame = 0;
            else
                this._isComplete = true;
        }
        
        this.entity.element.spriteFrame = nextFrame;
        this._timer -= this._interval;
    }
};

UiSpriteAnim.prototype.restart = function() {
    this.entity.element.spriteFrame = 0;
    this._timer = -this.delay;
    this._isComplete = false;
};

This seemed preferable to attempting to keep sprite world transform in sync with UIElement screen transform.Or making/integrating a spritefont script/lib. It seems to work fine though, which makes me curious why it isn’t an option to begin with.

Added a feature request for this: https://github.com/playcanvas/engine/issues/new

I just don’t think it has been done yet. :sweat_smile:

2 Likes

Small addendum:

Just setting the spriteFrame on the element doesn’t update it’s size or pivot. So need to add this:

			this.entity.element.spriteFrame = nextFrame;
			const frameKey = this.entity.element.sprite.frameKeys[nextFrame];
			const frame = this.entity.element.sprite.atlas.frames[frameKey];
			this.entity.element.width = frame.rect.z;
			this.entity.element.height = frame.rect.w;
			this.entity.element.pivot = frame.pivot;

And everything should be dandy :slight_smile:

1 Like