Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » Problem with sin cosine

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Problem with sin cosine
blargmob
Member #8,356
February 2007
avatar

Howdy,

I read the post about "how to make an object move in the direction its pointing" and clicked on the link the directed me to an article about this kind of stuff becuase I also had that problem. So I read the article and noticed that I could pass a radian to the "sin()" and "cos()" functions, than multiply the return by the length of the velocity vector. But in order to make this work for me, I had to first convert the allegro degrees (256) of my object into normal degrees (360), than find the radian of the result and pass the final result to the two functions. This worked, but as I read further on, I noticed that "fsin()" and "fcos()" accepted allegro degrees as their parameters, I tried this and it didn't work.....any suggestions?:-/

---
"No amount of prayer would have produced the computers you use to spread your nonsense." Arthur Kalliokoski

ImLeftFooted
Member #3,935
October 2003
avatar

Quote:

I tried this and it didn't work.....any suggestions?:-/

Yes actually, I suggest you post a small (ie <15 lines) bit of code that demonstrates your problem.

LennyLen
Member #5,313
December 2004
avatar

Quote:

but as I read further on, I noticed that "fsin()" and "fcos()" accepted allegro degrees as their parameters, I tried this and it didn't work.....any suggestions?

What do you mean by "didn't work?" And were you actually using the correct function names, which are fixsin() and fixcos()? Here's the manual entry for fixsin() so you can see how it should be used.

By the way, for modern computers with fast FPUs, using the fixed versions may actually be slower than their floating point counterparts.

blargmob
Member #8,356
February 2007
avatar

Well, the article said the "fsin()" and "fcos()" are the function names. I compile with no errors but when I run the program some super - duper - oober high number is produced. Also, when I try to declare the angle as "fixed" my compiler returns an error that says "fixed" is invalid and doesn't work.

---
"No amount of prayer would have produced the computers you use to spread your nonsense." Arthur Kalliokoski

kazzmir
Member #1,786
December 2001
avatar

#include <allegro.h>

fixed f = fsin( itofix( 192 ) ); // 192 is 270 degress

IIRC

blargmob
Member #8,356
February 2007
avatar

I tried to pass the angle variable in the "fcos()" and "fsin()" functions using itofix but that didn't work either....help please!.....

---
"No amount of prayer would have produced the computers you use to spread your nonsense." Arthur Kalliokoski

kazzmir
Member #1,786
December 2001
avatar

Show some friggin code!

blargmob
Member #8,356
February 2007
avatar

 int shipangle;
int laserxspeed;
int laseryspeed;
int laserx,lasery;

if(key[KEY_LEFT])
     shipangle++;
if(key[KEY_RIGHT])
     shipangle--;

laserxspeed = 8 * fcos(itofix(shipangle));
laseryspeed = 8 * fsin(itofix(shipangle));

laserx += laserxspeed;
lasery += laseryspeed;

---
"No amount of prayer would have produced the computers you use to spread your nonsense." Arthur Kalliokoski

kazzmir
Member #1,786
December 2001
avatar

laserxspeed = 8 * fixtof(itofix(shipangle));
laseryspeed = 8 * fixtof(itofix(shipangle));

you have to convert fix back to float/int.

alternatively you can just use cos/sin from the standard math library...

gnolam
Member #2,030
March 2002
avatar

Quote:

I had to first convert the allegro degrees (256) of my object into normal degrees (360), than find the radian of the result

... why not just convert directly between Allegro degrees and radians (* π / 128)? :P

Of course, the best course of action is to keep everything in radians and only convert when drawing (* 128 / π). It's by far the easiest, most convenient and readable way. And for Eris's sake, use floats!

1#include <math.h>
2#include <allegro.h>
3 
4float shipangle;
5float laserxspeed, laseryspeed;
6float laserx,lasery;
7 
8void your_function(void)
9{
10 if(key[KEY_LEFT])
11 shipangle += SOME_PROPER_AMOUNT;
12 if(key[KEY_RIGHT])
13 shipangle -= SOME_PROPER_AMOUNT;
14 
15 laserxspeed = 8 * cos(shipangle);
16 laseryspeed = 8 * sin(shipangle);
17 
18 laserx += laserxspeed;
19 lasery += laseryspeed;
20}

void and_then_draw_it(void)
{
 rotate_sprite(buffer, shipsprite, shipx, shipy, ftofix(shipangle*128.0/M_PI));
}

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

blargmob
Member #8,356
February 2007
avatar

But if I stick with float point math I have to do conversions everry time I call sin() and cos().

---
"No amount of prayer would have produced the computers you use to spread your nonsense." Arthur Kalliokoski

gnolam
Member #2,030
March 2002
avatar

No. Unless you mean the float->double conversion in sin() and cos() (they take and return doubles), but even the overly anal language of C++ does that automagically without complaining. :P
(And, of course, using doubles is always an option as well)

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

blargmob
Member #8,356
February 2007
avatar

gnolam said:

sin() and cos() (they take and return doubles)

No. Sin() and cos() both take radians, not doubles. (unless you meen the radian AS the double) And how come when I declare a variable with "fixed" my compiler returns an error saying that "fixed" isn't a class and doesn't exist?

---
"No amount of prayer would have produced the computers you use to spread your nonsense." Arthur Kalliokoski

kazzmir
Member #1,786
December 2001
avatar

Quote:

(unless you meen the radian AS the double)

Yes, he meant radians as doubles. radians are a unit of measure, doubles are an encoding of numeric quantity, they are independant of each other. It would be like saying "im going to measure this in meters, not integers".

Quote:

And how come when I declare a variable with "fixed" my compiler returns an error saying that "fixed" isn't a class and doesn't exist?

I forget exactly what causes this, are you including <allegro.h> before you use a fixed variable?

Michael Jensen
Member #2,870
October 2002
avatar

Dont use fixed numbers, they're slower than just using doubles and only have a precision from ~-32000 to ~32000 -- just use itofix and ftofix when you need to pass them into allegro functions...

Also as kazzmir said, radians, degrees, and allegro degrees are just units of measure. You can put radians into a double, a float or a fixed, just as well as you can put allegro degrees, or degrees, or meters, miles, or light years in.

A radian is a number between 0 and ~6.2831 (PI*2), a degree is between 0 and 360, and an allegro degree is between 0 and 255 -- they're all the same and you can use basic fractional math to convert between them.

For simplicity sake, you could do the following after including math.h (and make sure you include math.h or cos/sin won't work right):

#include <math.h>
#define DegToRad   PI/180.0f
#define RadToDeg   180.0f/PI

then when you have a variable:

double myvar = 180;  //180 degrees
double length = 10;  //10 pixels

and you need to pass it into cos or sin you can:

//the double "myvar" is in degrees, but cos and sin only take doubles as radians!
double dx = cos(myvar * DegToRad) * length;
double dy = sin(myvar * DegToRad) * length;

8-)

edit:
To convert from degrees to allegro degrees:

#define DegToADeg   256.0f/360.0f
#define ADegToDeg   360.0f/256.0f

And Similarly to convert allegro degrees to radians:

#define ADegToRad   PI/128.0f
#define RadToADeg   128.0f/PI

blargmob
Member #8,356
February 2007
avatar

Ah,ha! Thanks. That's what I was looking for. A simply and fast way to convert....thanks. (Can't believe I didn't think of that);)

---
"No amount of prayer would have produced the computers you use to spread your nonsense." Arthur Kalliokoski

Tobias Dammers
Member #2,604
August 2002
avatar

On the radians / double issue again:
Computers don't know about units (meters, degrees, liters, ampères, kelvins, radians and what have you) when doing calculations; all units are usually implicit, and the function takes something as an argument or returns something that is to be interpreted as a real-world number, the documentation usually specifies what unit is expected. For many things, especially in the computing world, there are conventions that pretty much everybody adheres to: for example, the size of a data chunk is given in bytes (not 12-bit binary words, or words of 57 base-7 digits). For other types of quantities though, such as angles, the matter isn't as clear, since there are several systems being used alongside each other; in this case, there are 3 systems involved, each of which has its advantages:
- Degrees; a full circle equals 360 degrees. This format is very human-friendly, since most commonly used angles are represented as whole numbers (0, 30, 45, 90, 180). It also allows for easy conversion to and from the "clock" system (the system used by sailors and aircraft pilots to indicate relative directions: "Enemy fighters at 3 o'clock!") - each hour equals 30 degrees. OpenGL uses this format.
- Radians; a full circle equals 2 * PI. From the mathematician's point of view, this is the "natural" way of measuring angles, because it defines the angle by the length of an arc on the unit circle. In other words, an angle in radians equals the length of its arc divided by a radius. (It makes more sense when you see it sketched on paper). Also, all the trig functions can be used unchanged for various circle calculations when using radians. Downside is that angles in this format look very un-intuitive, because PI is not a whole number. The C math library (libm) uses radians.
- Allegro degrees; a full circle equals 256. Big advantage is that it allows for a number of speed optimizations, especially on older computers. Wrapping an angle into a full-circle-range, which usually requires a modulo operation, can be optimized to a bitwise-and, because 256 is a power-of-2. It is still quite intuitive (half circle is 128, 1/4 is 64, etc.); downside, though, is that it is incompatible with pretty much all other libraries, including libm.

The unit chosen is independent from the numeric encoding format you use: int, allegro::fixed, float, double, etc.
The issue with allegro's math functions is that they expect fixed-point numbers, but since they are typedef'ed as long ints, C cannot tell the difference, nor convert them correctly for you.

My suggestion is to leave the fixed-point math alone altogether, and do everything using floats (or doubles) and radians. The only point where you really can't avoid 256-based fixed-point values is when you pass angles to allegro's drawing functions, in which case you should just take the float-point value and convert it on-the-fly, like this:

#include <allegro.h>
#include <math.h>
// assuming angle to be a float:
rotate_sprite(screen, sprite, 100, 100, ftofix(angle * 128.0f / M_PI));

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

X-G
Member #856
December 2000
avatar

Quote:

#define DegToADeg 256/360
#define ADegToDeg 360/256

Baaaaaaaad idea. 256/360 is an integer division, resulting in an integer. You want 256.0/360.0 or something similar.

Quote:

"Enemy fighters at 3 o'clock!") - each hour equals 15 degrees.

Don't you mean 30 degrees?

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Tobias Dammers
Member #2,604
August 2002
avatar

'course. 30 degrees. I'll go edit, hehe.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Michael Jensen
Member #2,870
October 2002
avatar

Quote:

Baaaaaaaad idea. 256/360 is an integer division, resulting in an integer. You want 256.0/360.0 or something similar.

Thank you, I'll edit that post and put 256.0f/360.0f -- etc, I've been using VB.NET where constants have to be declared with data types and this would work fine, and I've forgotten about some the annoyances of C...

Public Const DegreesToADegrees As Double = 256 / 360

BAF
Member #2,981
December 2002
avatar

Even 256/360.0f would do. But, even that looks like horrible coding style to me (DegToADeg sounds like a function, not a constant, which should be const float blah = blah anyway ;)). I'd personally do #define DegToADeg(x) = (x) * 256/360.0f.

Tobias Dammers
Member #2,604
August 2002
avatar

Quote:

#define DegToADeg(x) = (x) * 256/360.0f.

What about:

const float DEG2ADEG_FAC = 256.0f / 360.0f;
inline float DegToADeg(float x) { return x * DEG2ADEG_FAC; }

?

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

BAF
Member #2,981
December 2002
avatar

That's even better.

[edit]
Nevermind

ImLeftFooted
Member #3,935
October 2003
avatar

Baf said:

I'd personally do #define DegToADeg(x) = (x) * 256/360.0f.

#define DegToADeg(x) = (x) * (256/360.0f)

Makes it easier for a compiler to optimize your code.

Matt Smith
Member #783
November 2000

Some versions of <math.h> define fcos() and fsin() as float versions (rather than double) of sin() and cos()

This is why Allegro's fsin() and fcos() have been renamed to fixsin() and fixcos(). It is better to use the new names to avoid confusion (both by you and by your compiler). The old compatability defines may be removed by Allegro 5.0.

 1   2 


Go to: