Castlevania Dungeon Forums
Off Topic => Off Topic => Topic started by: TheouAegis on October 25, 2011, 05:56:19 PM
-
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:
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)
-
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".
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.
-
Thanks for this. Have you filed a bug report for it?
-
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.
-
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.
//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;