• Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

Discussion Shouldn't Sprite Pivot be Real?

M

MarceloP

Guest
Hey guys, it's me again.

Well, I've noticed a pretty weird problem and I think it is related to my previous unanswered ticket/problem, which has the number: 143039, and was submitted in April.
The fact is that after doing some tests I came across a bug related to scaling. When I scale an odd sized sprite, I get error propagation with respect to the center of my sprite.

Let me explain it better thought a pic.

upload_2018-7-10_11-59-31.png

As you can see, my odd sized sprite is 55x55. When scaled to 200, it finds that the scale factor should be 3.6363637447. No problem until that, because, it is correct and the precision calculation will fix any problems.

But when it comes to my XOffset, which HAD TO BE REAL, we have a problem. Since I set my sprite origin to be in the center, it SHOULD be 27.5, not only 27. Therefore, after scaling, the 0.5 that was left off my center propagates by the scale factor, leaving me with an invalid xoffset of 98.18, instead of 100.

This simply won't happen to an even sized sprite, since the center will actually round correctly after the scale factor is applied.

From my point of view, what should happen is that the pivot should be allowed to be a REAL value in the IDE/game and, therefore simply round the x and y position before draw, the same way it already does with X and Y positions.

Not allowing the pivot (xoffset and yoffset) to be real values, leads to error propagation and may be the same issue with my other post/bug.

Any ideas? Should I simply report this, or this is a forced integer for a reason?
I'll wait for some answers before actually submitting this as a bug/ticket.

Thanks!
 

gnysek

Member
Did you just made XOffset = sprite_get_xoffset(sprite_name) * sprite_xscale; ?? Then the value in XOffset is your calculation, while for GM it's still 27 (or 28 in second example). GM itself doesn't know you're multiplying xoffset here, it just multiplies it as any other number. Also, as rounding to second decimal place happens here, it looks like rounding happens, but it's not true. It's usally so close (like 99.9999991) that it's displayed as whole number.

sprite_get_xoffset(sprite_name) for sure returns whole number (not real, as real can be fraction too), as image_xscale can be applied per object image only, not per sprite. So you're mixing two things.


Edit: also worth note, it's not possible do draw halfpixel on any computer, so origin position will still be rounded in case of scaling image.
 
M

MarceloP

Guest
Hello @gnysek,

Actually XOffset receives my sprite_xoffset, I'm not changing this value, or altering it. Gamemaker changes it as I scale the object. And yes, I know about image_xscale, but that's the whole point I'm trying to show as a problem.

I created a sprite and set the pivot to be "Middle Centre". Since my sprite size is an odd value, I lose part of the desired center, since the pivot can only be a whole number (as mentioned by you). Therefore, when scaling (since my middle doesn't actually has the 0,5 that it should) I get an error propagation on my sprite_xoffset (pivot X position of my sprite). Instead of being on the center (100) after scaling, I get it on 98.18 (this is gamemaker calculating my sprite_xoffset constant/read only). Which it is correct in terms of multiplying the scale (3.6363637447) by the initial pivot X (27), but this means that the IDE (or engine, dunno) by only allowing whole numbers as pivots is propagating errors when operating with real numbers and odd sized sprites.

If it let me simply put 27.5 as being the center (the IDE/engine) the engine would calculate the scale (3.6363637447) multiplied by the sprite_xoffset (27.5) getting me my real center (99.99999999). As you mentioned, that will be rounded by 100 when drawing.
And yeah, as you put as a note, it will always round when drawing, so there's no point in not letting us use real numbers in the pivot, since the rounding will happen anyway latter on during the draw.

The problem is just not letting us put a real value as the pivot and, during game run, any scale or rotation on odd sized sprites resulting in unwanted results after an error propagation, caused by the decimals that we had to ignore.
We still have sprite_set_xoffset, but I don't think it allows you to set this values to real (float) numbers. Changing this by hand may also change the whole asset offsets, which is not what is wanted. I want a correctly calculated sprite_xoffset after scaling my object.

Since I only posted an image of the problem happening, and draw some text to help, I'm posting the code so that you can also check it out.

Create:
Code:
//type = ""; //This is a variable in my object, which is easier to control (text: Even or Odd)

if(scaled){ //scale is also a variable (boolean)
    image_xscale = finalSize/sprite_width; //finalSize is also a variable. 200 and 400 in my examples
}

Draw Event:
Code:
/// @description Draw
var msg = "";

draw_set_halign(fa_center);
draw_set_valign(fa_middle);
if(!scaled){
    msg = "Normal " + type + " Sprite:";
} else {
    msg = "Sprite Scaling Width";
}

draw_text(x, y-70, msg + "\n Width: " + string(sprite_width) + "px\n XScale: " + string_format(image_xscale, -1, 10) + "\n XOffset: " + string(sprite_xoffset));
draw_self();
upload_2018-7-11_8-41-29.png
 
Last edited by a moderator:

gnysek

Member
You're wrong. In all 3 top cases, xorigin of your sprite is 27, in all bottom sprite xorigins of sprite is 28. GM never changes it, as it's defined in sprite editor.

If you're using draw_sprite_ext() or image_xscale, then sprite is scaled according to that origin. So if you write, that scale is 3.57, then GM draws 27*3.57 pixels on left and 28*3.58 pixels on right of origin. As graphic card can't display half pixel, it either round those values, or if interpolation is enabled, it may ceil sprite width and draw last pixel at 50% alpha.

So, your pivot point of stretched sprite is probably at
Code:
round( sprite_get_xoffset() * image_xscale)
There's no error in either engine, or GM functions, only issue is with your logic, that GM returns it wrong, while it's you who wrongly computes it :)
 
M

MarceloP

Guest
But I don't have any logic. I'm simply scaling it to a size, and expected it to still be in the center. I know that what is defined in the editor won't change, unless using some function as sprite_set_xoffset(). I also know about their being 27 and 28, and that's the whole point of this discussion. I'm using only draw_self(), nothing else should be needed and that's also a point in this discussion.

Setting the pivot to a real number wouldn't break the engine, neither corrupt any positioning. But would make image_xscale change correctly the value of sprite_xoffset in the end, even if it was an odd number.
Again, the calculations are right, but from my point of view the way it is done seems wrong. Not only in this case, but many cases, if you simply set your sprite to centre middle, you want to keep this correct even after changing the scale and, having only a integer as pivot, "creates error propagation" during operations like scaling (check below why I used quotes).

There's also ~no~ X and Y that are real, that doesn't stop the engine from allowing X and Y to be a real number, since they know that it would lead to a propagation of errors when coding. My suggestion is to put it as a real, and solve this errors and misunderstandings. I could also save a X and Y internally, apart from the object's and do my real calculations and round/ceil or whatever before drawing, but the choice was to make it simple and straight for the programmers.

The same goes here. There's no need to keep it as an integer breaking the logic of a centre middle that will not be the centre/middle after changing the scale or rotating (which is happening, as already exemplified). I can calculate all of that correctly if I want, I can calculate any property by myself if I want, internally and have triplicated work. I'm simply trying to show that I shouldn't need to, and it can be seen in this example that a simple change would change this. It's not so intuitive, but letting you "simply put a real value in the IDE" when setting the pivot of a sprite would probably solve this propagation and keep it straight, when talking about keeping the pivot correct after operations like scale.

Yes, the center is 27 and 27*3.6363637447 is 98.18 (round( sprite_get_xoffset() * image_xscale)) is not wrong and the engine is calculating this correctly, I'm not denying it. I'm saying that this being a real, wouldn't require further calculations and hard code fixes for people to achieve a real center (literally) that will keep being the center pivot after operations like scaling. Again, ~I only used gamemaker's constants, nothing else~. The calculations are right, but due to the impossibility of keeping it as a real number in the pivot you get a counter-intuitive value after operations like scaling, since you set "centre middle" and it was expect to be maintained after scaling. This kind of operation is not actually generating/leading to imprecision on those constants, but the intuitive thing was to keep the pivot on the center or whatever position it was at and, since it is not real, that doesn't happen at all.

If it helps, forget all the times I said it leads to imprecision calculations and change that to counter-intuitive resolution of the pivot after setting it initially to "centre middle".

------ Edit ------

So if you write, that scale is 3.57, then GM draws 27*3.57 pixels on left and 28*3.58 pixels on right of origin.
This isn't what actually happens. Allowing us to set it to 27.5 would do:
27.5 * 3.6363637447 = 100.0000297925

Allowing us to set as a real would give us another real that, suited as integer, is 100. Then after scaling you'd actually have 100 pixels in one side and another 100 pixels in the other side. This is what I'm calling "expected and intuitive", since we set your pivot to be the "centre middle".

By this logic, and the current integer pivot logic of the IDE (I can't set the real middle of the sprite), it is assumed that pivots should be always a pixel, when they shouldn't. It's an abstract concept of axis, and should be able to be in the middle of a pixel, since we can scale the sprite by real factors.
 
Last edited by a moderator:

gnysek

Member
It's still in center. The number above is calculated by you. Sprite is stretched according to it's pivot/origin point. Your calculations are just your calculations and have nothing to do with real position of pivot point. It's exactly on x,y which you provide in draw function :)

Also, if you use round() function, all you calculations should be good. Or use draw_sprite_stretched.
 
Top