Is it possible to stretch texture to the size of parent sprite?

Hi, guys!

I’m searching for the way to scale texture to the size of sprite containing it.

Let’s me describe my case.

I’m have some file “ShopIcon.png” with 80x80 size.

I’m load this file into the Sprite:

var shopIcon = new cc.Sprite(“resources/ShopIcon.png”);

Next, I check content size of my sprite:

var iconSize = shopIcon.getContentSize();

All fine, it returns:

Point[80,80]

Next, I want to resize my sprite to size of parent panel which have size 100x100.

So, I just do it:

shopIcon.width = 100;
shopIcon.height = 100;

Well, sprite container has been resized properly. Now, it has size 100x100:

var newIconSize = shopIcon.getContentSize();

returns:

Point[100,100]

However, my texture is not stretch to the size of parent sprite.
It’s still located at the point x = 0, y = 0 of sprite container and it has size 80x80.

So, I have some solutions to such issue for now:

  1. The most stupid way: just store the same texture in different sizes. So, I will have “ShopIcon_Panel80x80.png”, “ShopIcon_Window120x120.png”, etc.
    I think you can see the problems with such approach.

  2. Scale image manually on each resize call:

function resizeSprite(sprite, width, height) {
sprite.width = width;
sprite.height = height;
sprite.setScale(width / sprite.getTextureRect().width, height / sprite.getTextureRect().height);
}

I think it can be good in most cases but now it’s difficult to scale sprites without breaking texture stretching.

In addittion, it’s difficult to understand, what does it mean “set the scale of sprite to 1”. Does this mean: we should scale a sprite to size of it’s texture, or we should scale a sprite to it’s original size?

  1. Using Scale9Sprite instead of Sprite:

We just change:

var shopIcon = new cc.Sprite(“resources/ShopIcon.png”);

to:

var shopIcon = new cc.Scale9Sprite(“resources/ShopIcon.png”);

… and all next code works as expected.

For now, I think it’s the best approach, but there are some potential problems with it:

a) now we have dependency from cocos extensions library; so the resulting JS code will be have larger size; it may be unacceptably for little games with high requirements to loading time;

b) 9-scale mechanism looks ugly for some little values:

https://pasteboard.co/images/HyeF8cy.png/download

It’s a default Cocos image logo stretched to 30x30 size.

I believe such problem may be resolved with properly capInsets params, isn’t it?

so…

c) we should provide 9-pitch scale settings for each image to preserves it aspect ratio while scaling

What I actually wanted when I just encountered with such problem:

I’m just add texture to my Sprite and it’s automagically stretches to Sprite size on each resizing operation.
Maybe, there are some options to control stretch strategy for texture (something like fill options (fillType/fillCenter/fillStart/…) that are presents in Sprite class of Cocos Creator Engine).

So, does anyone know how to achieve described behavior with Sprite class?
Any suggestions will be helpful.

you can call your resizeSprite function in an overriden setContentSize function.
Why do you need to change the dimensions of your parent sprite?
Do you change its spriteframe?
Cant see any problem with using the scale attribute.

Why do you need to change the dimensions of your parent sprite?

The main case here - use the same image in different places.
My image has 80x80 size.
I can place it inside of sprite representing menu item (sprite with size 32x32), or inside of sprite representing section icon (sprite with size 128x128), or… I think you get the idea.

Do you change its spriteframe?

No, spriteframe is creating once, and has content rect = {0,0,80,80}.
I’m change the size of sprite, not the size of texture / textureframe. When I do it, I’m expecting texture inside of this sprite will be resized also.

Cant see any problem with using the scale attribute.

I’m agree with you. I’m just surprised that behavior like a stretching of image to the size of sprite container is not working by default, like it has been implemented in Cocos Creator, or Unity.

I see one problem with scaling - when we do it, the bounding rect of node is changed also, isn’t it? So, when I use scaling I can’t trust anymore that the bounding rect will be the same as I specified when creating the sprite. This can make collision detection / mouse pointer detection over the sprite difficult. Commonly, it’s expected that the bounding rect will not exceed the borders of initial sprite.

Just a case:
We have a sprite of button with size 100x100 and an image of button with size 50x50.
We init our sprite with image.
We set our sprite size to 100x100.
Image is located inside of sprite, with the rect = [0,0,50,50]
Now, we have border around of image in 50 units from top and right sides.
Next, we can set scale factor to 2.
Image rect now is [0,0,100,100].
Sprite rect now is [0,0,200,200].
Now, tell me please which area will be included in the bounding box? I believe it will be the area including borders around an image (it is now will have size in 50units * 2.0scale = 100 units per side).
So, bounding box in such case is [0,0,200,200] instead of expected [0,0,100,100].
If an image will be just stretched inside of sprite without using scale, there will no such empty area. All space will be always filled with image.

Well, I’m finished my investigation of this issue, there are my results (maybe, it will be helpful for somebody):

  1. cc.Sprite is just an image holder. It does not have any logic / interface to handle scale of inner image. You can use it when your image size matching to size of sprite.

  2. Do re-scale on each resize is really not a good idea. Because when re-scale the bounding box is changed also, it will lead to multiple problems when we should working with sprite as mouse-triggered object.
    You can use this practice when your image just a decoration that should not react with mouse / another objects.

  3. cc.Scale9Sprite is a good way to handle scaled images. It has useful property setRenderingType that can be used to switch between “9-pitch scale” (SLICE) — “normal image” (SIMPLE). When we switch cc.Scale9Sprite to SIMPLE mode, there is no problems with stretching to small image size, and we shouldn’t provide capInsets to any sprite using this class - capInsets just ignoring in SIMPLE mode.
    You can use it when you need universal way to handle 9-pitch scaled / scaled / non-scaled images.

  4. I also paid attention to Widget classes family from the ccui namespace. ccui.ImageView use cc.Scale9Sprite class in their implementation to scale inner image. I believe using Widgets is a better way to build UI in Cocos2d-Js.
    You can use ccui.ImageView when you building UI and you need scalable image.