Creating a sprite in the game

Hello. In my games, I use loading links to images and create content based on them. I usually use models and materials and it looks like this:

          const image = new Image()
        image.crossOrigin = 'anonymous'
        const prom = new Promise(res => {
            image.onload = () => {
                const texture = new pc.Texture(this.app.graphicsDevice, {
                    magFilter: pc.FILTER_LINEAR,
                    minFilter: pc.FILTER_LINEAR

                })
                texture.setSource(image)
                const material = new pc.StandardMaterial()
                material.diffuseMap = texture
                material.opacityMap = texture
                material.blendType = 'alpha'
                material.alphacoverage = true
                material.update()
                material.img = image;
                this.materialItemsArr.push(material)
                return res(material)
            }
            image.onload()
        })
        image.src = el.default_look_preview_200

I create a link-based material. But now I have a game on sprites and I can’t find in the documentation an algorithm for creating a sprite using a link to a third-party resource. Please write an example of creating a sprite from a link.

Hi @sergey_ch,

Check the following engine example on how it loads a texture, creates a texture atlas and at the end sprite assets from it:

https://playcanvas.github.io/#user-interface/button-sprite.html

1 Like

Thanks. But it is not quite clear how to specify the frame correctly.

  "0": {
                    rect: new pc.Vec4(0, 147, 190, 49),
                    pivot: new pc.Vec2(0.5, 0.5),
                    border: new pc.Vec4(7, 11, 7, 7)
                },

This is the code from the example, getting an image from the network where these parameters come from.
Is there a way to use the entire texture as a frame?

Check the pc.TextureAtlas docs on what those numbers are for each frame:

https://developer.playcanvas.com/en/api/pc.TextureAtlas.html

Yes, definitely you can have a texture atlas with a single frame.

1 Like

Please look at the code, it does not work yet, the site is not visible, but the logic seems correct.

GameManager.prototype.createLogo = function(data){
    const url = data.logo_200
    
    const cloudLogo = this.cloud.findByName('logo')
    
    const image = new Image()
    image.crossOrigin = 'anonymous'
     const prom = new Promise(res => {
            image.onload = () => {
                const atlas = new pc.TextureAtlas()
                 atlas.frames = {
                    "0": {
                        rect: new pc.Vec4(0, 0, 200, 200),
                        pivot: new pc.Vec2(0.5, 0.5),
                        border: new pc.Vec4(20, 20, 20, 20)
                    },
                
                 }
                const texture = new pc.Texture(this.app.graphicsDevice, {
                    magFilter: pc.FILTER_LINEAR,
                    minFilter: pc.FILTER_LINEAR

                })
                texture.setSource(image)  
                atlas.texture = texture   
                
                const sprite = new pc.Sprite(this.app.graphicsDevice, {
                    atlas,
                    frameKeys: 0,
                    pixelsPerUnit: 1,
                    renderMode: pc.SPRITE_RENDERMODE_SIMPLE

                })
                return res(sprite)
            }
            image.onload()
            image.src = data.logo_200
        })
     
         prom
         .then(sprite=>{
            cloudLogo.c.sprite.sprite = sprite
            console.log(cloudLogo)
         })
     
}

Hi @sergey_ch, sorry I can’t see what’s wrong out of context.

If you are not getting any errors, try stepping through the code using the debugger and see if everything is correctly initialized.

One difference that I see between your code and the engine example is that you aren’t creating and adding pc.Asset instances for each object you are initializing. That isn’t required in all cases but there may be something here that requires an asset to be registered in the registry.

If I were you I would grab that engine example and work on that first trying to load the custom sprite based on that example.

I’ve taken your code and made a few fixes, example: https://playcanvas.com/editor/scene/1167975

I think the biggest issue is that the frameKeys attribute is a string, not a number: https://github.com/playcanvas/playcanvas.github.io/blob/master/examples/user-interface/button-sprite.html#L166

var CreateSpriteAtRuntime = pc.createScript('createSpriteAtRuntime');

// initialize code called once per entity
CreateSpriteAtRuntime.prototype.initialize = function() {
    const url = "https://raw.githubusercontent.com/yaustar/yaustar.github.io/master/textures/512x512.jpeg";
    
    const cloudLogo = this.entity.findByName('Cloud Logo');

    const image = new Image();
    image.crossOrigin = 'anonymous';
    const prom = new Promise(res => {
        image.onload = () => {
            const atlas = new pc.TextureAtlas();
            atlas.frames = {
                "0": {
                    rect: new pc.Vec4(0, 0, 512, 512),
                    pivot: new pc.Vec2(0.5, 0.5),
                    border: new pc.Vec4(0, 0, 0, 0)
                },

            };
            const texture = new pc.Texture(this.app.graphicsDevice, {
                magFilter: pc.FILTER_LINEAR,
                minFilter: pc.FILTER_LINEAR

            });
            
            
            texture.setSource(image);
            atlas.texture = texture;

            const sprite = new pc.Sprite(this.app.graphicsDevice, {
                atlas,
                frameKeys: '0',
                pixelsPerUnit: 100,
                renderMode: pc.SPRITE_RENDERMODE_SIMPLE

            });
            return res(sprite);
        };
        image.src = url;
    });

    prom
        .then(sprite=>{
        cloudLogo.sprite.sprite = sprite;
        console.log(cloudLogo);
    });

};

// update code called every frame
CreateSpriteAtRuntime.prototype.update = function(dt) {

};

// swap method called for script hot-reloading
// inherit your script state here
// CreateSpriteAtRuntime.prototype.swap = function(old) { };

// to learn more about script anatomy, please read:
// https://developer.playcanvas.com/en/user-manual/scripting/
2 Likes

It works! Thank you very much!

1 Like