I've made a mini-tutorial on BMax angles

Miscellaneous Forums/General Discussion/I've made a mini-tutorial on BMax angles

OK, during the last day or so I've been asking all sorts of crazy questions on the forum and geting back into my vector maths and trig from a long time ago. Anyway, I found out some useful stuff that some of you might not know, so I thought I'd post it in case someone else found it useful, and perhaps people may even come up with other useful points.





--------------------------------------------------

1) The first thing is that vector maths in all the textbooks assumes that the Y coordinate goes UP and X goes to the RIGHT. Makes sense if you think of it like a normal graph (see fig 1)

Also when measuring angles in degrees, they go ANTI-CLOCKWISE round from the Positive X axis. Thus at:

1,0 the angle is 0
0,1 the angle is 90
-1,0 the angle is -180
-1,-1 then angle is -270

This seems a bit weird if you are used to thinking of rotation as CLOCKWISE and starting from the TOP, just like how BlitzMax Rotation works (see fig 3).



--------------------------------------------------

2) On computer screens the Y coordinate points DOWN the screen as it gets bigger (See fig 2). This is the exact opposite to how the maths books depict it and thus it has a big effect on your vector maths and trigonemtry. For a start rotation is now measured CLOCKWISE, although it still starts at 0 on the Positive X axis.



--------------------------------------------------

3) Here's an example. Say I want to fire a ball in any direction based on a rotating arrow and a fixed speed, and then I want to slow it down with friction.

Well I might be rotating my arrow using BMax, so it'll range from 0 to 360 degrees CLOCKWISE measured from the TOP (the negative Y axis). So when the user clicks "Fire" we know the angle of launch. We also know the fixed speed.

Using the angle and the fixed speed we should be able to work out the X and Y components of the speed as follows:

XSpeed = BallSpeed * Cos(angle)
YSpeed = BallSpeed * Sin(angle)

BUT this won't work because that is the "normal" maths way to work out the X and Y speed which assumes the rotation starts at Positive X axis and goes ANTI-CLOCKWISE, but BlitzMax goes CLOCKWISE from the Negative Y axis if you recall.

So I now do this:

XSpeed = BallSpeed * Sin(angle)
YSpeed = BallSpeed * (0-Cos(angle))

Which takes the BMax rotation angle and gives X and Y speeds in the correct direction. I could have adjusted the angle by 90 degrees first and used a different calculation.



--------------------------------------------------

4) Here's another example. So I want to slow my ball down with friction. We I could simply multiply the X and Y speeds by an amount <1 each frame (you must not subtract friction from the X and Y as they are only components of a true Ball Speed which is at an angle!). However, I going to do it properly and reduce Ball Speed by friction and the recalculate the X and Y speeds using ArcTan.

So I get my BallSpeed and do: BallSpeed=BallSpeed - Friction

ArcTan will tell me the angle between the positive X axis and the tangent line (t) that my ball is travelling along (see fig 4).

I want to get the angle, because we know the new BallSpeed and we can use the calculations point 3 to give us the new X and Y speed components.

To make ArcTan return a valid angle you have to pass in the SLOPE of a line. This is easy, it's simply the ratio of Y/X. So I call:

Angle = ArcTan(BallYSpeed/BallXSpeed)

Woo, we've got an angle, but there's a problem, in fact there are several.

ArcTan doesn't give nice angles from 0 to 360, it gives them from -90 through 0 to 90 depending on which QUADRANT the line was in (See fig 4). I've marked the quadrants from 1-4 in roman numerals. I is the first quadrant and IV is the last.

You can see that the positive angles are opposite each other and the negative angles are opposite each other. (Note that fig 4 shows the y axis as on a Computer Screen.)

So here's some nice jiggery pokery. Lines in quadrants II and III can be considered 180 degrees away from their "proper" opposites. So if you check your line's X component and discover that it's negative, you can simply add on 180 degrees to the result. This gives you results in the range 0 to 270 from the positive X axis up to the negative Y axis (quandrants I, II, and III). Great!

But we still have -90 to 0 in quadrant IV *and* the angle starts from the positive X axis unlike BlitzMax which starts from the top. However, this can be easily fixed by adding on 90 degrees to the result. Then quadrant IV changes from negative into 0 to 90, quadrant II goes up and is now 90 to 180, quadrant III is now 180 to 270 and quadrant IV is now 270 to 360. Tada!

Now it's safe to use the resulting angle as a BlitzMax rotation if you wanted and to work out the X and Y Speeds based on the formulas in point 3.

By the way, you can also get the angle by using the Dot Product of two vectors, but that's a topic for another day.

--------------------------------------------------

I hope you enjoyed reading this. Please help me add to this if you know more cool stuff. Thanks.

This does my head normally and I end up getting very strange behaviour in my games

well hopefully this will help a bit. It's not too complex, but I haven't gone on about finding the angle between two lines, and calculatig normals, and normalising vectors and all that jazz yet.

I'm a bit confused. Do Cos/Sin etc work differently in bmax, or something?

There output is consistent with 2D screen axes in Blitz3D. You can also use angles in whichever way you prefer e.g. Cos(-90) is identical to Cos(270).

Also, what's wrong with ATan2? Don't tell me bmax doesn't have that?! :)

trust me, if you use sin and cos in the normal manner with an angle starting at 12 oclock, it will make the ball fly off in the wrong direction.

Atan2, cool I'll have to look into that.

No they work normally.

Friction should be a constant rather than a proportion of velocity.

I would calculate it by normalising the x and y speeds and multiplying that by the friction constant.

something like:

const friction#=0.1  ;This is your constant value for friction,  you might want it to be a variable based on the surface

; xvel & yvel are the current velocity of the ball

speed#=sqr (xvel*xvel + yvel*yvel)

frx#=(xvel/speed)*friction
fry#=(yvel/speed)*friction

; frx,fry is a vector with the same direction as xvel,yvel but its length is the same as 'friction'

;subtract the friction vector from the movement vector

xvel=xvel-frx
yvel=yvel-fry




Friction should be a constant rather than a proportion of velocity.



Yes but you also need to ensure that by applying it you do not reverse the sign of the velocity. I guess you could simulate static friction in your example by setting frx and fry to xvel, yvel if the speed < 0.1.

Stevie

you won't reverse any velocity if you multiply it by a constant.. say friction = 0.99, means that there is almost no friction at all, and if friction = 0.1, it will stop pretty fast.. :)

@ LarsG,

If you multiply the velocity by a friction constant then yes. Clearly I'm talking about Johns example which is using the unit vector direction of the velocity where the speed has no relevance to the friction applied, so at low speeds the friction could be higher than the velocity. While not physically correct it is a much better friction model than a velocity dependant equivalent..

well.. all I know is that it works very well. I've used it several times. :)

agreed.

Thanks JP for that, it's a different approach where you are reducing the X and Y components of the speed by an amount based on a constant (friction) multiplied by the Normalised x and y components (so friction will remain the same throughout the animation). With mine, I just got the speed of the object and applied a constant friction to it then just converted that back into the X and Y components, same result unless I'm mistaken. I'm wondering if like air resistence, friction decreases over certain speeds. It probably does in real life but the modeling would depend on many factors.

Probably have to edit the top post soon as new info comes in... As big10p questioned and John Pickford confirmed, Sin and Cos DO work the same as in maths where 0 degrees is on the Positive X axis.

here's some example code:

Strict

Graphics 800,600,0

Global image:TImage = LoadImage("header.png")
MidHandleImage(image)

Global radius=100
Global x = 400
Global y = 300
Global a:Float=0
While Not KeyHit(KEY_ESCAPE)
	Cls
	Plot x+radius*Cos(a),y+radius*Sin(a)		
	SetRotation a
	DrawImage Image,x,y
	SetRotation 0
	a:+1
	If a>360 Then a:-360
	Flip
Wend


My cock up was basically I had loaded in an arrow pointing up, and that was the image I was rotating and I wanted the ball to fire in the direction it was pointing. When drawn at 0 rotation the arrow points up, yet all my calcs made the ball fly off to the side and I thought "weird" so I rejigged the cos and sin to account for the 90 degree offset :-) Then I kinda assumed BMax rotation started at the top as it seemed logical when I was thinking about the arrow graphics haha, when in fact it starts on the positive X axis.

[edit]I just changed the code where I fired the ball to x=cos(arrowangle-90) and y = sin(arrowangle-90) and it works fine :-)

I just make all my sprites that need to relate visually to Blitzmax rotation, just point to the right in the texture. ;)

I'll be doing that from now on too :-)