Author [EN] [PL] [ES] [PT] [IT] [DE] [FR] [NL] [TR] [SR] [AR] [RU] [ID] Topic: Attention GameMaker users: Update on image_xscale bug  (Read 3322 times)

0 Members and 1 Guest are viewing this topic.

Offline TheouAegis

  • Amateur Auteur of GMvania
  • Master Hunter
  • *****
  • Posts: 1860
  • Gender: Male
  • Awards The Retro Gamer: Has a heated passion for the oldschool VG Titles. The Great Defender will always defend the object of his or her fandom. Hack Master makes creations out of CV parts. (S)he makes Dr. Frankenstein proud.
    • GMvania Developer's Blog
    • Awards
  • Likes:
Attention GameMaker users: Update on image_xscale bug
« on: October 25, 2011, 05:56:19 PM »
0
As some of you may know, and as all of you [who use GameMaker] should know, image_xscale is bugged. I think the bug existed in the NES as well, but that's not important. What is important is that it is bugged. When image_xscale is negated, a method frequently used to mirror sprites, the sprite's bounding box gets changed. Actually, a lot of things get changed, but this important update simply concerns the bounding box. Using image_xscale=-1 (or image_xscale*=-1) increases the bounding box by 2px. I'd stated this before and it's been proven by others on the GMC forums. However, what hasn't been stated yet is that negating image_xscale also shifts the bounding box! It's a scary aspect you shouldn't neglect, but it is manageable:

Think of the bounding box in terms of two values - left_differential and right _differential. Simply put, left_differential is the value returned by sprite_get_bbox_left() and right_differential is the value returned by sprite_get_width()-sprite_get_bbox_right(). (Keep in mind that sprite_get_bbox_right() is not technically the same as bbox_right; the latter returns the x-value of bbox_right in the room, not how it relates to the rest of the sprite.) As long as left_differential and right_differential are equal, the bounding box increases by 2px evenly, subtracting 1 from bbox_left and adding 1 to bbox_right. However, this isn't the case when left_differential and right_differential are different.

One of two things can happen, depending on the values. If left_differential is 1 higher than right_differential, the bbox_left changes by 2 and bbox_right stays the same, and naturally vice-versa when right_differential is higher than left_differential. This is what happens when a sprite has a odd-valued sprite_width and full-image bounding box. However, if left_differential is 2 higher than right_differential, for example, the bounding box will actually shift to the left 1 pixel in addition to changing bbox_left by 2. If you thought that was bad enough, the shift increases depending on the difference between left_ and right_differential. If left_differential is 10 and right_differential is 2, the bounding box will shift 7 pixels and balloon out on the left side.

In summary:
Code: [Select]
left_differential += sprite_width mod 2
if left_differential != right_differential
{
    if left_differential > right_differential
        bbox_left -=2
    else
        bbox_right += 2
}
else
{
    bbox_left -= 1
    bbox_right += 1
}
bbox_left += (right_differential-left_differential)&!1
bbox_right += (right_differential-left_differential)&!1

where &! is something I made up meaning reduce the numerical value by 1
(e.g., -2 becomes -1, 3 becomes 2)
« Last Edit: October 25, 2011, 07:07:11 PM by TheouAegis »
Your mom has had more floppies put in her than a Commodore 64!


Follow my lack of progress on my game at my blog:
http://gmvania.blogspot.com

Offline TheouAegis

  • Amateur Auteur of GMvania
  • Master Hunter
  • *****
  • Posts: 1860
  • Gender: Male
  • Awards The Retro Gamer: Has a heated passion for the oldschool VG Titles. The Great Defender will always defend the object of his or her fandom. Hack Master makes creations out of CV parts. (S)he makes Dr. Frankenstein proud.
    • GMvania Developer's Blog
    • Awards
  • Likes:
Script to fix image_xscale bug
« Reply #1 on: October 27, 2011, 10:23:23 AM »
0
I haven't tested this yet, but in theory this script should work to counter the image_xscale bug. Yes I'm replying to myself because this is in response to the bug.  :P

You call the script with:

sprite_get_bbox(bbox_left)
or
sprite_get_bbox(bbox_right)

Of course, name the script "sprite_get_bbox".

Code: [Select]
if image_xscale>0 return argument
else
{
    diff_L = sprite_get_bbox_left(sprite_index);
    diff_R = sprite_get_width(sprite_index)-sprite_get_bbox_right(sprite_index);
    true_L = bbox_left;
    true_R = bbox_right;
    if diff_R - diff_L - 1
    {
        true_L -= diff_R-diff_L-1;
        true_R -= diff_R-diff_L-1;
    }
    if diff_L - diff_R - 1
    {
        truel_L += diff_L-diff_R-1;
        true_R += diff_L-diff_R-1;
    }
    if diff_L = diff_R
    {
        true_L += 1;
        true_R -= 1;
    }
    if diff_L > diff_R
        true_L += 2;
    if diff_R > diff_L
        true_R -= 2;
    switch (argument)
    {
        case bbox_left: return true_L;break;
        case bbox_right: return true_R;break;
    }
}

If it doesn't work, let me know. I haven't tested it out in my coding yet but in theory it should work. It should in theory return the same values for bbox_left and bbox_right for both image_xscale=1 and image_xscale=-1.
Your mom has had more floppies put in her than a Commodore 64!


Follow my lack of progress on my game at my blog:
http://gmvania.blogspot.com

Offline Inccubus

  • Wannabe Great Old One
  • Master Hunter
  • *****
  • Posts: 3265
  • Gender: Male
  • Warrior
  • Awards The Retro Gamer: Has a heated passion for the oldschool VG Titles. SuperOld Dungeonite: Members who have been around since the oldOLD days. Permanent Resident: Seems to always be around to post/reply.
    • Awards
  • Favorite Game: Vampire Killer (MSX)
  • Likes:
Re: Attention GameMaker users: Update on image_xscale bug
« Reply #2 on: October 27, 2011, 01:19:32 PM »
0
Thanks for this. Have you filed a bug report for it?
"Stuff and things."

Offline TheouAegis

  • Amateur Auteur of GMvania
  • Master Hunter
  • *****
  • Posts: 1860
  • Gender: Male
  • Awards The Retro Gamer: Has a heated passion for the oldschool VG Titles. The Great Defender will always defend the object of his or her fandom. Hack Master makes creations out of CV parts. (S)he makes Dr. Frankenstein proud.
    • GMvania Developer's Blog
    • Awards
  • Likes:
Re: Attention GameMaker users: Update on image_xscale bug
« Reply #3 on: October 27, 2011, 04:42:43 PM »
0
No one believes me when I tell them it's there. Managed to convince one of the forum's mods but that doesn't mean anything. ... In other words, no not yet. But someone else might have already. Not sure.
Your mom has had more floppies put in her than a Commodore 64!


Follow my lack of progress on my game at my blog:
http://gmvania.blogspot.com

Offline TheouAegis

  • Amateur Auteur of GMvania
  • Master Hunter
  • *****
  • Posts: 1860
  • Gender: Male
  • Awards The Retro Gamer: Has a heated passion for the oldschool VG Titles. The Great Defender will always defend the object of his or her fandom. Hack Master makes creations out of CV parts. (S)he makes Dr. Frankenstein proud.
    • GMvania Developer's Blog
    • Awards
  • Likes:
Re: Attention GameMaker users: Update on image_xscale bug
« Reply #4 on: April 07, 2012, 09:58:56 PM »
0
I just found a bug in my script. I forgot to compensate for GM's never letting you set bbox_right to the full sprite width. This was throwing off the script in some cases when image_xscale was negated. This should work now, as I just ran another visual test of it and saw no change in the bounding box when I mirrored the sprite.

I also added an untested compensator for flipped sprites. Like I said, i haven't tested it yet but it should be the same in theory.

Code: [Select]
//Corrects bounding box offsets in room when using negative sprite scaling
//Use: sprite_get_bbox(bbox)


if (argument=="bbox_left" || argument=="bbox_right") && image_xscale<0
{
    var diff_L,diff_R,true_L,true_R;
    //Calculate distances bounding box edges are from sprite border
    diff_L = sprite_get_bbox_left(sprite_index);
    diff_R = sprite_get_width(sprite_index)-1-sprite_get_bbox_right(sprite_index);
   
    //Store bounding box coordinates in the room for manipulation
    true_L = bbox_left;
    true_R = bbox_right;
   
    //Check and compensate for symmetrical bounding box stretching
    if diff_L = diff_R
    {
        true_L += 1;
        true_R -= 1;
    }
    else
    //Check and compensate for leftward stretch
    if diff_L > diff_R
    {
        //Check and compensate for bounding box shift to the left
        true_L += 1 + diff_L - diff_R;
        true_R += diff_L - diff_R - 1;
    }
    else
    //Check and compensate for rightward stretch
    if diff_R > diff_L
    {
        //Check and compensate for bounding box shift to the right
        true_L -= diff_R - diff_L - 1;
        true_R -= diff_R - diff_L + 1;
    }
    //Return the corrected bbox_ value
    switch argument
    {
        case "bbox_left":     return true_L; exit;
        case "bbox_right":    return true_R; exit;
    }
}

else

if (argument=='bbox_top' || argument='bbox_bottom') && image_yscale<0
{
    var diff_T,diff_B,true_T,true_B;
    //Calculate distances bounding box edges are from sprite border
    diff_T = sprite_get_bbox_top(sprite_index);
    diff_B = sprite_get_height(sprite_index)-1-sprite_get_bbox_bottom(sprite_index);
   
    //Store bounding box coordinates in the room for manipulation
    true_T = bbox_top;
    true_B = bbox_bottom;
   
    //Check and compensate for symmetrical bounding box stretching
    if diff_T = diff_B
    {
        true_T += 1;
        true_B -= 1;
    }
    else
    //Check and compensate for upward stretch
    if diff_T > diff_B
    {
        //Check and compensate for bounding box shift up
        true_T += 1 + diff_T - diff_B;
        true_B += diff_T - diff_B - 1;
    }
    else
    //Check and compensate for downward stretch
    if diff_B > diff_T
    {
        //Check and compensate for bounding box shift down
        true_T -= diff_B - diff_T - 1;
        true_B -= diff_B - diff_T + 1;
    }
    //Return the corrected bbox_ value
    switch argument
    {
        case 'bbox_top':      return true_T; exit;
        case 'bbox_bottom':   return true_B; exit;
    }
}

else
return argument;
« Last Edit: April 08, 2012, 11:58:36 AM by TheouAegis »
Your mom has had more floppies put in her than a Commodore 64!


Follow my lack of progress on my game at my blog:
http://gmvania.blogspot.com

Tags: