GMS 2 draw_sprite_ext with scaling and the mask?

FacesOfMu

Member
Hey all,

I've been working under the assumption that when you draw a sprite to the object's x and y and use scaling as in draw_sprite_ext that the bounding box would be calculated to the newly scaled sprite.

I tried making a button in my game and scaled it by 2 but found clicking on it didn't always work. I drew a rectangle using the object's bbox variables and saw that it outlines the unscaled sprite.

How do you go about making it always scale to whatever xscale and yscale you're giving it?
 

NightFrost

Member
If you scale during a draw it will not affect the bounding box as it is just that, a draw command. If you want to stretch the bounding box you must set the built-in image_xscale and image_yscale variables somewhere, usually in create if you need to scale only once.
 

FacesOfMu

Member
Thanks NightFrost. So if I have two instances using the same sprite but have different scales, each needs to reset the image_xscale when it draws?
 

NightFrost

Member
Yes, the scale setters are per-instance so each will carry their own. You'll need to tell draw_sprite_ext() what the current scaling is, most straightforward is to put those scaling variables into where it expects you to give the scaling.
 

TsukaYuriko

☄️
Forum Staff
Moderator
You would set their respective *scales at creation, for example using their instance creation code. Setting it multiple times whenever they draw would be pointless unless their scale can change over the course of their life span.
 

FacesOfMu

Member
So why do i need to give it the scale again in draw_sprite_ext? I would expect that after setting image_scale that draw_sprite_ext only need scale = 1? (or that I can just go back to draw_sprite() now)
For example, I'm now finding sprite_height and sprite_width reflects the image_scale multiplier.
 

TheouAegis

Member
Why even use draw_sprite_ext() at that point?

Using "1" would draw it unscaled and the bounding box would be too large. So you pass the scale variables instead.
 

FacesOfMu

Member
So image_xscale and image_yscale are really bbox_xscale and bbox_yscale only?

Except setting image_scale changes sprite_height and sprite_width. Aaaaargh!
 

FacesOfMu

Member
I think.....I might find it less confusing if sprite_index, sprite_width and _height were read-only specific to the sprite object, and a set of variables called image, image_width and _height were instance-specific. Then I'd understand that sprite_index, sprite_width, and sprite_height and any other sprite_whatever referred to the raw, unaltered sprite object shared across all instances. Image, Image_width, _height, _xscale, _yscale, would all be instance-only variables.

That way you could have the following and they'd all draw the same sized image:
Code:
scale = 2;
image_xscale = scale;
image_yscale = scale;
draw_sprite(image, sub_i, x,y); //(scaled up picture, scaled up bounding box)

draw_sprite_ext(sprite_index, sub_i, x, y, scale, scale, 0, c, 1); //(scaled up picture, unscaled bounding box)

draw_sprite_stretched(sprite_index, sub_i, x,y, image_width, image_height); //(scaled up picture, unscaled bounding box)
These two would draw the same, smaller image with different bounding boxes:
Code:
draw_sprite(sprite_index, sub_i, x,y); //(unscaled picture, unscaled bounding box)

draw_sprite_stretched(image, sub_i, x, y, sprite_width, sprite_height); //(scaled down picture, scaled up bounding box)
The differences would be that any uses of sprite_index uses the raw bounding box (draw_sprite_ext and draw_sprite_stretched in the example above), and any uses of "image" (in place of sprite_index such as in draw_sprite and the 2nd draw_sprite_stretched above) would use the image_scaled bounding box. Sprite_width and _height would be the raw sprite variables, and image_width and _height would be the instance specific image_scaled variables.

Unlike now where sprite_width and sprite_height are also instance specific, and there isn't just an image variable that I can use instead of sprite_index to get the scaled version.

Consistency++
 
Last edited:

TsukaYuriko

☄️
Forum Staff
Moderator
I think.....I might find it less confusing if sprite_index, sprite_width and _height were read-only specific to the sprite object
First of all: Sprite object? There are sprites, there are objects and there are instances, and neither of them are synonymous. Which of them did you refer to here? (According to the supplemental context info that follows in your post, I assume you meant sprite.)

sprite_width and sprite_height are read-only.
sprite_index can not be read-only as it is intended for the developer to be able to change an instance's default sprite at run time.

and a set of variables called image, image_width and _height were instance-specific. Then I'd understand that sprite_index, sprite_width, and sprite_height and any other sprite_whatever referred to the raw, unaltered sprite object shared across all instances. Image, Image_width, _height, _xscale, _yscale, would all be instance-only variables.
I believe what you are looking for already exists in the form of sprite_get_width and sprite_get_height. These get the width and height of a specified sprite and height at its original size and are mentioned in the manual entries of sprite_width and sprite_height for clarity.

I see what you mean, though - the naming of some of these might lead you to believe that they refer to sprites in general, not specifically the calling instance's assigned sprite. There is indeed no clear-cut distinction between those two in the current variable and function naming scheme.


Some things to note. You may already be familiar with some of these - if so, imagine I'm including them for the sake of completeness.
- sprite_index itself is not and does not store a sprite, it stored a number. Said number is the ID of a sprite.
- draw_sprite* functions instruct the engine to draw a sprite (based on its ID) to be drawn with specific parameters. This is purely visual and has no effect on the bounding box.
- image_*scale directly affect the bounding box and are a multiplier to the original size. They only affect drawing if there is either no Draw event (so the default Draw code will be used) or they are directly used in a Draw event's code.
- Once drawn to the screen, drawn sprites can no longer be interacted with and have no properties. Drawing a scaled version of a sprite does not create a copy of said sprite, and the scaled version is not tangible - it exists only as pixels on a surface.

Since anything that happens in the Draw event does not affect the bounding box and therefore wouldn't be visible otherwise, I like to put this piece of code at the end of an object's drawing code to see what my bounding boxes actually look like:
Code:
draw_set_color(c_red);
draw_rectangle(bbox_left, bbox_top, bbox_right, bbox_bottom, true);
 

NightFrost

Member
There is indeed no clear-cut distinction between those two in the current variable and function naming scheme.
And there likely won't ever be, as changing even one would break backwards compatibility, require legacy import routines to fix it, and require devs to forget well-established variable names for no good reason.

The collision box and drawing elements are detached from each other in manner explained above because you don't always want them to go hand in hand. You may want to scale them separately, change the bounding box, or remove one while still have the other. You might be doing multiple sprite draws but have a different kind of collision box. Or you might be running a master effect controller that draws numerous sprite animations and none should have a collision box. (And of course there's the limit of instance having only one collision box but being able to perform as many sprite draw operations as you please.)
 

FacesOfMu

Member
First of all: Sprite object? There are sprites, there are objects and there are instances, and neither of them are synonymous. Which of them did you refer to here? (According to the supplemental context info that follows in your post, I assume you meant sprite.)
Yes, I didn't use the right words and you read the context correctly.

Since anything that happens in the Draw event does not affect the bounding box and therefore wouldn't be visible otherwise, I like to put this piece of code at the end of an object's drawing code to see what my bounding boxes actually look like:
Code:
draw_set_color(c_red);
draw_rectangle(bbox_left, bbox_top, bbox_right, bbox_bottom, true);
Yes, this is how I found out I was having a problem between my sprites and masks.

The collision box and drawing elements are detached from each other in manner explained above because you don't always want them to go hand in hand. You may want to scale them separately, change the bounding box, or remove one while still have the other. You might be doing multiple sprite draws but have a different kind of collision box. Or you might be running a master effect controller that draws numerous sprite animations and none should have a collision box. (And of course there's the limit of instance having only one collision box but being able to perform as many sprite draw operations as you please.)
I think this is the subtlety I was beginning to understand through this conversation. I reckon it makes a good case that the concepts can be difficult for newcomers to learn as they are.

And there likely won't ever be, as changing even one would break backwards compatibility, require legacy import routines to fix it, and require devs to forget well-established variable names for no good reason.
And yea, I could see how the scope of my wish would break most projects. In lieu of this, I hope whoever is in charge of editing the docs can explain these distinctions everywhere they apply so us newbies can get our heads around them faster. Even what TsukaYuriko said "[image_*scale] only affect drawing if there is either no Draw event (so the default Draw code will be used) or they are directly used in a Draw event's code." seems very fundamental knowledge, but difficult to tease out from the docs and tutorials I've seen.

Thanks all for your help and instructions.
 
Top