PDA

View Full Version : Weird Bug With Screen->Arc Drawing



ywkls
10-18-2017, 02:07 PM
So, I wrote up the following script and had some weird bugs surface...

https://pastebin.com/ybdkGbVn

When the angle at which the arc is being drawn reaches certain values; the drawn area encompasses the entire screen.
This is the desired appearance...
https://cdn.discordapp.com/attachments/368564070758219787/369930586955055114/zelda001.png

The angles which caused this are calculated based on Distance between the ffc and Link->X+8,Link->Y. At most angles, it looks right. But at some, it doesn't.
The angles which generate the error are hard to define, but -87.3646 was one.
This is what that looked like.
https://media.discordapp.net/attachments/368564070758219787/370271213874053120/zelda005.png

I'm not entirely sure why this occurs and the number of possible angles is too numerous for me to check them all.

ZoriaRPG
10-18-2017, 06:17 PM
Does this occur with angles clamped between 0 and 359.9999?

Gleeok
10-19-2017, 02:26 AM
Can you add in a few lines to your script and post the values being passed to arc? ex:



Screen->Arc(args...);
if(Link->PressEX4) //press this key when the arc fails
{
Trace(arg0);
Trace(arg1);
Trace(arg2);
Trace(arg3);
}


[edit] Also, can you postor PM the script?

ZoriaRPG
10-19-2017, 03:29 AM
Can you add in a few lines to your script and post the values being passed to arc? ex:



Screen->Arc(args...);
if(Link->PressEX4) //press this key when the arc fails
{
Trace(arg0);
Trace(arg1);
Trace(arg2);
Trace(arg3);
}


[edit] Also, can you postor PM the script?



I second the traces, but ywkls did provide the script in his OP via a post on Pastebin.

Here's a local copy for the thread:



ffc script Eye_Sentry{
void run(int item_id, int perm, bool left){
bool triggered = false;
float angle;
int sfxTimer;
if(Screen->D[perm]==1)
triggered= true;
while(!Link->Item[item_id])
Waitframe();
Screen->D[perm]=1;
this->Data++;
while(!triggered){
if(left){
//angle between object and player
angle = Angle(this->X+24, this->Y+8,Link->X+8,Link->Y);
//Because arc is weird.
angle *=-1;
Screen->Arc(3, this->X+8, this->Y+8, 256, angle+10,angle-10, 1, 1, 0, 0, 0, true, true, OP_TRANS);
}
else{
angle = Angle(this->X+8, this->Y+8,Link->X+8,Link->Y);
angle *=-1;
Screen->Arc(3, this->X+8, this->Y+8, 256, angle+10,angle-10, 1, 1, 0, 0, 0, true, true, OP_TRANS);
}
//Create sound every sixty seconds.
if ( sfxTimer == 0 ) Game->PlaySound(SFX_X_RAY);
sfxTimer = (sfxTimer+1)% 60;
Waitframe();
}
this->Data=GH_INVISIBLE_COMBO;
}
}


Shouldn't the value of the angle passed to Arc() always be absolute, from 0 to 359.9999 ?

std.zh states:
The behavior of this function is undefined unless * 0 <= endangle-startangle < 360.

At the very least, you want WrapDegrees, or VBound() to clamp the values within the legal range.

Passing a value of -84 or whatever, would do unpredictable things.
ywkls: Does using WrapDegrees( angle+10 ), WrapDegrees ( angle-10 ) work?

I think there may be points where the angle orders are reversed in your code, based on what the variables are at the time of the error: If startangle is higher than endangle, it might invert as you descripe.

Gleeok
10-19-2017, 04:05 AM
Oh, I missed that he posted a link to the script in the OP. Whoops.

But yes, my first suspicion was that the arguments being passed were unintentional. ..and yeah, it does look like you are passing negative numbers in reverse order.

Still might be a corner-case bug though if you want to trace the values that draw an entire screen sized rect.

ZoriaRPG
10-19-2017, 06:02 AM
Oh, I missed that he posted a link to the script in the OP. Whoops.

But yes, my first suspicion was that the arguments being passed were unintentional. ..and yeah, it does look like you are passing negative numbers in reverse order.

Still might be a corner-case bug though if you want to trace the values that draw an entire screen sized rect.

I suspect that most users overlook that the degree values must be logical values between 0 and 360. I thought that it would clamp to 359.9999, but the docs say 0->360. :shrug:

I could fix this with an overload in std.zh.

Something like this, perhaps?



void Arc
(int layer, int x, int y, int radius, int startangle, int endangle, int color, float scale,
int rx, int ry, int rangle, bool closed, bool fill, int opacity )
{
startangle = WrapDegrees(startangle); endangle = WarpDegrees(endangle);
if ( startangle > endangle )
{
Screen->Arc(layer, x, y, radius, endangle, startangle, color, scale, rx, ry, rangle, closed, fill, opacity);
}
else
{
Screen->Arc(layer, x, y, radius, startangle, endangle, color, scale, rx, ry, rangle, closed, fill, opacity);
}

}



Here is a potentially useful debug function for Arc():




//The same as above, but with logging option.
void Arc
(int layer, int x, int y, int radius, int startangle, int endangle, int color, float scale,
int rx, int ry, int rangle, bool closed, bool fill, int opacity, bool debug)
{
if ( debug )
{
if ( startangle > 360 )
{
int s[]="Value supplied to startangle is outside the legal range of 0 to 360. The value provided was: ";
TraceNL(); TraceS(s); Trace(startangle); TraceNL();
}
if ( endangle > 360 )
{
int s[]="Value supplied to endangle is outside the legal range of 0 to 360e. The value provided was: ";
TraceNL(); TraceS(s); Trace(endangle); TraceNL();
}
if ( startangle < 0 )
{
int s[]="Value supplied to startangle is outside the legal range of 0 to 360. The value provided was: ";
TraceNL(); TraceS(s); Trace(startangle); TraceNL();
}
if ( endangle < 0 )
{
int s[]="Value supplied to endangle is outside the legal range of 0 to 360. The value provided was: ";
TraceNL(); TraceS(s); Trace(endangle); TraceNL();
}
}

startangle = WrapDegrees(startangle); endangle = WarpDegrees(endangle);
if ( startangle > endangle )
{
if ( debug )
{
int s[]="The angles provided to Arc() are in the reverse order!"; TraceNL(); TraceS(s); TraceNL();
}
Screen->Arc(layer, x, y, radius, endangle, startangle, color, scale, rx, ry, rangle, closed, fill, opacity);
}
else
{
Screen->Arc(layer, x, y, radius, startangle, endangle, color, scale, rx, ry, rangle, closed, fill, opacity);
}

}


Now, that will slow ZC to a crawl if called every frame (and there are errors to log). :D

ywkls
10-19-2017, 11:40 AM
I'm confused... is startangle or endangle supposed to be larger?
I think part of this is due to the fact the Arc works counterclockwise and everything else rotates in the opposite direction.
Strangely, the function seems to do what it is supposed to even if either is true? (Startangle is smaller or larger than endangle)
I hadn't tried WrapDegrees yet (couldn't remember what it did) so I wrote up this version instead.



angle = Angle(this->X+24, this->Y+8,Link->X+8,Link->Y);
angle*=-1;
if(angle<0)
angle+=360;



Since adding 360 to the negative angle would have it rotate to the exact same angle(only positive) I thought that might work.
But, that hasn't proven to be the case.
Looking at WrapDegrees, I'm not sure it'd be better; but I'll try it and post the results afterward.

ZoriaRPG
10-20-2017, 08:39 AM
I'm confused... is startangle or endangle supposed to be larger?
I think part of this is due to the fact the Arc works counterclockwise and everything else rotates in the opposite direction.
Strangely, the function seems to do what it is supposed to even if either is true? (Startangle is smaller or larger than endangle)
I hadn't tried WrapDegrees yet (couldn't remember what it did) so I wrote up this version instead.



angle = Angle(this->X+24, this->Y+8,Link->X+8,Link->Y);
angle*=-1;
if(angle<0)
angle+=360;



Since adding 360 to the negative angle would have it rotate to the exact same angle(only positive) I thought that might work.
But, that hasn't proven to be the case.
Looking at WrapDegrees, I'm not sure it'd be better; but I'll try it and post the results afterward.


EndAngle should be higher. Try running your code with the debugging function that I posted.

ywkls
10-20-2017, 08:29 PM
EndAngle should be higher. Try running your code with the debugging function that I posted.

I feel almost like Arc needs a conversion function to work easily with other stuff, since it is so non-intuitive.
As I posted on Discord, I was confused because the correct (and incorrect) results happened both when startangle was larger and when it was smaller.

Using the function you posted, I changed the code like so...


//Section 120. Eye Sentry

ffc script Eye_Sentry{
void run(int item_id, int perm, bool left){
bool triggered = false;
float angle;
int sfxTimer;
if(Screen->D[perm]==1)
triggered= true;
while(!Link->Item[item_id])
Waitframe();
//Screen->D[perm]=1;
this->Data++;
while(!triggered){
if(left){
angle = Angle(this->X+24, this->Y+8,Link->X+8,Link->Y);
//angle*=-1;
Arc(3, this->X+24, this->Y+8, 256, angle-10,angle+10, 1, 1, 0, 0, 0, true, true, OP_TRANS,true);

}
else{
angle = Angle(this->X+8, this->Y+8,Link->X+8,Link->Y);
//angle*=-1;
Arc(3, this->X+8, this->Y+8, 256, angle-10,angle+10, 1, 1, 0, 0, 0, true, true, OP_TRANS,true);

}
//Create sound every sixty seconds.
if ( sfxTimer == 0 ) Game->PlaySound(SFX_X_RAY);
sfxTimer = (sfxTimer+1)% 60;
Waitframe();
}
this->Data=GH_INVISIBLE_COMBO;
}
}


I didn't get the screen-covering effect, just an arc that was on the opposite side of the screen from what I wanted.
I'm not sure about the best way to rotate it to where it should be.
I'd previously used angle *=-1 but that didn't really work. Nor did using WrapDegrees on the outcome of that.

Any suggestions? My alternative is to use a versiion of Screen->Triangle Moosh provided which I've already gotten to replicate the effect I want.
(Hence my interest here is mostly to find the cause of this.)

Dimentio
10-21-2017, 05:14 PM
I know for a fact that if the angle's radius in certain angles exceeds a boundary somewhere past the edge of the screen, it'll do that wraparound thing. Try a smaller radius.