Game math: atan

28/12/2009

Hm, I wanted to shoot an arrow, in the direction in which a sprite is dragged, using the touchscreen of course.
So the arrow sprite has to be rotated, and we have the x distance and the y distance of the dragging.
To get the angle, normally the atan or atan2 is used (this even works in Second Life!!!)
First possibility:

atan gives an error….. not found in devkitpro???

if this happens take a look at your makefile:

#———————————————————————————
# any extra libraries we wish to link with the project
#———————————————————————————
LIBS    := -lmm9 -lnds9 -lm

this last -lm tells the compiler to include mathematical libraries. Sometimes in example makefiles it is left out.

Ok the atan function is found, how to work with it?

By the way without a library you have two possibilities:

  • working with approximations
  • working with tables

Working with approximations

If you want to do math without the math library you can always use approximations, which are quite good: I wrote about this in another blog: http://nds-homebrew-hslleiden.blogspot.com/2008/06/nds-and-atan.html

Approximations can be found on the internet, for sin, cos, tan, atan, and of course other math functions.

Working with tables: LUT look up table

When working on smaller or slower devices, you dont use complicated functions like sin, atan, you use tables. At the start you generate an array with the values you need for your functions, probably, also because the screen is small, only 255 for a whole 360 degrees. This costs a bit of memory space, but looking up something in this table is much faster than calculating the function.

An example:

float sinTable[255];

u8 x = 0;

for(x=0;x<255;x++)

sinTable[x] = sin( 360 /255 * x * 2 * PI );

you do this once at the beginning of your app and after that:

you just ask the value of your  array for 180 degrees: sinTable[128]

You can even do better because of the symmetry of the sin:

When over 180 degrees you use the negative value of the x-180, saving half of the mem space needed for the table. The cosTable can also be minimized, the cos having the same shape and being “in front” 90 degrees.

cos ( x ) = sin ( x + 90 degrees)

be careful with negative x or x bigger than 360. (360 degrees = 255 u8)

ok: not working with floats? multiply the value by say 1000 and use the int:

int sinTable[255];

u8 x = 0;

for(x=0;x<255;x++)

sinTable[x] = (int)(1000* sin( 360 /255 * x * 2 * PI ));

later on you divide by 1000 needing a value of the LUT: sinTable[128]/1000

saving lots of space!
Remark: say you dont have a sin function. You are not able to calculate your table. Then you calculate the list in another IDE and import this prepared LUT as a textfile using libfat.

(found this picture somewhere 🙂

Working with atan or atan2:

Of course the x and y on the screen are different from our normal thinking y being positive while going downwards.

atan( x/y ) (one arguments)  is only defined on -90 to 90 degrees so you have to be careful about the quadrants:

atan( 65 / 45 ) = 45.001327 // using atan( 65 / 45 )/PI*180 to get degrees
atan( -65 / 45 )= -45.001327
atan( 65 / -45 )=  -45.001327  //this is  a quadrant repeated
atan( -65 / -45 )= 45.001327  //this is  a quadrant repeated

The trick is simple: if y (in atan (x / y) is negative add 180 or PI.

atan2(x, y) (two arguments)  is defined on the whole 360 degrees:

atan2( 65 / 45 ) = 55.306478 // using atan2( 65 , 45 )/PI*180 to get degrees
atan2( -65 / 45 )= -55.306478
atan2( 65 / -45 ) = 124.698831
atan2( -65 / -45 )= -124.698831

all is done without worrying about the quadrants

Rotation using a matrix will b explained in another blog.


C question time

28/12/2009

Having digested an introduction in C does not mean you are a seasoned C programmer!

hmmm is this the new nds?

Pointers are connected to real memory space. Pointers can be seen as globals. But pointers have the nasty behaviour of shutting of memory if you forget to free the memory space. Also the interplay between pointers and methods must be done carefully, not allocating memspace in a method and then returning a pointer to it. The free-ing process will get messy!

So possible trouble will be ahead! Working with malloc and free and pointers makes C programming really different from programming in JAVA or C#. You need another kind of thinking.

Here a the question: (hm it takes a bit of preparing, sorry)

Say we have a struct called LINE

This struct consists of two structs called POINT and three floats

struct POINT{

float x, y;

}

struct LINE

{

struct POINT* pointPTR1;

struct POINT*pointPTR2;

float cx, cy, cc;

}

What we need is two lines parallel to line someLine (someLinePTR) (bouncing a ball with width for instance needs this)

Normally (coming from JAVA or whatever) I would have this someLine declared and call a class method passing the variable to this someLine and returning an array consisting of two lines:

(returnArray *) giveMeTwoParallelLines( someLinePtr, distance){

struct LINE* myFirstParallelLinePTR = makeAParallelLine (someLinePtr, distance);//another method returns a pointer

struct LINE* mySecondParallelLinePTR = makeAParallelLine (someLinePtr, -distance);

//returning the results in an array

(struct LINE*) returnArray[] = {  myFirstParallelLinePTR , mySecondParallelLinePTR  };

return returnArray;

}

this method is called like this:

(struct LINE*) returnArray[] = giveMeTwoParallelLines( someLinePtr, 50);

elements from returnArray can be used further on.

What is wrong here? (Take the above as an indication how the task is done, details can be different)

This is the clue:

The compiler indicates (or the app crashes) memory leaks…

Having memory leaks means that memory is allocated but not freed. In Xcode (Objective C)you can run an app inside a memory leak analizer. Devcpp doesn’t offer this service!

The whole structure of making parallel lines must be solved differently. How?

Answer in some other blog!

This was a real stupidity I committed in XCODE objective C for the Iphone (a version of C that admits classes, but for the rest is like normal C.)

http://en.wikibooks.org/wiki/C_Programming/Memory_management


Math functions like random and sin

27/12/2009

Sometimes you need a random number.

Strange enough: this math function is  found in the stdlib.h: rand() with datatype int

http://www.cs.cf.ac.uk/Dave/C/node16.html#SECTION001600000000000000000

Other math functions are found in the math.h:

like abs, cos, sin, tan, atan

http://en.wikipedia.org/wiki/Math.h

you use the libs like this:

<stdio.h>

<stdlib.h>

<math.h>

int main(){

printf( “this is a random number between 0 and 10 %d \n”, rand() % 10 );

printf( “this is a sin %f \n”, sin(.157) );

while(1) {}

}

Also in the makefile -lm should be added, if it isn’t. You get funny bugs if it isn’t.


Using libfat

27/12/2009

(this is an update of a former blog)

Libfat is a library that can save data to a file outside your game. Great for keeping scores, remembering where you were in a game and a highscore. In principle you can read an write data.

The libfat example in de devkitpro prints the directory of the nds memory card.

It only runs on the ds itself, not in the emulator i use….:-( so if you want to test it get yourself an nds.

But i needed to read in the integers describing the points of the triangulation for the minigolf game fields.

the libfat example only described reading the directory.

I found an example of really reading in a textfile here: (actually it is written for the wii, but who cares?)

http://www.codemii.com/2009/03/02/tutorial-10-using-the-filesystem/
This link describes details about the makefile, includes and a demo: http://chishm.drunkencoders.com/libfat/

The functions to read a txt file are: (adding to the example in the devkitpro)

void die(char *msg) {
perror(msg);
fatUnmount(0);
exit(0);
}

void readFile()
{
FILE *f = fopen ("hello.txt", "rb");// If file doesn't exist or can't open it then we can grab the latest file
if (f == NULL) {
die("Could not open myfile.txt file for reading.\n");
}

else {
char file_line [20];
int line_number = 0;
while (fgets (file_line, 20, f)) {
printf("Line %i: %s\n",line_number, file_line);
line_number++;
}
fclose(f);
}
}

as explained (and needed for my minigolf, reading in the triangulations of the fields)
you can easily read in and distribute integers to arrays lik this:

make these arrays global, for instance

int x_pos[] = { 0, 0, 0, 0, 0};
int y_pos[] = { 0, 0, 0, 0, 0};
void readFile()
{
FILE *f = fopen ("hello.txt", "rb");
// If file doesn't exist or can't open it then we can grab the latest file
if (f == NULL) {
die("Could not open myfile.txt file for reading.\n");
}
else {
char file_line [20];
int line_number = 0;
while (fgets (file_line, 20, f)) {
printf("Line %i: %s\n",line_number, file_line);
char *temp_string;
temp_string = strtok (file_line, " ");
if (temp_string != NULL) {
x_pos[line_number] = atoi(temp_string);
temp_string = strtok (NULL, " ");
if (temp_string != NULL) {
y_pos[line_number] = atoi(temp_string);
}
}
line_number++;
}
fclose(f);
}
}

which still prints the values as a check, this can be left out.

Writing to a file is also described above, which is useful for a highscore, eventually.

Writing in the example went well, but for the fact that the integers were written without a space, so the lines glued together.

This was solved adding:
char end_string[2] = { 0x0D, 0x0A};
fputs (end_string ,f);

so the function becomes:

void writeFile()
{
FILE *f = fopen ("myScorefile.txt", "wb");
int line_number = 5;
if (f == NULL) {
die("Couldnot open myScorefile.txt file for writing.\n");
}
else{
int x;
for (x = 0; x < line_number; x++) {
char temp_string[20];
sprintf(temp_string, "%i %i", x_pos[x], y_pos[x]);
fputs (temp_string ,f);
char end_string[2] = { 0x0D, 0x0A};
fputs (end_string ,f);
}
fclose(f);
}
}

The example can be found inside the iepro folder on skydrive, it is called modified_libfat_example.zip, if the screen is touched the txt file is renwed with new random data and it read back and printed on the screen.

The example has all methods in one file, it should be reworked with a nice setup using different header and source files.

http://cid-58814201e79976dd.skydrive.live.com/self.aspx/iepro/modified%5E_libfat%5E_example.zip


Mathematical scripts

26/12/2009

Sometimes you need a small algorithm for a game, for instance a test if a point is inside or outside a triangle defined by three other points.

You can make and test your own solution which will certainly be very instructive, but other very dedicated people have come up with clever solutions and these are very tested!

a good link is: http://www.gmlscripts.com/

for instance, for the problem mentioned above you type triangle in the search field and it comes up with the solution in a readable format:

http://www.gmlscripts.com/script/point_in_triangle

it is easily translated in c for our nds purposes!


Logitech webcam

26/12/2009

A strange thing I noticed:

working in Programmers NotePad:

the process of making was slow or even aborted.

Finally looking around on the internet I found out that my Logitech webcam was causing this!

Uninstalling the webcam software made my compiling fast again (reletively speaking) and without problems….


nds homebrew IDE’s

26/12/2009

There are two aspect to be careful about when programming for the nds:

c – feautures (or c++ feautures) like pointers, malloc and free

nds – features (including images, maxmod sounds etc)

To get acquainted with C and to be able to test your c structure we use DevCpp, which comes with it’s own template Makefile.

To do programming for the nds we use mainly Programmers NotePad, which ships with the DevKitPro. You can use the template nds makefile coming with the examples or the one used in the examples for this blog.

On MACOS we use Eclipse, setting this up must be documented in another blog.

But there are other IDE’s:

On I used once was C++ Visual Express:
page of devkitpro explaining how to set up:
http://www.devkitpro.org/index.php?s=cpp

experience with these IDE’s will be added later on.