Raycasting problems
aybabtu

I just read part of the "Sin & Cos: The Programmer's Pals!" tutorial by amarillion. I previously didn't know how to apply these functions to movement, but I do now!! (BTW: Great tutorial!!!)

Well, after experimenting with them and making a simple "game" to test them out, I've decided to do a raycasting engine. I just want it simple like Wolfenstein 3D's engine. I've got some code "working", but there's a problem with the displaying of the level, it's really blocky, and it doesn't look like walls or anything, just big straight blocks. Ther is some difference in heights and such, but I can't figure out where corners are and stuff. Like I said, I'm new to using angles and sin&cos and stuff like that in my programs, so maybe that's one of the problems, too. Here's the display/casting code:

1/* The view variable is declared like this:
2 * int view[85], and when the rays are casted, the distances are stored here.
3 * The following code is the cast function, the
4 * raycasting handler function and the drawing.
5 */
6 
7int cast_ray(int x,int y,float a)
8{
9 int distance=0;
10 int the_x=x;
11 int the_y=y;
12 while(level[the_y/TILE][the_x/TILE]!=1)
13 {
14 the_x+=(int)cos(a);
15 the_y+=(int)sin(a);
16 distance++;
17 }
18 return distance;
19}
20 
21void do_raycasting()
22{
23 float angle=pa-42;
24 for(int i=0;i<85;i++)
25 {
26 view<i>=cast_ray(px,py,angle);
27 angle++;
28 }
29}
30 
31void draw_view()
32{
33 int tall=0; //Height of a line (represents distance of ray
34 int distance_from_top=0; //So it's centered.
35 int color=255; //This is for depth shading (not implemented yet)
36 for(int i=0;i<85;i++)
37 {
38 //This area is to calculate how tall the line should be
39 //There's probly an error here...
40 if(view<i><200) //This is so it has a distance limit
41 {
42 tall=200-view<i>;
43 distance_from_top=(200-tall)/2;
44 //This draws the line, I don't think this is a problem
45 line(front,i,distance_from_top,i,distance_from_top+tall,makecol(color,color,color));
46 }
47 }
48}

If that's not enough to find the problem, here's the whole program's code:

1#include <allegro.h>
2 
3#define TILE 64
4 
5int level[5][5]={
6{1,1,1,1,1},
7{1,0,0,0,1},
8{1,0,0,0,1},
9{1,0,0,0,1},
10{1,1,1,1,1}};
11 
12int view[85];
13 
14int px=160;
15int py=160;
16int ps=5;
17float pa=64.0;
18 
19BITMAP*front;
20 
21int cast_ray(int x,int y,float a);
22void draw_view();
23void do_raycasting();
24 
25 
26int main()
27{
28 allegro_init();
29 install_keyboard();
30 set_color_depth(16);
31 set_gfx_mode(GFX_AUTODETECT,320,200,0,0);
32 front=create_bitmap(320,200);
33 while(!key[KEY_ESC])
34 {
35 clear(front);
36 do_raycasting();
37 draw_view();
38 if(key[KEY_LEFT]) pa-=1;
39 if(key[KEY_RIGHT]) pa+=1;
40 if(pa<0) pa+=255;
41 if(pa>255) pa-=255;
42 if(key[KEY_UP])
43 {
44 px+=(int)(ps*cos(pa));
45 py+=(int)(ps*sin(pa));
46 }
47 if(key[KEY_DOWN])
48 {
49 px-=(int)(ps*cos(pa));
50 py-=(int)(ps*sin(pa));
51 }
52 line(front,100,100,100+(25*cos(pa)),100+(25*sin(pa)),makecol(255,255,255));
53 vsync();
54 blit(front,screen,0,0,0,0,320,200);
55 }
56 destroy_bitmap(front);
57 return 0;
58}
59 
60int cast_ray(int x,int y,float a)
61{
62 int distance=0;
63 int the_x=x;
64 int the_y=y;
65 while(level[the_y/TILE][the_x/TILE]!=1)
66 {
67 the_x+=(int)cos(a);
68 the_y+=(int)sin(a);
69 distance++;
70 }
71 return distance;
72}
73 
74void do_raycasting()
75{
76 float angle=pa-42;
77 for(int i=0;i<85;i++)
78 {
79 view<i>=cast_ray(px,py,angle);
80 angle++;
81 }
82}
83 
84void draw_view()
85{
86 int tall=0;
87 int distance_from_top=0;
88 int color=255;
89 for(int i=0;i<85;i++)
90 {
91 if(view<i><200)
92 {
93 tall=200-view<i>;
94 distance_from_top=(200-tall)/2;
95 line(front,i,distance_from_top,i,distance_from_top+tall,makecol(color,color,color));
96 }
97 }
98}

I'm almost certain it's a problem with the display or the casting function, but I'm not sure.

Thomas Harte
Quote:

the_x+=(int)cos(a);

This is equivalent to:

if(a == M_PI) x--;
if(!a) x++;

i.e. cos(a) only varies from -1 to +1, so the (int) essentially throws all the information away.

aybabtu

So do I need to have the x&y floats or fixeds or doubles? As I said all the movement and angle code worked in my other "game" test. Well, why would it matter? You can't put a point at a non-integer coordinate anyway, so I don't need that extra information, right?

Goodbytes

Yes, you have to have the x&y float or fixed or double. Trust us, it matters. :D

Think about it. cos(a) and sin(a) are going to be the same thing every time you calculate them. So, if your x increment for a particular ray is either -1, 0, or 1 all the time, and your y increment is either -1, 0, or 1 all the time, any rays you cast will automagically be clamped to 45 degree increments, which is definitely not what you want.

P.S. You can precalculate the values of cos(a) and sin(a) instead of calling those functions repeatedly in your raycasting loop. It will make for a huge speed increase.

aybabtu

So instead of haveing it shoot a ray out at 1 degree increments, it shoots them out a t 45 degree increments? That explains the blockyness of the output. So, I need to have the_x & the_y be floats, to get an accurate reading, right?

Quote:

You can precalculate the values of cos(a) and sin(a) instead of calling those functions repeatedly in your raycasting loop. It will make for a huge speed increase.

I think I'll probly do this later, but for now, I'll just call it every time. I don't think its a big problem, cuz it runs fine on my old 586 computer. But, how is this done? I'm guessing just by filling something like float sin_table[85] or something, right? How much would I increment it for each part of the table? 1 or .1 or somthing?

float sin_table[85];
for(int i=0;i<85;i++)
{
 sin_table<i>=sin(i);
}

?

amarillion

the allegro functions fixsin and fixcos are already implemented using tables.

Trust me, don't worry about optimization too much at first. Just get it working first, optimize later.

ROSTheFuture

If you aren't getting any compile errors or runtime errors, i would say try a different, more complicated level. Probably whats happening is that the level is too simple, so naturally all you see is blocks. [edit] or not :P I really need to speed up my typing [/edit]

Also what you might want to do is modify your code a bit so that walls can be different colour so that you can differentiate them. All that would take to do that would be to make your level array with different values that one, then you would change your ray casting code, and add another array parallel to 'view' which contains colour information:

1...
2int level[5][5] =
3{{ makecol(255, 255, 0), makecol(255, 0, 255), /* ... etc */ }};
4 
5int view[85];
6int colinfo[85];
7 
8...
9 
10int cast_ray(int *x,int *y,float a)
11{ /* ^ ^ */
12 ...
13 while(level[the_y/TILE][the_x/TILE]==0)
14 { /* ^ */
15 ...
16 }
17 
18 *x = (the_x/TILE); /* <-- */
19 *y = (the_y/TILE);
20 return distance;
21}
22void do_raycasting()
23{
24 float angle=pa-42;
25 for(int i=0;i<85;i++)
26 {
27 tx = px; ty = py;
28 view<i>=cast_ray(tx,ty,angle);
29 colinfo<i> = level[tx][ty];
30 angle++;
31 }
32}
33 
34void draw_view()
35{
36 ...
37 for(int i=0;i<85;i++)
38 {
39 if(view<i><200)
40 {
41 ...
42 line(front,i,distance_from_top,i,distance_from_top+tall,colinfo<i>);
43 }
44 }
45}

just a suggestion. I don't know how far you intended to go with this.

aybabtu

Image...
Yay! ;D

As you can see, I've got it displaying right (changed the_x&y to floats), and it has a primitive form of depth shading! (The line in the middle is just to show the direction you're facing.) Also, you'll notice that it's got that nasty curved effect. How do I fix that?

amarillion

Well, it is because raycasting doesn't work the way you think it works. It's hard to explain but you are in the wrong line of thinking. Try to see if you can find other raycasting tutorials.

aybabtu

What's wrong with my line of thinking?

Well, I've read another nice tutorial, and it says to fix the fishbowl effect, multiply the distance by cos(BETA) and beta is -30 (since I'm using the 255 degree circle, -21) for the left-most ray, and 30 (21) for the rightmost ray. I've solved this by doing distance*=cos(0-a); and it works. But, the angle should be between -21 and 21, but in reality, it can be anywhere between two numbers that are 42 different. SO, the effect I get is that when you turn 90 degrees (64 allegro-degrees) you get an incorrect reading! I think I'm stuck...

Zaphos

aybabtu: Try changing 0 to the direction you're facing so that 0-a is between -21 and 21 regardless of how offset a is. e.g. if you turn 64 alleg-degs then you multiply distance by cos(64-a).

Anyway, you should really try to get a grasp of the trig underlying what you're doing ...

I think this calls for some smiling art:
:-X:-X:-X:-X:-*:(
:-X:-X:-X:-*:-X:(
:-X:-X:-*:-X:-X:(
:-X:-*:-X:-X:-X:(
;D8-)8-)8-)8-):(

:-X == Whitespace
:-* == Distance you calculate
8-) == Distance you should calculate, also your line of sight
;D == You
:( == Wall

The size of each bit of wall you draw is determined by the distance parallel to your line of sight that you'd need to walk to get to that wall -- perpendicular distance should not "shrink" the wall. How do we find that parallel distance? Well, if we look at the diagram above as a right-triangle, we see that we already have the length of the hypotenuse and the angle, and we can apply simple trig to find that that parallel distance is hypot*cos(angle) ... exactly the formula you're using.

Niunio

Here you have a raycast tutorial. It explains what's happening with that nasty curved effect and how to prevent it.

Let me know when you release this project, please;).

amarillion

You see? That other tutorial is much better. You see, mine is not really intended as a raycasting tutorial, just a trig primer.

aybabtu

amarillion: Yeah, I know. I've learned a little trigonometry in my geometry class at school, but we never learned really how to apply it to a computer game :P! But, even though your tutorial is not for raycasting in particular, it was what I was missing to at least get started. After all, at least it's farther than I've ever gotten before.

Niuino: Yeah! That tutorial's great, it's the same one you linked to in my other raycasting thread. I'm trying to use that method, but it's not working very well. I've gotten rid of some of the fishbowl, but in some parts, it's actually reversed! Like, I'll look at a flat wall, and it will have slight curvature to it, but instead of the middle being larger, the ends are. Here's the code I'm using to "fix" the distance problem:

void do_raycasting()
{
 float angle=pa-21;
 for(int i=0;i<42;i++)
 {
  view<i>=cos(i-21)*cast_ray(px,py,angle);
  angle++;
 }
}

This is what the tutorial says to do, right?

The Tutorial said:

Thus to remove the viewing distortion, the resulting distance obtained from equations in Figure 17 must be multiplied by cos(BETA); where BETA is the angle of the ray that is being cast relative to the viewing angle. On the figure above, the viewing angle (ALPHA) is 90 degrees because the player is facing straight upward. Because we have 60 degrees field of view, BETA is 30 degrees for the leftmost ray and it is -30 degrees for the rightmost ray.
correct_distance=distorted_distance*cos(BETA);

Of course, I changed 30 degrees into it's equivalent (about 21) in allegro degrees.
Maybe I'm doing the formula wrong, but it seems it should work, I've even got it in the do_raycasting function, where the anlge measures are between -21 & 21.

Quote:

Let me know when you release this project, please.

Hmmm...I don't know even what I'm going to do with it yet! Probly a shooter like Wolfenstein, but between then and now, I've gotta get it working right! My next task is texture mapping. goes to the tutorial...

Niunio
   view<i> = cos (i-21) * cast_ray (px, py, angle);

That cos function, doesn't it get the angle in radians? But you're using binary angles (0-255), don't you? Try with fixcos or fcos, and do not forget to translate it to fixed point.

Trezker

If you go to http://www.neozones.com and search a bit, you'll find some raycasting tutorials, they're in qbasic but I've made some advancements in c++.

I attach my work and the original tutorials.
Enjoy!

Zaphos

Well, given that the cos has worked as well as it has, I'd guess that aybabtu hasn't #included math.h and the allegro functions are stepping in automatically, so that isn't the problem. However it would be a good idea to follow Niunio's advice all the same so that the eventual possible #include math.h won't break all your math.

Anyway, the function looks right too me, so if Niunio isn't on to something then all I can guess is that there's something minorly wrong with "cast_ray()" ... perhaps the your steps are too big so the granularity is causing some small error in the drawing? How significant is the distortion?

aybabtu

Here's a pic with my crappy texture mapping and distortion correction working:
[url http://www.angelfire.com/empire/jonhome/WOLF.gif]Image...[/url]

As you can see, there's a few problems in the texture mapping, but it's ok for now. But, you'll notice the distortion in that cube.

Niuino: As Zaphos said, I don't have math.h included, so allegro's helping me out! I could change them to radians, but this works. Later when I get all the bugs worked out of it, I'll make all the code "the way it should be".;D

Trezker: Yeah! Even if they're in QBASIC, I know enough (not a lot still) to see how they work, and implement that code in C.

Zaphos: Um...as for the distortion...it sorta looks like a reverse-fishbowl effect. Instead of the distortion being on the sides, it's in the middle. And, I think I may know the reason...maybe. Maybe because 30 degrees isn't exactly equal to 21 allegro degrees, but 21.25 rather. So, the view is being cut off by half a degree, possibly screwing it up. Actually, it shouldn't do that kind of damage, just make the screen smaller...oh well.
Here's the code for the program...
I've got the ability to switch on and off the texture mapping and distortion correction, as well as a custom circle function for the "compass"! (The circle function isn't the best, it's not the one from the tutorial, but it works, and it's neat to see it...you know...whatever...::))

#SelectExpand
1#include <allegro.h> 2 3#define TILE 64 4 5int level[9][9]={ 6{1,1,1,1,1,1,1,1,1}, 7{1,0,0,0,0,0,0,0,1}, 8{1,0,1,0,1,0,1,0,1}, 9{1,0,0,0,0,0,0,0,1}, 10{1,0,1,0,1,0,1,0,1}, 11{1,0,0,0,0,0,0,0,1}, 12{1,0,1,0,1,0,1,0,1}, 13{1,0,0,0,0,0,0,0,1}, 14{1,1,1,1,1,1,1,1,1}}; 15 16int view[42]; 17int texture_map[42]; 18 19int px=65; 20int py=65; 21int p_old_x=65; 22int p_old_y=65; 23int ps=5; 24float pa=32.0; 25 26bool fishbowl=false; 27bool textures_off=false; 28 29BITMAP*front; 30BITMAP*backdrop; 31BITMAP*texture; 32 33float cast_ray(int x,int y,float a); 34void draw_view(); 35void do_raycasting(); 36bool collisions(); 37void my_draw_circle(BITMAP*b,int x,int y,int radius,int color); 38 39int main() 40{ 41 allegro_init(); 42 install_keyboard(); 43 set_color_depth(24); 44 set_gfx_mode(GFX_AUTODETECT,320,200,0,0); 45 front=create_bitmap(320,200); 46 backdrop=create_bitmap(320,200); 47 for(int i=0;i<100;i++) hline(backdrop,0,i,320,makecol(200,200,255-i)); 48 rectfill(backdrop,0,100,320,200,makecol(0,100,0)); 49 text_mode(-1); 50 texture=load_bitmap("texture.bmp",NULL); 51 while(!key[KEY_ESC]) 52 { 53 clear(front); 54 blit(backdrop,front,0,0,0,0,320,200); 55 do_raycasting(); 56 draw_view(); 57 if(key[KEY_F]) fishbowl=true; 58 if(key[KEY_G]) fishbowl=false; 59 if(key[KEY_T]) textures_off=false; 60 if(key[KEY_R]) textures_off=true; 61 if(key[KEY_LEFT]) pa-=2; 62 if(key[KEY_RIGHT]) pa+=2; 63 if(key[KEY_UP]) 64 { 65 px+=(int)(ps*cos(pa)); 66 py+=(int)(ps*sin(pa)); 67 } 68 if(key[KEY_DOWN]) 69 { 70 px-=(int)(ps*cos(pa)); 71 py-=(int)(ps*sin(pa)); 72 } 73 if(collisions()==true) 74 { 75 px=p_old_x; 76 py=p_old_y; 77 } 78 else 79 { 80 p_old_x=px; 81 p_old_y=py; 82 } 83 if(pa<0) pa+=255; 84 if(pa>255) pa-=255; 85 line(front,160,100,160+(25*cos(pa)),100+(25*sin(pa)),makecol(0,0,255)); 86 line(front,160,100,160+(25*cos(pa-21)),100+(25*sin(pa-21)),makecol(255,255,0)); 87 line(front,160,100,160+(25*cos(pa+21)),100+(25*sin(pa+21)),makecol(255,255,0)); 88 my_draw_circle(front,160,100,25,makecol(255,0,0)); 89 textout_centre(front,font,"N",160,65,makecol(0,0,255)); 90 vsync(); 91 blit(front,screen,0,0,0,0,320,200); 92 if(key[KEY_S]) save_bitmap("wolf.pcx",front,NULL); 93 } 94 destroy_bitmap(front); 95 return 0; 96} 97 98int map_texture(int x,int y,float a) 99{ 100 float the_x=x; 101 float the_y=y; 102 bool ended_on_y=false; 103 while(level[(int)the_y/TILE][(int)the_x/TILE]==0) 104 { 105 the_x+=(float)cos(a); 106 if(level[(int)the_y/TILE][(int)the_x/TILE]!=0) 107 { 108 ended_on_y=true; 109 break; 110 } 111 the_y+=(float)sin(a); 112 if(level[(int)the_y/TILE][(int)the_x/TILE]!=0) 113 { 114 ended_on_y=false; 115 break; 116 } 117 } 118 if(ended_on_y==true) return (int)((int)the_y%TILE); 119 if(ended_on_y==false) return (int)((int)the_x%TILE); 120} 121 122float cast_ray(int x,int y,float a) 123{ 124 float distance=0; 125 float the_x=x; 126 float the_y=y; 127 while(level[(int)the_y/TILE][(int)the_x/TILE]==0) 128 { 129 the_x+=(float)cos(a); 130 the_y+=(float)sin(a); 131 distance++; 132 } 133 return distance; 134} 135 136void do_raycasting() 137{ 138 float angle=pa-21; 139 for(int i=0;i<42;i++) 140 { 141 if(fishbowl==false) view<i>=(int)(cos(i-21)*cast_ray(px,py,angle)); 142 if(fishbowl==true) view<i>=(int)cast_ray(px,py,angle); 143 texture_map<i>=map_texture(px,py,angle); 144 angle++; 145 } 146} 147 148void draw_view() 149{ 150 int tall=0; 151 int distance_from_top=0; 152 int color=255; 153 for(int i=0;i<42;i++) 154 { 155 if(view<i><200) 156 { 157 color=255-(view<i>); 158 tall=200-view<i>; 159 distance_from_top=(200-tall)/2; 160 if(textures_off==true) rectfill(front,(int)(i*(320/42.5))+1,distance_from_top,(int)(((320/42.5)*i)+(320/42.5)),distance_from_top+tall,makecol(color,color,color)); 161 if(textures_off==false) stretch_blit(texture,front,texture_map<i>,0,(int)(320/42.5),64,(int)(i*(320/42.5)),distance_from_top,((int)(320/42.5))+1,tall); 162 } 163 } 164} 165 166void my_draw_circle(BITMAP*b,int x,int y,int radius,int color) 167{ 168 float angle=0.0; 169 while(angle<255) 170 { 171 putpixel(b,x+(radius*cos(angle)),y+(radius*sin(angle)),color); 172 angle+=0.1; 173 } 174} 175 176bool collisions() 177{ 178 if(level[py/TILE][px/TILE]==0) return false; 179 else return true; 180}

(Note: if you want to compile this or anything, you need a 64x64 texture bitmap for the walls...duh!:P)

EDIT: In the files that Trezker attached, I found this:

#SelectExpand
1'----- CONSTRUCT THE VIEWFIX TABLE 2'----- NOTICE THAT z% GOES FROM -31 TO 32 BECAUSE OUR RAYCAST GOES FROM -31 TO 3'----- 32 4FOR z% = -31 TO 32 5 ViewFix(z%) = 1 / COS(z% * PI / 180) '----- HERE'S THE FORMULA FOR YOUR 6 '----- VIEWFIX TABLE 7NEXT z% 8 9//Later in the code... 10'***** This is where we cast out our ray. We add yy% by the rise, and xx% 11'***** by then run. But I subtract it so that angle 0 is infront of you. 12DO 13 'xx% = xx% - SinTable(a%) '----- IT USED TO BE 14 'yy% = yy% - CosTable(a%) '----- THIS, BUT 15 xx% = xx% - SinTable(a%) * ViewFix(z%) '----- NOW IT'S 16 yy% = yy% - CosTable(a%) * ViewFix(z%) '----- THIS, WE MULTIPLIED OUR STEP 17 '----- TABLES BY OUR VIEWFIX TABLE 18 '----- ACCORDING TO z%

So, I need to construct a table like ViewFix, then multiply the reading from cast_ray by that value that corresponds to the angle, right? Or is that exacly what I'm doing...?

Zaphos

I would actually suggest implementing the faster, more accurate method of detecting walls, explained on this page of Nuino's linked tutorial, as I think the distortion may be caused by your current distance calculations (which are only of mediocre accuracy ...)

aybabtu

Zaphos: Yup. I'm working on making it so that the do_raycasting fuction shoots out 320 rays, 1 for each pixel on the screen, which will eliminate all bugs in the texture mapping, and possibly fix some of the distortion. It shouldn't take too long...

BTW: That qbasic fix for the distortion didn't hardly help at all...:-/ just a little. Oh well...

Zaphos
Quote:

I'm working on making it so that the do_raycasting fuction shoots out 320 rays

I wasn't talking about that, but rather the way in which you calculate the distance, but then again for a large enough value of TILE using the method in that tutorial will probably be more of a speed boost than an accuracy one.

aybabtu

Perfect texture mapping, courtesy of 320 rays being cast:
[url http://www.angelfire.com/empire/jonhome/WOLF.gif]Image...[/url]

But, 320 rays is A LOT of math per frame!! If I hold down an arrow key, it's at least .75 seconds between frames/moves. How do I display the exact fps? I belive the floating point numbers are causing part of the slowdown (but fixed looks like it'd be too hard to convert to from it's current state...), but another problem is that it does a lot of math! That optimization that Zaphos showed me would be great, but I'm afraid I don't exactly understand it. I'll look at it some more, but any help would be greatly appreciated!

I modified the code a lot:

#SelectExpand
1#include <allegro.h> 2 3#define TILE 64 4 5int level[9][9]={ 6{1,1,1,1,1,1,1,1,1}, 7{1,0,0,0,0,0,0,0,1}, 8{1,0,1,0,1,0,1,0,1}, 9{1,0,0,0,0,0,0,0,1}, 10{1,0,1,0,1,0,1,0,1}, 11{1,0,0,0,0,0,0,0,1}, 12{1,0,1,0,1,0,1,0,1}, 13{1,0,0,0,0,0,0,0,1}, 14{1,1,1,1,1,1,1,1,1}}; 15 16int view[320]; 17int texture_map[320]; 18 19int px=65; 20int py=65; 21int p_old_x=65; 22int p_old_y=65; 23int ps=5; 24float pa=32.0; 25 26bool fishbowl=false; 27bool textures_off=false; 28 29BITMAP*front; 30BITMAP*backdrop; 31BITMAP*texture; 32 33float cast_ray(int x,int y,float a); 34void draw_view(); 35void do_raycasting(); 36bool collisions(); 37void my_draw_circle(BITMAP*b,int x,int y,int radius,int color); 38 39int main() 40{ 41 allegro_init(); 42 install_keyboard(); 43 set_color_depth(24); 44 set_gfx_mode(GFX_AUTODETECT,320,200,0,0); 45 front=create_bitmap(320,200); 46 backdrop=create_bitmap(320,200); 47 for(int i=0;i<100;i++) hline(backdrop,0,i,320,makecol(200,200,255-i)); 48 rectfill(backdrop,0,100,320,200,makecol(0,100,0)); 49 text_mode(-1); 50 texture=load_bitmap("texture.bmp",NULL); 51 while(!key[KEY_ESC]) 52 { 53 clear(front); 54 blit(backdrop,front,0,0,0,0,320,200); 55 do_raycasting(); 56 draw_view(); 57 if(key[KEY_F]) fishbowl=true; 58 if(key[KEY_G]) fishbowl=false; 59 if(key[KEY_T]) textures_off=false; 60 if(key[KEY_R]) textures_off=true; 61 if(key[KEY_A]) 62 { 63 px+=(int)(ps*cos(pa-64)); 64 py+=(int)(ps*sin(pa-64)); 65 } 66 if(key[KEY_D]) 67 { 68 px-=(int)(ps*cos(pa-64)); 69 py-=(int)(ps*sin(pa-64)); 70 } 71 if(key[KEY_LEFT]) pa-=2; 72 if(key[KEY_RIGHT]) pa+=2; 73 if(key[KEY_UP]) 74 { 75 px+=(int)(ps*cos(pa)); 76 py+=(int)(ps*sin(pa)); 77 } 78 if(key[KEY_DOWN]) 79 { 80 px-=(int)(ps*cos(pa)); 81 py-=(int)(ps*sin(pa)); 82 } 83 if(collisions()==true) 84 { 85 px=p_old_x; 86 py=p_old_y; 87 } 88 else 89 { 90 p_old_x=px; 91 p_old_y=py; 92 } 93 if(pa<0) pa+=255; 94 if(pa>255) pa-=255; 95 line(front,160,100,160+(25*cos(pa)),100+(25*sin(pa)),makecol(0,0,255)); 96 line(front,160,100,160+(25*cos(pa-21)),100+(25*sin(pa-21)),makecol(255,255,0)); 97 line(front,160,100,160+(25*cos(pa+21)),100+(25*sin(pa+21)),makecol(255,255,0)); 98 my_draw_circle(front,160,100,25,makecol(255,0,0)); 99 textout_centre(front,font,"N",160,65,makecol(0,0,255)); 100 vsync(); 101 blit(front,screen,0,0,0,0,320,200); 102 if(key[KEY_S]) save_bitmap("wolf.pcx",front,NULL); 103 } 104 destroy_bitmap(front); 105 destroy_bitmap(texture); 106 destroy_bitmap(backdrop); 107 return 0; 108} 109 110int map_texture(int x,int y,float a) 111{ 112 float distance=0.0; 113 float the_x=x; 114 float the_y=y; 115 bool ended_on_y=false; 116 while(level[(int)the_y/TILE][(int)the_x/TILE]==0) 117 { 118 the_x+=(float)cos(a); 119 if(level[(int)the_y/TILE][(int)the_x/TILE]!=0) 120 { 121 ended_on_y=true; 122 break; 123 } 124 the_y+=(float)sin(a); 125 if(level[(int)the_y/TILE][(int)the_x/TILE]!=0) 126 { 127 ended_on_y=false; 128 break; 129 } 130 distance++; 131 } 132 if(ended_on_y==true) return (int)((int)the_y%TILE); 133 if(ended_on_y==false) return (int)((int)the_x%TILE); 134} 135 136float cast_ray(int x,int y,float a) 137{ 138 float distance=0.0; 139 float the_x=x; 140 float the_y=y; 141 while(level[(int)the_y/TILE][(int)the_x/TILE]==0) 142 { 143 the_x+=(float)cos(a); 144 the_y+=(float)sin(a); 145 distance++; 146 } 147 return distance; 148} 149 150void do_raycasting() 151{ 152 float angle=pa-21.25; 153 for(int i=0;i<320;i++) 154 { 155 if(fishbowl==false) view<i>=(int)(cos((i/7.529411765)-21.25)*cast_ray(px,py,angle)); 156 if(fishbowl==true) view<i>=(int)cast_ray(px,py,angle); 157 texture_map<i>=map_texture(px,py,angle); 158 angle+=0.13125; 159 } 160} 161 162void draw_view() 163{ 164 int tall=0; 165 int distance_from_top=0; 166 int color=255; 167 for(int i=0;i<320;i++) 168 { 169 if(view<i><200) 170 { 171 color=255-(view<i>); 172 tall=200-view<i>; 173 distance_from_top=(200-tall)/2; 174 if(textures_off==true) rectfill(front,i+1,distance_from_top,i+2,distance_from_top+tall,makecol(color,color,color)); 175 if(textures_off==false) stretch_blit(texture,front,texture_map<i>,0,1,64,i,distance_from_top,1,tall); 176 } 177 } 178} 179 180void my_draw_circle(BITMAP*b,int x,int y,int radius,int color) 181{ 182 float angle=0.0; 183 while(angle<255) 184 { 185 putpixel(b,x+(radius*cos(angle)),y+(radius*sin(angle)),color); 186 angle+=0.1; 187 } 188} 189 190bool collisions() 191{ 192 if(level[py/TILE][px/TILE]==0) return false; 193 else return true; 194}

Ack...::)

EDIT: I have a theory about the distortion. It's compensating too much. Like I said, before, the middle was bulged out. Now, the middle is right, but the sides are bulged. This would lead me to belive that it's compensating too much for the distortion! Maybe:

int distance=(int)cast_ray(px,py,angle);
int compensated=distance*cos((i/7.529411765)-21.25);
int nice_distance=(compensated+distance)/2;

I know, this would give me the average. But, from what it looks lke, this would produce straight walls! I dunno, I'll try it...probly won't be the solution, though. But, hey! Anything's worth a try!

23yrold3yrold

Heh; that distortion is funny :) I stole your code, so I figure I give you a hand. FPS is pretty low for me too; less than 10fps. I notice it gets pretty fast when a wall is right in your face though, so maybe your engine is wasting its time finding far walls? Comment your code some and maybe I could understand it ;)

I'm going to play with it some; I'm bored ...

EDIT: The tutorial Niunio linked to states (correctly) that you can speed up calculations using bitshifts. A quick Find reveals you aren't doing any bitshifting in your engine; only multiplication and division ... I just tried it, and not much difference ...

EDIT2: I found a major problem; in map_texture(), these two lines:

    the_x += (float)cos(a);
    ....
    the_y += (float)sin(a);

Do you have any clue how you're inching along there? Those are small values; try this instead:

    the_x += (float)cos(a) * 64;
    ....
    the_y += (float)sin(a) * 64;

Not sure how correct that is, but it's a nice healthy speed boost ...

EDIT3: Eek! cast_ray() is pretty bodgy; I gotta figure out how to rewrite that (see Niunio's link again).

aybabtu
Quote:

Do you have any clue how you're inching along there? Those are small values; try this instead:

Okay! ;D
But, most of the values that come out of cos(a) are close to -1 or 1 ! So, multiplying by 64, wouldn't that give it less accuracy. But, I guess less accuracy is better than my 1 fps. Wait...I just did some math...
cos(-30)*64 is about 55.425, so isn't that a LARGE step? My math could be wrong. Did you actually try that *64 thing? If so, how does it work out for you?

EDIT: Commented code for 23:

#SelectExpand
1#include <allegro.h> 2 3#define TILE 64 //Block (tile) width,height,depth 4 5int level[9][9]={ //A level 6{1,1,1,1,1,1,1,1,1}, //A 1 is a wall, 0 is floor 7{1,0,0,0,0,0,0,0,1}, 8{1,0,1,0,1,0,1,0,1}, 9{1,0,0,0,0,0,0,0,1}, 10{1,0,1,0,1,0,1,0,1}, 11{1,0,0,0,0,0,0,0,1}, 12{1,0,1,0,1,0,1,0,1}, 13{1,0,0,0,0,0,0,0,1}, 14{1,1,1,1,1,1,1,1,1}}; 15 16int view[320]; //The wall slice distances 17int texture_map[320]; //X offests for texture map 18 19int px=65; //Player x 20int py=65; //Player y 21int p_old_x=65; //Player's old x (collision detection) 22int p_old_y=65; //Old y 23int ps=5; //Speed 24float pa=32.0; //Angle 25 26bool fishbowl=false; //So I can switch on/off distortion correction 27bool textures_off=false; //Same, but for textures 28 29BITMAP*front; //The buffer that's blit to screen 30BITMAP*backdrop; //Background image (sky and grass) 31BITMAP*texture; //Wall texture (64x64) 32 33float cast_ray(int x,int y,float a); //Casts a ray at a given angle, then returns distance 34void draw_view(); //Draws the view to screen according to view[320] 35void do_raycasting(); //Handles the raycasting 36bool collisions(); //Handles collisions 37void my_draw_circle(BITMAP*b,int x,int y,int radius,int color); //I wanted to make my own circle drawing function!! 38 39int main() 40{ 41 allegro_init(); 42 install_keyboard(); 43 set_color_depth(24); 44 set_gfx_mode(GFX_AUTODETECT,320,200,0,0); 45 front=create_bitmap(320,200); 46 backdrop=create_bitmap(320,200); 47 //Next few lines draw backdrop 48 for(int i=0;i<100;i++) hline(backdrop,0,i,320,makecol(200,200,255-i)); 49 rectfill(backdrop,0,100,320,200,makecol(0,100,0)); 50 text_mode(-1); 51 //Loads texture.bmp 52 texture=load_bitmap("texture.bmp",NULL); 53 while(!key[KEY_ESC]) 54 { 55 clear(front); //Clear the buffer 56 blit(backdrop,front,0,0,0,0,320,200); //draw bg 57 do_raycasting(); //Cast the rays 58 draw_view(); //Draw the view of the level 59 if(key[KEY_F]) fishbowl=true; //Switch stuff on/off 60 if(key[KEY_G]) fishbowl=false; 61 if(key[KEY_T]) textures_off=false; 62 if(key[KEY_R]) textures_off=true; 63 //Next six keys are movement 64 if(key[KEY_A]) //Strafe left 65 { 66 px+=(int)(ps*cos(pa-64)); 67 py+=(int)(ps*sin(pa-64)); 68 } 69 if(key[KEY_D]) //Strafe right 70 { 71 px-=(int)(ps*cos(pa-64)); 72 py-=(int)(ps*sin(pa-64)); 73 } 74 if(key[KEY_LEFT]) pa-=2; //Turn left 75 if(key[KEY_RIGHT]) pa+=2; //Turn right 76 if(key[KEY_UP]) //Move foward 77 { 78 px+=(int)(ps*cos(pa)); 79 py+=(int)(ps*sin(pa)); 80 } 81 if(key[KEY_DOWN]) //Move backward 82 { 83 px-=(int)(ps*cos(pa)); 84 py-=(int)(ps*sin(pa)); 85 } 86 if(collisions()==true) //check for collisions 87 { 88 px=p_old_x; 89 py=p_old_y; 90 } 91 else 92 { 93 p_old_x=px; 94 p_old_y=py; 95 } 96 if(pa<0) pa+=255; //Keep pa between 0-255 97 if(pa>255) pa-=255; 98 //Next few lines draw that compass thing 99 //Blue line is your angle, yellow is your fov 100 line(front,160,100,160+(25*cos(pa)),100+(25*sin(pa)),makecol(0,0,255)); 101 line(front,160,100,160+(25*cos(pa-21)),100+(25*sin(pa-21)),makecol(255,255,0)); 102 line(front,160,100,160+(25*cos(pa+21)),100+(25*sin(pa+21)),makecol(255,255,0)); 103 my_draw_circle(front,160,100,25,makecol(255,0,0)); 104 textout_centre(front,font,"N",160,65,makecol(0,0,255)); 105 vsync(); //Duh... 106 blit(front,screen,0,0,0,0,320,200); //Draw buffer to screen 107 if(key[KEY_S]) save_bitmap ("wolf.pcx",front,NULL); //Save screenshots 108 } 109 destroy_bitmap(front); 110 destroy_bitmap(texture); 111 destroy_bitmap(backdrop); 112 return 0; 113} 114 115//Gets the X offset for the texture 116int map_texture(int x,int y,float a) 117{ 118 float distance=0.0; 119 float the_x=x; //X of the ray's position 120 float the_y=y; //Y of the ray's postition 121 bool ended_on_y=false; //Check that it ends on a horizontal face or a vertical face of a block 122 while(level[(int)the_y/TILE][(int)the_x/TILE]==0) //Keeps going until a wall 123 { 124 the_x+=(float)cos(a); //Increase x 125 if(level[(int)the_y/TILE][(int)the_x/TILE]!=0) //Check to see if this movement caused a collision 126 { 127 ended_on_y=true; //If it did, it ended on a vertical face 128 break; // End the loop 129 } 130 the_y+=(float)sin(a); //If it's still going, increase y 131 if(level[(int)the_y/TILE][(int)the_x/TILE]!=0) //Once again, check collisions 132 { 133 ended_on_y=false; 134 break; 135 } 136 distance++; //Not used yet, but will be so if a ray doesn't hit a wall, it'll stop still 137 } 138 if(ended_on_y==true) return (int)((int)the_y%TILE); //The equation for finding the offset is different for a vertical face than a horizontal 139 if(ended_on_y==false) return (int)((int)the_x%TILE); 140} 141 142//Casts the ray, and returns the distance 143float cast_ray(int x,int y,float a) 144{ 145 float distance=0.0; 146 float the_x=x; // Ray x 147 float the_y=y; // Ray y 148 while(level[(int)the_y/TILE][(int)the_x/TILE]==0) //Keep going until a wall 149 { 150 the_x+=(float)cos(a); //Increase x 151 the_y+=(float)sin(a); //Increase y 152 distance++; //Increase distance 153 } 154 return distance; 155} 156 157void do_raycasting() 158{ 159 float angle=pa-21.25; //Start at the equivalent of -30 degrees 160 for(int i=0;i<320;i++) //Fill the view[] 161 { 162 //For some reason, this distortion correction doesn't help much... 163 // i/7.5... gets the angle i should be 164 // -21.25 because it'll be between 0-42.5 165 if(fishbowl==false) view<i>=(int)(cos((i/7.529411765)-21.25)*cast_ray(px,py,angle)); 166 if(fishbowl==true) view<i>=(int)cast_ray(px,py,angle); 167 texture_map<i>=map_texture(px,py,angle); //Get texture 168 angle+=0.13125; //Add the angle by 42/360 169 } 170} 171 172//Draws the wall slices 173void draw_view() 174{ 175 int tall=0; //How tall a slice is 176 int distance_from_top=0; //For it to be centered 177 int color=255; //For depth shading (no textures) 178 for(int i=0;i<320;i++) 179 { 180 if(view<i><200) //I need to fix this so I can display walls that are farther away 181 { 182 color=255-(view<i>); //Gets the color 183 tall=200-view<i>; //Gets the height 184 distance_from_top=(200-tall)/2; //Centers it 185 //If textures are off, it just uses rectfill 186 //These drawing functions are easy enough to understand... 187 if(textures_off==true) rectfill (front,i+1,distance_from_top,i+2,distance_from_top+tall,makecol(color,color,color)); 188 if(textures_off==false) stretch_blit(texture,front,texture_map<i>,0,1,64,i,distance_from_top,1,tall); 189 } 190 } 191} 192 193//Custom circle drawing function 194//Note that this doesn't contribute to the slowdown.... 195void my_draw_circle(BITMAP*b,int x,int y,int radius,int color) 196{ 197 float angle=0.0; 198 while(angle<255) 199 { 200 putpixel(b,x+(radius*cos(angle)),y+(radius*sin(angle)),color); 201 angle+=0.1; 202 } 203} 204 205bool collisions() 206{ 207 if(level[py/TILE][px/TILE]==0) return false; 208 else return true; 209}

23yrold3yrold

It worked well, actually. But I've been working on a "proper" version using the math on that site (thread bump is t3h win, btw) and here's my best effort so far. In the plus column, it's blazingly fast; in the minus column I think I'm screwing up the math and I'm too stupid to figure out where :P It looks like a mess if you try it, but actually about half the walls are being drawn correctly and the other half aren't. The program also tends to crash on me if the angle I pass to tan() is undesirably too close to a multiple of 90 degrees, which has a bad hack to fix. Anyone want to give us some pointers here?

#SelectExpand
1 2#include <math.h> 3#include <allegro.h> 4 5#define TILE 64 6#define TILESHIFT 6 7#define SCREENWIDTH 320 8#define SCREENHEIGHT 200 9#define M_PI 3.1415926535897932 10 11int level[9][9]={ 12{1,1,1,1,1,1,1,1,1}, 13{1,0,0,0,0,0,0,0,1}, 14{1,0,1,0,1,0,1,0,1}, 15{1,0,0,0,0,0,0,0,1}, 16{1,0,1,0,1,0,1,0,1}, 17{1,0,0,0,0,0,0,0,1}, 18{1,0,1,0,1,0,1,0,1}, 19{1,0,0,0,0,0,0,0,1}, 20{1,1,1,1,1,1,1,1,1}}; 21 22int view[320]; 23int texture_map[320]; 24int px = 65; 25int py = 65; 26int p_old_x = 65; 27int p_old_y = 65; 28int ps = 5; // player speed 29float pa = 1; // player angle 30bool fishbowl = false; 31bool textures_off = false; 32 33BITMAP* front; 34BITMAP* backdrop; 35BITMAP* texture; 36 37// float cast_ray(int x, int y, float a); 38float CastRay(int xpos, int ypos, double angle, int& t); 39void draw_view(); 40void do_raycasting(); 41bool collisions(); 42void my_draw_circle(BITMAP *b, int x, int y, int radius, int color); 43 44int main() 45{ 46 allegro_init(); 47 install_keyboard(); 48 set_color_depth(16); 49 set_gfx_mode(GFX_AUTODETECT, SCREENWIDTH, SCREENHEIGHT, 0, 0); 50 text_mode(-1); 51 52 front = create_bitmap(SCREENWIDTH, SCREENHEIGHT); 53 backdrop = create_bitmap(SCREENWIDTH, SCREENHEIGHT); 54 55 for(int i = 0 ; i < 100 ; ++i) hline(backdrop, 0, i, 320, makecol(200, 200, 255 - i)); 56 rectfill(backdrop, 0, 100, SCREENWIDTH, SCREENHEIGHT, makecol(0,100,0)); 57 texture = load_bitmap("texture.bmp",NULL); 58 59 while(!key[KEY_ESC]) 60 { 61 clear(front); 62 blit(backdrop,front,0,0,0,0,SCREENWIDTH,SCREENHEIGHT); 63 do_raycasting(); 64 draw_view(); 65 66 if(key[KEY_T]) textures_off = false; 67 if(key[KEY_R]) textures_off = true; 68 if(key[KEY_A]) 69 { 70 px += (int)(ps * cos(pa - M_PI / 2)); 71 py += (int)(ps * sin(pa - M_PI / 2)); 72 } 73 if(key[KEY_D]) 74 { 75 px -= (int)(ps * cos(pa - M_PI / 2)); 76 py -= (int)(ps * sin(pa - M_PI / 2)); 77 } 78 if(key[KEY_LEFT]) pa -= 0.1; 79 if(key[KEY_RIGHT]) pa += 0.1; 80 if(key[KEY_UP]) 81 { 82 px+=(int)(ps * cos(pa)); 83 py+=(int)(ps * sin(pa)); 84 } 85 if(key[KEY_DOWN]) 86 { 87 px-=(int)(ps * cos(pa)); 88 py-=(int)(ps * sin(pa)); 89 } 90 if(collisions()==true) 91 { 92 px=p_old_x; 93 py=p_old_y; 94 } 95 else 96 { 97 p_old_x=px; 98 p_old_y=py; 99 } 100 101 if(pa < 0) pa += M_PI * 2; 102 if(pa > M_PI * 2) pa -= M_PI * 2; 103 104 105 // draw the little compass/circle 106 line(front,160,100,160+(25*cos(pa)),100+(25*sin(pa)),makecol(0,0,255)); 107 line(front,160,100,160+(25*cos(pa-0.523598)),100+(25*sin(pa-0.523598)),makecol(255,255,0)); 108 line(front,160,100,160+(25*cos(pa+0.523598)),100+(25*sin(pa+0.523598)),makecol(255,255,0)); 109 my_draw_circle(front,160,100,25,makecol(255,0,0)); 110 textout_centre(front,font,"N",160,65,makecol(0,0,255)); 111 112 113 vsync(); 114 blit(front,screen,0,0,0,0,SCREENWIDTH, SCREENHEIGHT); 115 if(key[KEY_S]) save_bitmap("wolf.pcx",front,NULL); 116 } 117 118 destroy_bitmap(front); 119 destroy_bitmap(texture); 120 destroy_bitmap(backdrop); 121 122 return 0; 123} 124END_OF_MAIN() 125 126// called once from int main() 127void do_raycasting() 128{ 129 double angle = pa - 0.523598; 130 131 for(int i = 0 ; i < SCREENWIDTH ; ++i) 132 { 133 // get the distance of the ray 134 view<i> = (int)(cos(angle - pa) * CastRay(px, py, angle, texture_map<i>)); 135 136 // increment the angle 137 angle += 1.04719 / SCREENWIDTH; 138 } 139} 140 141// called once from int main() 142void draw_view() 143{ 144 int tall = 0; 145 int distance_from_top = 0; 146 147 for(int i = 0 ; i < SCREENWIDTH ; ++i) 148 { 149 tall = (int)(64.0 / view<i> * 277.0); 150 distance_from_top = (SCREENHEIGHT - tall) / 2; 151 stretch_blit(texture, front, texture_map<i>, 0, 1, 64, i, distance_from_top, 1, tall); 152 } 153} 154 155// trivial function called once fron int main() 156void my_draw_circle(BITMAP*b,int x,int y,int radius,int color) 157{ 158 float angle = 0.0; 159 160 while(angle < 360) 161 { 162 putpixel(b, x + (radius * cos(angle)), y + (radius * sin(angle)), color); 163 angle += 0.1; 164 } 165} 166 167// called once from int main() 168bool collisions() 169{ 170 // return (bool)level[py/TILE][px/TILE]; 171 return (bool)level[px >> TILESHIFT][py >> TILESHIFT]; 172} 173 174float CastRay(int xpos, int ypos, double angle, int& t) { 175 // initialize (X_Ycheck, X_Xcheck) with first vertical wall and 176 // (Y_Ycheck, Y_Xcheck) with the first horizontal one 177 float X_Ycheck, X_Xcheck, Y_Ycheck, Y_Xcheck; 178 float X_Yinc, X_Xinc, Y_Yinc, Y_Xinc; 179 180 // hacka hacka hacka .... 181 double tangent = tan(angle); 182 if(tangent >= 0.0 && tangent < 0.1) tangent = 0.1; 183 if(tangent <= 0.0 && tangent > -0.1) tangent = -0.1; 184 if(tangent > 9999) tangent = 9999; 185 if(tangent < -9999) tangent = -9999; 186 187 // sin(90) == 1; sin(270) == -1 188 if(sin(angle) > 0) // The y-values are increasing 189 { 190 Y_Ycheck = (ypos / 64) * 64 - 1; 191 Y_Xcheck = xpos + (ypos - Y_Ycheck) / tangent; 192 Y_Xinc = 64 / tangent; 193 Y_Yinc = -64; 194 } else { // The y-values are decreasing 195 Y_Ycheck = (ypos / 64) * 64 + 64; 196 Y_Xcheck = xpos + (ypos - Y_Ycheck) / tangent; 197 Y_Xinc = 64 / tangent; 198 Y_Yinc = 64; 199 } 200 201 // okay, let's check for a wall 202 while(level[(int)Y_Xcheck >> TILESHIFT][(int)Y_Ycheck >> TILESHIFT] == 0) 203 { 204 Y_Xcheck += Y_Xinc; 205 Y_Ycheck += Y_Yinc; 206 } 207 208 // cos(0) == 1; cos(180) == -1 209 if(cos(angle) > 0) // The x-values are increasing 210 { 211 X_Xcheck = (xpos / 64) * 64 + 64; 212 X_Ycheck = ypos + (xpos - X_Xcheck) * tangent; 213 X_Xinc = 64; 214 X_Yinc = 64 * tangent; 215 } 216 else // The x-values are decreasing 217 { 218 X_Xcheck = (xpos / 64) * 64 - 1; 219 X_Ycheck = ypos + (xpos - X_Xcheck) * tangent; 220 X_Xinc = -64; 221 X_Yinc = 64 * tangent; 222 } 223 224 // okay, let's check for a wall 225 while(level[(int)X_Xcheck >> TILESHIFT][(int)X_Ycheck >> TILESHIFT] == 0) 226 { 227 X_Xcheck += X_Xinc; 228 X_Ycheck += X_Yinc; 229 } 230 231 float xcheck = (X_Xcheck - xpos) * (X_Xcheck - xpos) + (X_Ycheck - ypos) * (X_Ycheck - ypos); 232 float ycheck = (Y_Xcheck - xpos) * (Y_Xcheck - xpos) + (Y_Ycheck - ypos) * (Y_Ycheck - ypos); 233 234 if(xcheck < ycheck) 235 { 236 t = (int)X_Ycheck % TILE; 237 return sqrt(xcheck); 238 } 239 else 240 { 241 t = (int)Y_Xcheck % TILE; 242 return sqrt(ycheck); 243 } 244}

Yeah, I know, it sucks :P I'm getting the math for CastRay() from [url http://www.permadi.com/tutorial/raycast/rayc7.html]here[/url], btw ...

EDIT: Found a bug and fixed it above, but still needs work; sucker's gone back to crashing depending on location and angle >_< I'm done with it for now ...

aybabtu

I'll try to compile it today...
BTW: I editted in some commented code to that last post...

MindCode

I once wrote a raycasting engine (many a moon ago). I had the same speed problem. 23yrold is going in the right direction, take larger steps at first, until you know your going to hit something, then when collision has been verified, you can actually calculate the point of collision from there.

My method involved a tile based system. Each "tile" (or block) was fixed size (I used 128 which was also the texture width and height). I only stepped the tiles, so it went pretty fast. When the tile was hit I did a little extra trig to find out the horizontal (x) coord of the surface it hit which then went into texture mapping.

If you want your textures to look even better I would suggest using some kind of mip-mapping scheme. Since your already sampling the texture in a linear fashion (vertically) it would simply be a matter of summing non-visible texels around the visible one and taking an average.

Also I would suggest you switch to fixed point math. I'm not a big proprieter of fixed point since (in most cases) floating point is not as slow anymore, but converting floating point to integer is (on many cpu's). In the core of loop you are converting the step values to integers so that they can index the map array.

this:

x_tile = x_tile_step >> 16;
y_tile = z_tile_step >> 16;

if(map[x_tile][y_tile] == EMPTY)
/* do stuff */

is much better than this:

x_tile = (int) (x_trig_step / MAP_SIZE);
y_tile = (int) (y_trig_step / MAP_SIZE);

if(map[x_tile][y_tile] == EMPTY)
/* do stuff */

I wish I still had that source code for raycaster. It ran swift on my POS 100mhz laptop. And it was light too, only about 30 lines or so in the core loop.

23yrold3yrold

Thanks for the tip about fixed, MC, but I'll worry about just getting it working for the moment :)

Here's my latest attempt. It stopped crashing as soon as I added the fstream to log certian values; it's almost like it knows I'm watching it :P But it doesn't crash, and most of the walls work, but there's always the odd one sticking out. Plus the strafing and moving don't always go in the right direction. I still have no idea what I'm doing (other than waiting for a math guru to show up :P). I'm going back to my platformer ...

#SelectExpand
1#define __GTHREAD_HIDE_WIN32API 2 3#include <math.h> 4#include <fstream> 5#include <allegro.h> 6using namespace std; 7 8#define TILE 64 9#define TILESHIFT 6 10#define SCREENWIDTH 320 11#define SCREENHEIGHT 200 12#define M_PI 3.1415926535897932 13 14int level[9][9]={ 15{1,1,1,1,1,1,1,1,1}, 16{1,0,0,0,0,0,0,0,1}, 17{1,0,1,0,1,0,1,0,1}, 18{1,0,0,0,0,0,0,0,1}, 19{1,0,1,0,1,0,1,0,1}, 20{1,0,0,0,0,0,0,0,1}, 21{1,0,1,0,1,0,1,0,1}, 22{1,0,0,0,0,0,0,0,1}, 23{1,1,1,1,1,1,1,1,1}}; 24 25int view[320]; 26int texture_map[320]; 27int px = 65; 28int py = 65; 29int p_old_x = 65; 30int p_old_y = 65; 31int ps = 5; // player speed 32float pa = 1; // player angle 33 34BITMAP* front; 35BITMAP* backdrop; 36BITMAP* texture; 37 38// float cast_ray(int x, int y, float a); 39float CastRay(int xpos, int ypos, double angle, int& t); 40void draw_view(); 41void do_raycasting(); 42bool collisions(); 43void my_draw_circle(BITMAP *b, int x, int y, int radius, int color); 44 45int main() 46{ 47 allegro_init(); 48 install_keyboard(); 49 set_color_depth(16); 50 set_gfx_mode(GFX_AUTODETECT, SCREENWIDTH, SCREENHEIGHT, 0, 0); 51 text_mode(-1); 52 53 front = create_bitmap(SCREENWIDTH, SCREENHEIGHT); 54 backdrop = create_bitmap(SCREENWIDTH, SCREENHEIGHT); 55 56 for(int i = 0 ; i < 100 ; ++i) hline(backdrop, 0, i, 320, makecol(200, 200, 255 - i)); 57 rectfill(backdrop, 0, 100, SCREENWIDTH, SCREENHEIGHT, makecol(0,100,0)); 58 texture = load_bitmap("texture.bmp",NULL); 59 60 while(!key[KEY_ESC]) 61 { 62 clear(front); 63 blit(backdrop,front,0,0,0,0,SCREENWIDTH,SCREENHEIGHT); 64 do_raycasting(); 65 draw_view(); 66 67 if(key[KEY_A]) 68 { 69 px += (int)(ps * cos(pa - M_PI / 2)); 70 py += (int)(ps * sin(pa - M_PI / 2)); 71 } 72 if(key[KEY_D]) 73 { 74 px -= (int)(ps * cos(pa - M_PI / 2)); 75 py -= (int)(ps * sin(pa - M_PI / 2)); 76 } 77 if(key[KEY_LEFT]) pa -= 0.1; 78 if(key[KEY_RIGHT]) pa += 0.1; 79 if(key[KEY_UP]) 80 { 81 px += (int)(ps * cos(pa)); 82 py += (int)(ps * sin(pa)); 83 } 84 if(key[KEY_DOWN]) 85 { 86 px -= (int)(ps * cos(pa)); 87 py -= (int)(ps * sin(pa)); 88 } 89 if(collisions() == true) 90 { 91 px = p_old_x; 92 py = p_old_y; 93 } 94 else 95 { 96 p_old_x=px; 97 p_old_y=py; 98 } 99 100 if(pa < 0) pa += M_PI * 2; 101 if(pa > M_PI * 2) pa -= M_PI * 2; 102 103 104 // draw the little compass/circle 105 line(front,160,100,160+(25*cos(pa)),100+(25*sin(pa)),makecol(0,0,255)); 106 line(front,160,100,160+(25*cos(pa-0.523598)),100+(25*sin(pa-0.523598)),makecol(255,255,0)); 107 line(front,160,100,160+(25*cos(pa+0.523598)),100+(25*sin(pa+0.523598)),makecol(255,255,0)); 108 my_draw_circle(front,160,100,25,makecol(255,0,0)); 109 textout_centre(front,font,"N",160,65,makecol(0,0,255)); 110 111 textprintf(front, font, 15, 5, makecol(0,0,255), "%f (tan = %f", pa, tan(pa)); 112 113 vsync(); 114 blit(front,screen,0,0,0,0,SCREENWIDTH, SCREENHEIGHT); 115 // if(key[KEY_S]) save_bitmap("wolf.pcx",front,NULL); 116 } 117 118 destroy_bitmap(front); 119 destroy_bitmap(texture); 120 destroy_bitmap(backdrop); 121 122 return 0; 123} 124END_OF_MAIN() 125 126// called once from int main() 127void do_raycasting() 128{ 129 double angle = pa - 0.523598; 130 131 ofstream ofile("anglelog.txt"); 132 133 for(int i = 0 ; i < SCREENWIDTH ; ++i) 134 { 135 ofile << angle << ", " << tan(angle) << endl; 136 137 // get the distance of the ray 138 view<i> = (int)(cos(angle - pa) * CastRay(px, py, angle, texture_map<i>)); 139 140 // increment the angle 141 angle += 1.04719 / SCREENWIDTH; 142 } 143} 144 145// called once from int main() 146void draw_view() 147{ 148 int tall = 0; 149 int distance_from_top = 0; 150 151 for(int i = 0 ; i < SCREENWIDTH ; ++i) 152 { 153 tall = (int)(64.0 / view<i> * 277.0); 154 distance_from_top = (SCREENHEIGHT - tall) / 2; 155 stretch_blit(texture, front, texture_map<i>, 0, 1, 64, i, distance_from_top, 1, tall); 156 } 157} 158 159// trivial function called once fron int main() 160void my_draw_circle(BITMAP*b,int x,int y,int radius,int color) 161{ 162 float angle = 0.0; 163 164 while(angle < 360) 165 { 166 putpixel(b, x + (radius * cos(angle)), y + (radius * sin(angle)), color); 167 angle += 0.1; 168 } 169} 170 171// called once from int main() 172bool collisions() 173{ 174 return (bool)level[px >> TILESHIFT][py >> TILESHIFT]; 175} 176 177float CastRay(int xpos, int ypos, double angle, int& t) { 178 // initialize (X_Ycheck, X_Xcheck) with first vertical wall and 179 // (Y_Ycheck, Y_Xcheck) with the first horizontal one 180 float X_Ycheck, X_Xcheck, Y_Ycheck, Y_Xcheck; 181 float X_Yinc, X_Xinc, Y_Yinc, Y_Xinc; 182 183 // ofstream ofile("anglelog.txt"); 184 185 // hacka hacka hacka .... 186 double tangent = tan(angle); 187 if(tangent >= 0.0 && tangent < 0.1) tangent = 0.1; 188 if(tangent <= 0.0 && tangent > -0.1) tangent = -0.1; 189 if(tangent > 9999) tangent = 9999; 190 if(tangent < -9999) tangent = -9999; 191 192 // ofile << angle << ", " << tangent << endl; 193 194 // sin(90) == 1; sin(270) == -1 195 if(sin(angle) > 0) // The y-values are increasing 196 { 197 Y_Ycheck = (ypos / 64) * 64 + 64; 198 Y_Xcheck = xpos + (Y_Ycheck - ypos) / tangent; 199 Y_Xinc = 64 / tangent; 200 Y_Yinc = 64; 201 } else { // The y-values are decreasing 202 Y_Ycheck = (ypos / 64) * 64 - 1; 203 Y_Xcheck = xpos + (Y_Ycheck - ypos) / tangent; 204 Y_Xinc = 64 / tangent; 205 Y_Yinc = -64; 206 } 207 208 // okay, let's check for a wall 209 while(level[(int)Y_Xcheck >> TILESHIFT][(int)Y_Ycheck >> TILESHIFT] == 0) 210 { 211 Y_Xcheck += Y_Xinc; 212 Y_Ycheck += Y_Yinc; 213 } 214 215 // cos(0) == 1; cos(180) == -1 216 if(cos(angle) > 0) // The x-values are increasing 217 { 218 X_Xcheck = (xpos / 64) * 64 + 64; 219 X_Ycheck = ypos + (X_Xcheck - xpos) * tangent; 220 X_Xinc = 64; 221 X_Yinc = 64 * tangent; 222 } 223 else // The x-values are decreasing 224 { 225 X_Xcheck = (xpos / 64) * 64 - 1; 226 X_Ycheck = ypos + (X_Xcheck - xpos) * tangent; 227 X_Xinc = -64; 228 X_Yinc = 64 * tangent; 229 } 230 231 // okay, let's check for a wall 232 while(level[(int)X_Xcheck >> TILESHIFT][(int)X_Ycheck >> TILESHIFT] == 0) 233 { 234 X_Xcheck += X_Xinc; 235 X_Ycheck += X_Yinc; 236 } 237 238 float xcheck = (X_Xcheck - xpos) * (X_Xcheck - xpos) + (X_Ycheck - ypos) * (X_Ycheck - ypos); 239 float ycheck = (Y_Xcheck - xpos) * (Y_Xcheck - xpos) + (Y_Ycheck - ypos) * (Y_Ycheck - ypos); 240 241 if(xcheck < ycheck) 242 { 243 t = (int)X_Ycheck % TILE; 244 return sqrt(xcheck); 245 } 246 else 247 { 248 t = (int)Y_Xcheck % TILE; 249 return sqrt(ycheck); 250 } 251}

EDIT: Wow :o I thought I was doing pretty well until I started wandering around the map. Depending on the angle and how you move, it either works really well or absolutely horrid ;D

aybabtu

Well, I sped it up a lot by merging the cast_ray() and map_texture() functions into one, inside the for() loop in do_raycasting. This give a substantial speed increase, but it's still very slow (about 2 frames per second). I still don't have the distortion fixed. Maybe I should rewrite it...I only have about 100 lines of code, it shouldn't be too hard to fix it up, though...

23yrold3yrold

Did you try mine? It's still buggy, but I think my method is more on the right track than yours.

Now where's that math pro ...

aybabtu
Quote:

Did you try mine? It's still buggy, but I think my method is more on the right track than yours.

I just saved it to a disk so I can take it to my room and compile it. I'm sure yours is better than mine, as your A) More experienced than me...and B) Used that tutorial more (I've only used it so far to do texture mapping and "fix" the distortion). ;D

Quote:

Now where's that math pro ...

We need to lure some of those people from "What is 0?" thread...:P

23yrold3yrold

I've never done a raycaster and I only just read the tutorial. You're doing something totally different :)

aybabtu

Well...help me fix it! This: "You're just doing something totally different " doesn't really help me, does it!? Whatever...I'm not a very "mathy" person. If I was, I bet I could fix this up very nicely. But, I'm not, so this is what I come up with...

I'm going to change most of the floats in cast_ray to fixed point. Also, contributing to my problem is the fact that I do 320 stretch blits every frame. The drawing alone is probly enough to slow it down substantially.

Wait! I think I see an advantage to yours right now! Your finding the X_inc and Y_inc once every ray, that way there isn't so much math being done!! Yay! I think that makes much more sense! Happy day!8-)

23yrold3yrold
Quote:

Well...help me fix it!

Help me fix mine and I'll help you fix yours 8-)

Kitty Cat

aybabtu: your code won't compile here.. I keep getting the error "conversion from `float' to non-scalar type `fix' requested" over and over again.

Ace

There's a raycasting section in "Tricks of the Game Programming Gurus" by Andre LaMothe, if any of you have it or can get it. If either of you can't get access to it, I can type of the code for the examples and post it here (I have no clue where my cd is, grrrrr).

I think I'm going to join in on the action and do a small raycasting game for the upcoming RPGDX como. ;)

- Ace

23yrold3yrold

If you (or anyone) could post a small example, that would be dandy. If it's any easier, you could just point out the error in my code, since it's pretty close to the desired effect ...

Ace

Eeek, well I'm not really sure how they work. I'll try to get the example's code typed up. It may help you out some and maybe I can figure it out as I type it up. ;)

- Ace

23yrold3yrold
aybabtu

Yay! I have no more speed problems!! I changed my raycasting code so that it doesn't redo the math to move the ray every loop. I get at least 5-10 fps, which is a great improvement. I know it's not good, but it's a lot better. Help: How do I get/display the fps?

Kitty Cat: Sorry...I don't know how to fix that...possibly because of the lines that say (float)cos(angle); My code isn't exactly "right". ;D

Ace said:

I think I'm going to join in on the action and do a small raycasting game for the upcoming RPGDX como.

What's the "RPGDX com[p]o?" RPG competition?

23: Those sites are good. I remember t3h second one from when I was just starting out programming in QBASIC (they were way over my head:P).

Ace

Heh. Como. I've been The King of Typos lately. Blech. The RPGDX comPo is a weekend competition coming up on the weekend of the 28th. You have the weekend to design an RPG. You can use preexisting code, but everything else has to be done during the weekend.

Check out RPGDX for more information.

- Ace

23yrold3yrold
Quote:

How do I get/display the fps?

Have a variable that counts the number of screen redraws (just increment the variable everytime you blit the buffer to the screen). Declare an int fps variable which will hold the fps. Finally, have a timer variable increment every second.

Now, display fps onscreen. Whenever the second timer increments, assign the variable counting screen redraws to fps, and reset it. So you have a timer counting the seconds, a variable counting the frames drawn, and a variable to assign the fps so you can display it onscreen. Geddit?

aybabtu
Quote:

Geddit?

Yup! That's simple.

Ace: How are you going to use raycasting in your RPG? Are you going to make one of those "3D" dungeon things? Although, yours wouldn't be as fake as those, because they just use predrawn images.::)

EDIT:
Ace: That's a cool site! (RPGDX):D

Carrus85

The only thing I can think of to increase the speed of the program is to use a lookup table (which I think has been already suggested earlier)

Although, if you just do this once, it shouldn't be to hard...

Some other possiblities of things that you could do to increase speed is... lets see...

You could eliminate the floats/doubles. I'm pretty sure that if you used FIXED point stuff it would run faster (just because of some of the CPU opimizations behind it).

You might even be able to just get a fixed accuracy or something by eliminating the decimal part of the return value. I mean, when you get right down to it, I don't think you are really going to need much beyond the thousands decimal place, maybe even the hundreths...

You could also implement some max viewing distance (as suggested in the tutorail) just to prevent excessive calculation.

aybabtu

<u><b>*NO DISTORTION*</u></b>:D8-);D:-*:o:):P;)

Image...

It was my displaying!!!!! I changed mine to 23's way to get the "tall" variable, and it works great!

BTW: 23, I ran your program, and I see what you're talking about. It looks nice, but I couldn't figure out what's causing that bug. Does it do the same thing without texture mapping? Hmm...I'm not very experienced, so I'm not the one to go to.

23yrold3yrold
Quote:

It was my displaying!!!!! I changed mine to 23's way to get the "tall" variable, and it works great!

I got the math for that from that one site up there, btw :) You should have had that a long time ago ;)

Yeah, it's the same without texture maps, since it's the walls that move, not the textures. I'll probably hack at it for fun tonight, maybe look at that Java engine (how hard could it be to understand? ;)) and see where I get. Still wouldn't mind a math guru saving me some time though (wink, wink).

aybabtu
Quote:

I got the math for that from that one site up there, btw You should have had that a long time ago

Why didn't you guys point it out sooner? Too obvious? Well, the important thing is that I can move on now ;D.

Quote:

maybe look at that Java engine (how hard could it be to understand?

It seems it could be almost directly ported to C. Just change some of the function declarations and such (like remove the "public" from them).

Quote:

Still wouldn't mind a math guru saving me some time though (wink, wink).

Ya'd think that the title "Raycasting problems" would just scream "MATH GURUS!! GET OVER HERE!!". Well, I guess it depends on if they know what raycasting is.
What exactly have you tried when trying to make it work? Not that I can probly help, but there's always a chance...::):P

Carrus said:

The only thing I can think of to increase the speed of the program is to use a lookup table (which I think has been already suggested earlier)

I'm going to do that. I've found (with the help of 23) that the cos() and sin() functions take up a lot of time. And, every time I draw a line, I'm using a cos() function to fix the distortion. I'm going to use that ViewFix table thing for the distances. I don't really know how, though...:-/mostly because the distortion correction uses player_angle (PA) to do it's thing...

23yrold3yrold

Well the cos() and sin() in my CastRay() function can be removed completely in favour of just checking if the angle is in a certian range. The Java code is a bit tricky for me to understand, but the render() function seems to be doing things not quite in line with the article linking to it, so it's still confusing me. And some of the more useful engines on that big list are broken links. I made a fresh post on GameDev; hopefully I'll get a bite quickly.

And your function went slowly not just because you were using sin() and cos(), but because you were adding infintesimal values. You could just precalculate those values outside the loop, you know ;)

aybabtu
Quote:

And your function went slowly not just because you were using sin() and cos(), but because you were adding infintesimal values. You could just precalculate those values outside the loop, you know

Did I fix it?

23yrold3yrold

As of the last bit of code you posted ... no.

If you're ever calling cos(angle) in a loop when angle never changes, you should just precalculate cos(angle) and use that instead.

aybabtu
Quote:

As of the last bit of code you posted ... no.

Oh. That's not the latest code. I changed it so I have an X_Inc and Y_Inc variable like you do, which is calculated before it enters the actual casting loop. the_x and the_y are just incremented by that.

MindCode

I've tried looking for my old DOS raycaster, but I think it got junked on one of my many memory purges. I've tried to recreate some of the source code too but, needles to say, I don't have such a great memory. It looks more like a scaled down version of what you guys already did.

1#define SCREEN_W (320)
2#define SCREEN_H (240)
3#define FOV (64)
4#define FOV_DIV2 (FOV/2)
5#define FOV_INCR ((FOV/SCREEN_W) << FIX_SHIFT)
6#define FIX_SHIFT (16)
7#define EMPTY (0)
8 
9typedef signed long fixed;
10typedef unsigned char angle;
11 
12// I'll pretend these are filled already.
13 
14fixed fix_cos[256];
15fixed fix_sin[256];
16 
17int map_data[32][32];
18 
19// I'll also pretend that I change these with user input
20 
21fixed player_x_pos;
22fixed player_y_pos;
23angle player_dir;
24 
25 
26fixed x_pos = player_x_pos;
27fixed y_pos = player_y_pos;
28fixed ray = (player_dir - FOV_DIV2) << FIX_SHIFT;
29 
30// this will be the core renderer
31 
32for(int w = 0; w < SCREEN_W; w++)
33{
34 int distance = 0;
35 
36 ray += FOV_INCR;
37 
38 fixed x = x_pos;
39 fixed y = y_pos;
40 
41 while(map_data[x >> FIX_SHIFT][y >> FIX_SHIFT] == EMTPY)
42 {
43 x += fix_cos[ray];
44 y += fix_sin[ray];
45 distance++;
46 }
47 
48 // this fixes the "fisheye" effect
49 distance *= fix_cos[player_dir];
50 
51 // use your imagination with this function
52 verticle_line(w, distance);
53}

I think you guys inspired me enough to rewrite the whole thing. This means I'll have to install allegro again.

lambik

I was just curious so I compiled the code posted
aybabtu: don't forget END_OF_MAIN()
23yrold3yrold: your code crashes as soon as I try to move to the right. I can rotate left for a while but then it crashes too. Which would suggest there is value getting out of bounds somewhere.
Fun stuff, I'll look into it some more. I might just stumble over your bug..

Ace

aybabtu: Yeah, the player will be searching through a "dungeon." Though I'm not sure what they're going to be doing yet. I hope I'll be able to add enemies and such, but if I run out of time, I'll just make it so they have to find their way out of a maze. Mwahahahahhaaha.

- Ace

aybabtu
Quote:

aybabtu: don't forget END_OF_MAIN()

If I do, the program doesn't compile! I had to remove it from 23's go get it compile. Maybe it's a DJGPP thing.

I got the FPS of my engine (It needs lots of optimation!):
Standing: 4
Walking: 3
Close to a wall: 6

Need more speed!!

23yrold3yrold
Quote:

If I do, the program doesn't compile!

I had to add it to get to compile ...

Quote:

I had to remove it from 23's go get it compile. Maybe it's a DJGPP thing.

Oh right; you use DJGPP and Allegro -2.0 ;)

lambik: Yes, I know, it crashes and I hate it. My code logs values to a file and constrains the crap out of tan(angle) in CastRay() but I still can't see the problem :-/ I hate math, math is 3vil ...

EDIT: Aaaaaaaaand the GameDevers were useless ::) Yeah, like I'm getting lots of help here ;)

MindCode
Quote:

I hate math, math is 3vil ...

You kind of picked the wrong hobby eh?

aybabtu
Quote:

Oh right; you use DJGPP and Allegro -2.0

Yeah. ;D I'm suprised my version even has blit...:P::)

Carrus85

You know, if you really want to get highly optimized code, It might be worth it to look at the FAT (Fixed Angle Texturing) engine developed by Thomas Nussambamer of TICT.ticalc.org. It has to be quit optimized, right? I mean, if you are able to run a raycaster on a graphing calculator, you should be able to optimize it to run on a regular computer, right?

At least the source could provide some insights. It is extremely optimized though, using some 68k ASM. I can't help you in understanding it... I kinda suck at ASM...

Well, Give it a Try...

Here is a link to the supposed "FAT" rendering engine SDK... I'm not sure exactly what it contains... might contain useful source, might not. But somebody should at least take a look at it.

FAT engine SDK
TICT Web Site

Sure hope this helps... It might just complicate things, though...
::):-/

23yrold3yrold
Quote:

It might just complicate things, though...

That's almost guarenteed. What; no one has the answer? Spellcaster? Thomas Harte? Bob? Anyone? Is this thing on?

Carrus85

I'm dumb! 23...

Looking at the FAT engine code probably would only prove useful in the final optimization stages though. It is pretty amazing though, you can get fairly decent framerates on the TI-89. (Considering the TI-89 has approximately a 5mhz processor, and less then 1MB of RAM)

Thomas Harte

I have to admit, I haven't really grasped everything that's been said in this thread, because it is just so expansive, but here are a few things I expect to have come up:

- the Wolfenstein optimisation of using a tile based map is very important for speed purposes
- as is the decision to use a predetermined texturing density

And two things which I think may not have done:

- the Allegro software bitmap scaler is the worst possible choice for a ray casting engine
- a polygon filler for rectangles which form walls in the style of Wolfenstein or Doom may be written without any divides whatsoever. Doom uses one, and this is where even people who know the engine sometimes claim that Doom has a ray casting step (BIG HINT)

Given this second point, there are very many situations broadly in the style of a ray caster (i.e. same height walls, all perfectly vertical) where a 2 dimensional portal or BSP approach will be faster - but with the benefit of any angled walls. Especially if you have 100s of kbs for levels rather than 10s.

aybabtu

How much faster is fixed than float?

Thomas Harte
Quote:

How much faster is fixed than float?

On a 386 or 486SX, a fixed is several orders of magnitude faster than a float. On a 486DX a fixed is substantially faster than a float. On Pentiums, the fixed is certainly faster than the float for addition/subtraction, but they probably draw about equal for division/multiplication. Somewhere around Pentium 2/3s, fixeds become slower than floats for multiplication/division operations and the two become equal for addition/subtraction.

Naturally there are many situations for which one type or the other simply isn't suitable - in which case that type is much faster than the other.

aybabtu

I'm gonna change some/most of the math and stuff in the do_raycasting function to fixed. I've gotta get this thing going faster! :P

23yrold3yrold

Mine flies, but I still have the errors. C'mon, where's that math whiz ...

aybabtu

On my programming computer, 23, I'm sorry to say that yours isn't much faster than mine. It is, but not a whole lot. What's your FPS?
Is it just the casting of the rays? Whatever...

23yrold3yrold

Keep in mine my last posted code does constant file IO to log values 320 times a logic cycle. That slows it down a bloody lot. Take it out and it's lightning.

aybabtu

Oh. ::)
Mine's so slow, you can see the FPS counting up.
FPS: 0 ... FPS: 1 ... FPS: 2 ... FPS: 3 ... FPS: 0 ...
Blah.:P:-/::)

Ace

23yrold3yrold: I've noticed that the angle between the two crash points is about 180 degrees. I haven't had the chance to look at your code, but I do know that tangent is undefined when cosine is equal to 0. cosine is 0 at 90 degrees (PI/2 radians). That should have something to do with the crashing since cosine and sine are continuous.

I'll check your example out some more.

- Ace

23yrold3yrold

I've looked into that and it's not really crashing anymore; it may be the cause but I'm a little more interested in the graphical glitches.

EDIT: I fixed the major wall glitch with two negative signs; why exactly this worked I'm not sure :P There's still a minor glitch in the texture mapping though :-/ Newest code (minus the file IO) follows. Slows down when you get close to a wall, so it seems the drawing is the slowest part of the engine right now :)

#SelectExpand
1#include <math.h> 2#include <allegro.h> 3 4#define TILE 64 5#define TILESHIFT 6 6#define SCREENWIDTH 320 7#define SCREENHEIGHT 200 8#define M_PI 3.1415926535897932 9 10int level[9][9]={ 11{1,1,1,1,1,1,1,1,1}, 12{1,0,0,0,0,0,0,0,1}, 13{1,0,0,0,0,0,0,0,1}, 14{1,0,0,0,1,0,0,0,1}, 15{1,0,0,1,1,1,1,1,1}, 16{1,0,0,0,1,0,0,0,1}, 17{1,0,0,0,0,0,0,0,1}, 18{1,0,0,0,0,0,0,0,1}, 19{1,1,1,1,1,1,1,1,1}}; 20 21int view[320]; 22int texture_map[320]; 23int px = 65; 24int py = 65; 25int p_old_x = 65; 26int p_old_y = 65; 27int ps = 5; // player speed 28float pa = 1; // player angle 29 30BITMAP* front; 31BITMAP* backdrop; 32BITMAP* texture; 33 34float CastRay(int xpos, int ypos, double angle, int& t); 35void draw_view(); 36void do_raycasting(); 37bool collisions(); 38void my_draw_circle(BITMAP *b, int x, int y, int radius, int color); 39 40int main() 41{ 42 allegro_init(); 43 install_keyboard(); 44 set_color_depth(16); 45 set_gfx_mode(GFX_AUTODETECT, SCREENWIDTH, SCREENHEIGHT, 0, 0); 46 text_mode(-1); 47 48 front = create_bitmap(SCREENWIDTH, SCREENHEIGHT); 49 backdrop = create_bitmap(SCREENWIDTH, SCREENHEIGHT); 50 51 for(int i = 0 ; i < 100 ; ++i) hline(backdrop, 0, i, 320, makecol(200, 200, 255 - i)); 52 rectfill(backdrop, 0, 100, SCREENWIDTH, SCREENHEIGHT, makecol(0,100,0)); 53 texture = load_bitmap("texture.bmp",NULL); 54 55 while(!key[KEY_ESC]) 56 { 57 clear(front); 58 blit(backdrop,front,0,0,0,0,SCREENWIDTH,SCREENHEIGHT); 59 do_raycasting(); 60 draw_view(); 61 62 if(key[KEY_A]) 63 { 64 px += (int)(ps * cos(pa - M_PI / 2)); 65 py += (int)(ps * sin(pa - M_PI / 2)); 66 } 67 if(key[KEY_D]) 68 { 69 px -= (int)(ps * cos(pa - M_PI / 2)); 70 py -= (int)(ps * sin(pa - M_PI / 2)); 71 } 72 if(key[KEY_LEFT]) pa -= 0.1; 73 if(key[KEY_RIGHT]) pa += 0.1; 74 if(key[KEY_UP]) 75 { 76 px += (int)(ps * cos(pa)); 77 py += (int)(ps * sin(pa)); 78 } 79 if(key[KEY_DOWN]) 80 { 81 px -= (int)(ps * cos(pa)); 82 py -= (int)(ps * sin(pa)); 83 } 84 if(collisions() == true) 85 { 86 px = p_old_x; 87 py = p_old_y; 88 } 89 else 90 { 91 p_old_x=px; 92 p_old_y=py; 93 } 94 95 if(pa < 0) pa += M_PI * 2; 96 if(pa > M_PI * 2) pa -= M_PI * 2; 97 98 99 // draw the little compass/circle 100 line(front,160,100,160+(int)(25*cos(pa)),100+(int)(25*sin(pa)),makecol(0,0,255)); 101 line(front,160,100,160+(int)(25*cos(pa-0.523598)),100+(int)(25*sin(pa-0.523598)),makecol(255,255,0)); 102 line(front,160,100,160+(int)(25*cos(pa+0.523598)),100+(int)(25*sin(pa+0.523598)),makecol(255,255,0)); 103 my_draw_circle(front,160,100,25,makecol(255,0,0)); 104 textout_centre(front,font,"N",160,65,makecol(0,0,255)); 105 106 vsync(); 107 blit(front,screen,0,0,0,0,SCREENWIDTH, SCREENHEIGHT); 108 } 109 110 destroy_bitmap(front); 111 destroy_bitmap(texture); 112 destroy_bitmap(backdrop); 113 114 return 0; 115} 116END_OF_MAIN() 117 118// called once from int main() 119void do_raycasting() 120{ 121 double angle = pa - 0.523598; 122 123 for(int i = 0 ; i < SCREENWIDTH ; ++i) 124 { 125 // get the distance of the ray 126 view<i> = (int)(cos(angle - pa) * CastRay(px, py, angle, texture_map<i>)); 127 128 // increment the angle 129 angle += 1.04719 / SCREENWIDTH; 130 } 131} 132 133// called once from int main() 134void draw_view() 135{ 136 int tall = 0; 137 int distance_from_top = 0; 138 139 for(int i = 0 ; i < SCREENWIDTH ; ++i) 140 { 141 tall = (int)(64.0 / view<i> * 277.0); 142 distance_from_top = (SCREENHEIGHT - tall) / 2; 143 stretch_blit(texture, front, texture_map<i>, 0, 1, 64, i, distance_from_top, 1, tall); 144 } 145} 146 147// trivial function called once fron int main() 148void my_draw_circle(BITMAP*b,int x,int y,int radius,int color) 149{ 150 float angle = 0.0; 151 152 while(angle < 360) 153 { 154 putpixel(b, (int)(x + (radius * cos(angle))), (int)(y + (radius * sin(angle))), color); 155 angle += 0.1; 156 } 157} 158 159// called once from int main() 160bool collisions() 161{ 162 return (bool)level[px >> TILESHIFT][py >> TILESHIFT]; 163} 164 165float CastRay(int xpos, int ypos, double angle, int& t) { 166 // initialize (X_Ycheck, X_Xcheck) with first vertical wall and 167 // (Y_Ycheck, Y_Xcheck) with the first horizontal one 168 float X_Ycheck, X_Xcheck, Y_Ycheck, Y_Xcheck; 169 float X_Yinc, X_Xinc, Y_Yinc, Y_Xinc; 170 171 // hacka hacka hacka .... 172 if(angle < 0.01 && angle > 0) angle = 0.01; 173 if(angle < M_PI + 0.01 && angle > M_PI) angle = M_PI + 0.01; 174 if(angle < M_PI && angle > M_PI - 0.01) angle = M_PI - 0.01; 175 176 double tangent = tan(angle); 177 if(tangent >= 0.0 && tangent < 0.1) tangent = 0.1; 178 if(tangent <= 0.0 && tangent > -0.1) tangent = -0.1; 179 if(tangent > 9999) tangent = 9999; 180 if(tangent < -9999) tangent = -9999; 181 182 // sin(90) == 1; sin(270) == -1 183 if(sin(angle) > 0) // The y-values are increasing 184 { 185 Y_Ycheck = (ypos / 64) * 64 + 64; 186 Y_Xcheck = xpos + (Y_Ycheck - ypos) / tangent; 187 Y_Yinc = 64; 188 Y_Xinc = 64 / tangent; 189 190 while(level[(int)Y_Xcheck >> TILESHIFT][(int)Y_Ycheck >> TILESHIFT] == 0) 191 { 192 Y_Xcheck += Y_Xinc; 193 Y_Ycheck += Y_Yinc; 194 } 195 } else { // The y-values are decreasing 196 Y_Ycheck = (ypos / 64) * 64 - 1; 197 Y_Xcheck = xpos + (Y_Ycheck - ypos) / tangent; 198 Y_Yinc = -64; 199 Y_Xinc = -64 / tangent; 200 201 while(level[(int)Y_Xcheck >> TILESHIFT][(int)Y_Ycheck >> TILESHIFT] == 0) 202 { 203 Y_Xcheck += Y_Xinc; 204 Y_Ycheck += Y_Yinc; 205 } 206 } 207 208 // cos(0) == 1; cos(180) == -1 209 if(cos(angle) > 0) // The x-values are increasing 210 { 211 X_Xcheck = (xpos / 64) * 64 + 64; 212 X_Ycheck = ypos + (X_Xcheck - xpos) * tangent; 213 X_Xinc = 64; 214 X_Yinc = 64 * tangent; 215 216 while(level[(int)X_Xcheck >> TILESHIFT][(int)X_Ycheck >> TILESHIFT] == 0) 217 { 218 X_Xcheck += X_Xinc; 219 X_Ycheck += X_Yinc; 220 } 221 } 222 else // The x-values are decreasing 223 { 224 X_Xcheck = (xpos / 64) * 64 - 1; 225 X_Ycheck = ypos + (X_Xcheck - xpos) * tangent; 226 X_Xinc = -64; 227 X_Yinc = -64 * tangent; 228 229 while(level[(int)X_Xcheck >> TILESHIFT][(int)X_Ycheck >> TILESHIFT] == 0) 230 { 231 X_Xcheck += X_Xinc; 232 X_Ycheck += X_Yinc; 233 } 234 } 235 236 float xcheck = (X_Xcheck - xpos) * (X_Xcheck - xpos) + (X_Ycheck - ypos) * (X_Ycheck - ypos); 237 float ycheck = (Y_Xcheck - xpos) * (Y_Xcheck - xpos) + (Y_Ycheck - ypos) * (Y_Ycheck - ypos); 238 239 if(xcheck < ycheck) 240 { 241 t = (int)X_Ycheck % TILE; 242 return sqrt(xcheck); 243 } 244 else 245 { 246 t = (int)Y_Xcheck % TILE; 247 return sqrt(ycheck); 248 } 249}

Comments?

PS: I have the vague suspicion that my bodgy way of dealing with the crashing is causing the glitch, but I can't check it since whenever I remove those bits and try to look in the direction of the glitch it - you guessed it - crashes ::)

EDIT3: Okay, I think I've ironed out most of it, and I'm going to start a fresh thread so someone may actually notice, but I just realized something. Aybabtu, why did you write your my_draw_circle() function? It does exactly what Allegro's circle function does (only much slower)?

Johnny13

aybabtu: found it,u asked this kind of question lastyear!:P

23: it still crash(and its not valid C code,plenty of error!:P),
try modify this 2 lines:

while((int)X_Xcheck>>6<9&&(int)X_Ycheck>>6<9&&!level[(int)X_Xcheck>>6][(int)X_Ycheck>>6]) {X_Xcheck+=X_Xinc; X_Ycheck+=X_Yinc;}
while((int)X_Xcheck>>6<9&&(int)X_Ycheck>>6<9&&!level[(int)X_Xcheck>>6][(int)X_Ycheck>>6]) {X_Xcheck+=X_Xinc; X_Ycheck+=X_Yinc;}

shouldn't crash anymoreÂ…

23yrold3yrold

Yeah, I think I've already figured it all out (including that) but it still seems hackish. I wish I knew how to do it right. Oh well, it doesn't seem to be crashing anymore, at least.

Anyway, since J13 gave me a bump, here's my best shot now. It works, but my rounding of the tangent values makes some walls look choppy if you stand beside it and look down it. It's acceptable though. I'm getting 60 fps if my face is in a wall, and well over 100fps otherwise.

#SelectExpand
1#include <math.h> 2#include <allegro.h> 3 4#define TILE 64 5#define TILESHIFT 6 6#define SCREENWIDTH 320 7#define SCREENHEIGHT 200 8#define M_PI 3.1415926535897932 9 10int level[9][9]={ 11{1,1,1,1,1,1,1,1,1}, 12{1,0,0,0,0,0,0,0,1}, 13{1,0,0,0,0,0,0,0,1}, 14{1,0,0,0,0,0,0,1,1}, 15{1,0,0,1,1,1,1,1,1}, 16{1,0,0,0,1,0,0,0,1}, 17{1,0,0,0,0,0,0,0,1}, 18{1,1,0,0,0,0,0,0,1}, 19{1,1,1,1,1,1,1,1,1}}; 20 21int view[320]; 22int texture_map[320]; 23int px = 65; 24int py = 65; 25int p_old_x = 65; 26int p_old_y = 65; 27int ps = 3; // player speed 28float pa = 1; // player angle 29 30BITMAP* front; 31BITMAP* backdrop; 32BITMAP* texture; 33 34volatile int game_time = 0; 35volatile int fps_timer = 0; 36int fps = 0; 37int num_frames_drawn = 0; 38 39// Timer functions 40void Timer() { 41 ++game_time; 42}END_OF_FUNCTION(Timer); // end Timer() 43 44void FPSTimer() { 45 ++fps_timer; 46}END_OF_FUNCTION(FPSTimer); // end Timer() 47 48// float cast_ray(int x, int y, float a); 49float CastRay(int xpos, int ypos, double angle, int& t); 50void draw_view(); 51void do_raycasting(); 52bool collisions(); 53 54int main() 55{ 56 allegro_init(); 57 install_keyboard(); 58 set_color_depth(16); 59 set_gfx_mode(GFX_AUTODETECT, SCREENWIDTH, SCREENHEIGHT, 0, 0); 60 text_mode(-1); 61 62 LOCK_VARIABLE(game_time); 63 LOCK_VARIABLE(fps_timer); 64 LOCK_FUNCTION((void*)Timer); 65 LOCK_FUNCTION((void*)FPSTimer); 66 install_int_ex(Timer, BPS_TO_TIMER(120)); 67 install_int_ex(FPSTimer, BPS_TO_TIMER(1)); 68 69 front = create_bitmap(SCREENWIDTH, SCREENHEIGHT); 70 backdrop = create_bitmap(SCREENWIDTH, SCREENHEIGHT); 71 72 for(int i = 0 ; i < 100 ; ++i) hline(backdrop, 0, i, 320, makecol(200, 200, 255 - i)); 73 rectfill(backdrop, 0, 100, SCREENWIDTH, SCREENHEIGHT, makecol(0,100,0)); 74 texture = load_bitmap("texture.bmp", NULL); 75 76 while(!key[KEY_ESC]) 77 { 78 clear(front); 79 blit(backdrop,front, 0, 0, 0, 0, SCREENWIDTH, SCREENHEIGHT); 80 do_raycasting(); 81 draw_view(); 82 83 // draw the little compass/circle 84 line(front, 160, 100, 160 + (int)(25 * cos(pa)), 100 + (int)(25 * sin(pa)), makecol(0, 0, 255)); 85 line(front, 160, 100, 160 + (int)(25 * cos(pa - 0.523598)), 100 + (int)(25 * sin(pa - 0.523598)), makecol(255, 255, 0)); 86 line(front, 160, 100, 160 + (int)(25 * cos(pa + 0.523598)), 100 + (int)(25 * sin(pa + 0.523598)), makecol(255, 255, 0)); 87 circle(front, 160, 100, 25, makecol(255, 0, 0)); 88 textout_centre(front, font, "N", 160, 65, makecol(0, 0, 255)); 89 ++num_frames_drawn; 90 91 if(fps_timer) 92 { 93 fps = num_frames_drawn; 94 fps_timer = num_frames_drawn = 0; 95 } 96 97 textprintf(front, font, 15, 5, makecol(0,0,255), "FPS: %d", fps); 98 99 blit(front, screen, 0, 0, 0, 0, SCREENWIDTH, SCREENHEIGHT); 100 101 while(game_time > 0) 102 { 103 if(key[KEY_A]) 104 { 105 px -= (int)(ps * cos(pa - M_PI / 2)); 106 py -= (int)(ps * sin(pa - M_PI / 2)); 107 } 108 if(key[KEY_D]) 109 { 110 px += (int)(ps * cos(pa - M_PI / 2)); 111 py += (int)(ps * sin(pa - M_PI / 2)); 112 } 113 if(key[KEY_LEFT]) pa += 0.03; 114 if(key[KEY_RIGHT]) pa -= 0.03; 115 if(key[KEY_UP]) 116 { 117 px += (int)(ps * cos(pa)); 118 py += (int)(ps * sin(pa)); 119 } 120 if(key[KEY_DOWN]) 121 { 122 px -= (int)(ps * cos(pa)); 123 py -= (int)(ps * sin(pa)); 124 } 125 if(collisions() == true) 126 px = p_old_x, py = p_old_y; 127 else 128 p_old_x = px, p_old_y = py; 129 130 if(pa < 0) pa += M_PI * 2; 131 if(pa > M_PI * 2) pa -= M_PI * 2; 132 133 --game_time; 134 } 135 } 136 137 destroy_bitmap(front); 138 destroy_bitmap(texture); 139 destroy_bitmap(backdrop); 140 141 return 0; 142} 143END_OF_MAIN() 144 145void do_raycasting() 146{ 147 double angle = pa + 0.523598; 148 149 for(int i = 0 ; i < SCREENWIDTH ; ++i) 150 { 151 // get the distance of the ray 152 view<i> = (int)(cos(angle - pa) * CastRay(px, py, angle, texture_map<i>)); 153 154 // increment the angle 155 angle -= 1.04719 / SCREENWIDTH; 156 } 157} 158 159void draw_view() 160{ 161 int tall = 0; 162 163 for(int i = 0 ; i < SCREENWIDTH ; ++i) 164 { 165 tall = (int)(64.0 / view<i> * 277.0); 166 stretch_blit(texture, front, texture_map<i>, 0, 1, 64, i, (SCREENHEIGHT - tall) / 2, 1, tall); 167 } 168} 169 170bool collisions() 171{ 172 return (bool)level[px >> TILESHIFT][py >> TILESHIFT]; 173} 174 175float CastRay(int xpos, int ypos, double angle, int& t) { 176 // initialize (X_Ycheck, X_Xcheck) with first vertical wall and 177 // (Y_Ycheck, Y_Xcheck) with the first horizontal one 178 float X_Ycheck, X_Xcheck, Y_Ycheck, Y_Xcheck; 179 float X_Yinc, X_Xinc, Y_Yinc, Y_Xinc; 180 181 // hacka hacka hacka .... 182 if(angle < 0.01 && angle > 0) angle = 0.01; 183 if(angle < M_PI + 0.01 && angle > M_PI) angle = M_PI + 0.01; 184 if(angle < M_PI && angle > M_PI - 0.01) angle = M_PI - 0.01; 185 186 double tangent = tan(angle); 187 if(tangent >= 0.0 && tangent < 0.01) tangent = 0.01; 188 if(tangent <= 0.0 && tangent > -0.01) tangent = -0.01; 189 if(tangent > 999) tangent = 999; 190 if(tangent < -999) tangent = -999; 191 192 // sin(90) == 1; sin(270) == -1 193 if(sin(angle) > 0) // The y-values are increasing 194 { 195 Y_Ycheck = (ypos / 64) * 64 + 64; 196 Y_Xcheck = xpos + (Y_Ycheck - ypos) / tangent; 197 Y_Yinc = 64; 198 Y_Xinc = 64 / tangent; 199 } else { // The y-values are decreasing 200 Y_Ycheck = (ypos / 64) * 64 - 1; 201 Y_Xcheck = xpos + (Y_Ycheck - ypos) / tangent; 202 Y_Yinc = -64; 203 Y_Xinc = -64 / tangent; 204 } 205 206 // check for the walls 207 while(((int)Y_Xcheck >> 6 < 9) && 208 ((int)Y_Ycheck >> 6 < 9) && 209 level[(int)Y_Xcheck >> TILESHIFT][(int)Y_Ycheck >> TILESHIFT] == 0) 210 { 211 Y_Xcheck += Y_Xinc; 212 Y_Ycheck += Y_Yinc; 213 } 214 215 // cos(0) == 1; cos(180) == -1 216 if(cos(angle) > 0) // The x-values are increasing 217 { 218 X_Xcheck = (xpos / 64) * 64 + 64; 219 X_Ycheck = ypos + (X_Xcheck - xpos) * tangent; 220 X_Xinc = 64; 221 X_Yinc = 64 * tangent; 222 } 223 else // The x-values are decreasing 224 { 225 X_Xcheck = (xpos / 64) * 64 - 1; 226 X_Ycheck = ypos + (X_Xcheck - xpos) * tangent; 227 X_Xinc = -64; 228 X_Yinc = -64 * tangent; 229 } 230 231 while(((int)X_Xcheck >> 6 < 9) && 232 ((int)X_Ycheck >> 6 < 9) && 233 level[(int)X_Xcheck >> TILESHIFT][(int)X_Ycheck >> TILESHIFT] == 0) 234 { 235 X_Xcheck += X_Xinc; 236 X_Ycheck += X_Yinc; 237 } 238 239 float xcheck = (X_Xcheck - xpos) * (X_Xcheck - xpos) + (X_Ycheck - ypos) * (X_Ycheck - ypos); 240 float ycheck = (Y_Xcheck - xpos) * (Y_Xcheck - xpos) + (Y_Ycheck - ypos) * (Y_Ycheck - ypos); 241 242 if(xcheck < ycheck) 243 { 244 t = (int)X_Ycheck % TILE; 245 return sqrt(xcheck); 246 } 247 else 248 { 249 t = (int)Y_Xcheck % TILE; 250 return sqrt(ycheck); 251 } 252}

Only problem now is that player movement at odd angles is a little "off", but making the player's position floats instead of ints should help that (EDIT: yup, that did it). I ought to add joystick code so I can move more accurately using analog joysticks and L/R strafe buttons ;D

Thomas Harte

Have you seen this?

23yrold3yrold

I've only been pimping that site all thread, TH :P If I fixed my math correctly, then that site has some math errors on it ...

EDIT: Actually, I think I'm right; that site does have an error, in that it doesn't negate the tangent value if a ray is going in certian directions. Anyway, it's pretty much perfect now ... I just need to figure out how to call tan() without having it crash. The fix I'm using right now produces minor texture problems ...

aybabtu

I looked at 23's engine, then at mine, then I noticed a major flaw in mine. In 23's the wall slices are all 1 pixel. In mine, the wall slices are 2 pixels! What the hell? What's going on?
I "cheated" to get a bit more speed out of it last night. I have it multiplying x_inc and y_inc by 3, and distance by 3. Of course, this limits the accuracy of the texture mapping, and I needed to create more of a collision buffer so the player couldn't get within 3 px of a wall. I get about 8 or 9 fps standing, 6 walking, and 4 up way close to a wall. With the texture mapping problem above, it doesn't look pretty, though. How do I fix that?

Latest code:

#SelectExpand
1#include <allegro.h> 2 3#define TILE 64 4 5int level[9][9]={ 6{1,1,1,1,1,1,1,1,1}, 7{1,0,0,0,0,0,0,0,1}, 8{1,0,1,0,1,0,1,0,1}, 9{1,0,0,0,0,0,0,0,1}, 10{1,0,1,0,1,0,1,0,1}, 11{1,0,0,0,0,0,0,0,1}, 12{1,0,1,0,1,0,1,0,1}, 13{1,0,0,0,0,0,0,0,1}, 14{1,1,1,1,1,1,1,1,1}}; 15 16int view[320]; 17int texture_map[320]; 18 19int px=96; 20int py=96; 21int p_old_x=96; 22int p_old_y=96; 23int p_turn_s=3; 24int p_walk_s=7; 25float pa=32.0; 26 27int fps=0; 28int max_fps=0; 29 30bool fishbowl=false; 31bool textures_off=false; 32 33volatile int timer=0; 34void inc_timer() 35{ 36 timer++; 37}END_OF_FUNCTION(inc_timer); 38 39BITMAP*front; 40BITMAP*backdrop; 41BITMAP*texture; 42 43float cast_ray(int x,int y,float a); 44void draw_view(); 45void do_raycasting(); 46bool collisions(); 47 48int main() 49{ 50 allegro_init(); 51 install_timer(); 52 install_keyboard(); 53 set_color_depth(24); 54 set_gfx_mode(GFX_AUTODETECT,320,200,0,0); 55 front=create_bitmap(320,200); 56 backdrop=create_bitmap(320,200); 57 for(int i=0;i<100;i++) hline(backdrop,0,i,320,makecol(200,200,255-i)); 58 rectfill(backdrop,0,100,320,200,makecol(0,100,0)); 59 texture=load_bitmap("texture.bmp",NULL); 60 LOCK_VARIABLE(timer); 61 LOCK_FUNCTION(inc_timer); 62 install_int_ex(inc_timer,SECS_TO_TIMER(1)); 63 while(!key[KEY_ESC]) 64 { 65 if(timer>0) 66 { 67 fps=0; 68 timer=0; 69 } 70 else fps++; 71 if(max_fps<fps) max_fps=fps; 72 clear(front); 73 blit(backdrop,front,0,0,0,0,320,200); 74 do_raycasting(); 75 draw_view(); 76 if(key[KEY_F]) fishbowl=true; 77 if(key[KEY_G]) fishbowl=false; 78 if(key[KEY_T]) textures_off=false; 79 if(key[KEY_R]) textures_off=true; 80 if(key[KEY_A]) 81 { 82 px+=(int)(p_walk_s*cos(pa-64)); 83 py+=(int)(p_walk_s*sin(pa-64)); 84 } 85 if(key[KEY_D]) 86 { 87 px-=(int)(p_walk_s*cos(pa-64)); 88 py-=(int)(p_walk_s*sin(pa-64)); 89 } 90 if(key[KEY_LEFT]) pa-=p_turn_s; 91 if(key[KEY_RIGHT]) pa+=p_turn_s; 92 if(key[KEY_UP]) 93 { 94 px+=(int)(p_walk_s*cos(pa)); 95 py+=(int)(p_walk_s*sin(pa)); 96 } 97 if(key[KEY_DOWN]) 98 { 99 px-=(int)(p_walk_s*cos(pa)); 100 py-=(int)(p_walk_s*sin(pa)); 101 } 102 if(collisions()==true) 103 { 104 px=p_old_x; 105 py=p_old_y; 106 } 107 else 108 { 109 p_old_x=px; 110 p_old_y=py; 111 } 112 if(pa<0) pa+=255; 113 if(pa>255) pa-=255; 114 textprintf(front,font,0,0,makecol(255,255,255),"FPS: %i Max: %i",fps,max_fps); 115 textprintf(front,font,0,8,makecol(255,255,255),"X: %i Y: %i A: %i",px,py,(int)pa); 116 textprintf(front,font,0,16,makecol(255,255,255),"Tile X: %i Tile Y: %i",px/TILE,py/TILE); 117 vsync(); 118 blit(front,screen,0,0,0,0,320,200); 119 if(key[KEY_S]) save_bitmap("wolf.pcx",front,NULL); 120 } 121 destroy_bitmap(front); 122 destroy_bitmap(texture); 123 destroy_bitmap(backdrop); 124 return 0; 125} 126 127void do_raycasting() 128{ 129 float x_inc; 130 float y_inc; 131 float distance=0.0; 132 float the_x=px; 133 float the_y=py; 134 float angle=pa-21.25; 135 bool ended_on_y=false; 136 for(int i=0;i<320;i++) 137 { 138 x_inc=((float)cos(angle))*3; 139 y_inc=((float)sin(angle))*3; 140 while(level[(int)the_y/TILE][(int)the_x/TILE]==0) 141 { 142 the_x+=x_inc; 143 if(level[(int)the_y/TILE][(int)the_x/TILE]!=0) 144 { 145 ended_on_y=true; 146 break; 147 } 148 the_y+=y_inc; 149 if(level[(int)the_y/TILE][(int)the_x/TILE]!=0) 150 { 151 ended_on_y=false; 152 break; 153 } 154 distance+=3; 155 } 156 if(ended_on_y==true) texture_map<i>=(int)((int)the_y%TILE); 157 if(ended_on_y==false) texture_map<i>=(int)((int)the_x%TILE); 158 if(fishbowl==false) view<i>=(int)((cos(angle-pa))*distance); 159 if(fishbowl==true) view<i>=(int)distance; 160 angle+=0.13125; 161 distance=0.0; 162 the_x=px; 163 the_y=py; 164 } 165} 166 167void draw_view() 168{ 169 int tall=0; 170 int distance_from_top=0; 171 int color=255; 172 for(int i=0;i<320;i++) 173 { 174 color=255-(view<i>*(int)(255/view<i>)); 175 tall=(int)(64.0/view<i>*277.0); 176 distance_from_top=(200-tall)/2; 177 if(textures_off==true) rectfill(front,i+1,distance_from_top,i+2,distance_from_top+tall,makecol(color,color,color)); 178 if(textures_off==false) stretch_blit(texture,front,texture_map<i>,0,1,texture->w,i,distance_from_top,1,tall); 179 } 180} 181 182bool collisions() 183{ 184 if(level[py/TILE][px/TILE]!=0) return true; 185 if(level[(py+5)/TILE][(px+5)/TILE]!=0) return true; 186 if(level[(py+5)/TILE][(px-5)/TILE]!=0) return true; 187 if(level[(py-5)/TILE][(px-5)/TILE]!=0) return true; 188 if(level[(py-5)/TILE][(px+5)/TILE]!=0) return true; 189 return false; 190}

:P

23yrold3yrold

Well, your methods are wrong :) It's not very exact and its slow and there's bound to be precision loss or what have you. Why not just use my engine? It's faster and prettier and it's based on yours; how hard could it be?

Trezker

Did you notice the fps on my engine?
23, what's your oppinion on my files?

23yrold3yrold

Didn't look at them. Aybabtu says they're QBASIC ... yuck :P ;)

Trezker

The original was qbasic, I translated its last tutorial code to c++, then I took the engine a bit further.

23yrold3yrold

Compiled fine. 80fps windowed, potentially higher if windowed. I like how you can follow walls, something my current code doesn't do yet (but that's collision detection, not raytracing, anyway :)) Looks and works great.

EDIT: Oooh, I like my engine in 640x480 :o ;D The stretch_blit() is definitely killing it though ...

Trezker

I was about to go in way over my head when I abandoned it, I was planning to make every block have its own floor and roof height, but that felt like too much so I lost the enthusiasm.
I doubt it would bring much value to the game anyway, so I dropped it over an unnessesary feature.
If you need help with my engine, just ask.

I got an idea of making a nice RPG game with it.

23yrold3yrold

Scratch what I said; your second and third examples don't compile using the latest MinGW.

Ace

I believe that has something to do with #define M_PI. I changed it from #define M_PI 3.14(w*.5-1)265358979323846 to #define M_PI 3.14 and it compiles. Looks like M_PI is suppose to take a parameter. I don't know much about #defines. ;)

- Ace

Zaphos

23: to make the tangent not return an infinity you can try doing a hack like:

if (cos(angle)==0) angle+=.01;
tangent = tan(angle);

(or, to optimize, take out the cos and replace with appropriate values ... although the inherent inaccuracy in your PI define might mean you'd have to account for a bit of error in the equality, then)

23yrold3yrold

I have that hack. It's not crashing anymore; there's just some texture erroneousness ...

And how accurate does my pi need to be?

#define M_PI           3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679

:P

Johnny13
Quote:

clear(front);
blit(backdrop,front,0,0,0,0,320,200);

aybabtu:
thats why you have low FPS!
ok,let me post my modified version here and attach a screenshot.;)

1#include<math.h>
2#include<al419.h>
3#include<loadpng.h>
4char NYAH[9][9]={
5{9,9,9,9,9,9,9,9,9},
6{9,0,0,0,0,0,0,0,9},
7{9,0,9,0,0,0,9,0,9},
8{9,0,0,0,0,0,0,0,9},
9{9,0,9,9,9,9,9,0,9},
10{9,0,0,0,4,4,4,0,9},
11{9,0,0,0,4,4,4,0,9},
12{9,0,0,0,0,0,0,0,9},
13{9,9,9,9,9,9,9,9,9}}; BITMAP*b,*TEX,*MAP; void raycasting(); float CastRay(int xpos,int ypos,double ang,int*t);
14#define MC(RR,GG,BB) makecol(RR,GG,BB)
15#define COLL (NYAH[px>>6][py>>6])
16#define J1(X) joy[0].stick[0].axis[X].d1
17#define J2(X) joy[0].stick[0].axis[X].d2
18#define AL_RAND ((rand()>>8)|(rand()&0xff00))
19int W=320,H=240,view[320],tmap[320],i,px=65,py=65,p_ox=65,p_oy=65,ps=2,tall,dist,c; float a,pa=1;
20int main(){allegro_init();install_mouse();install_joystick(-1);
21 set_color_depth(16);set_gfx_mode(2,W,H,0,0); set_window_title(allegro_id); loadpng_init();
22 MAP=create_bitmap_ex(8,9,9); for(i=0;i<9;i++)for(c=0;c<9;c++)MAP->line<i>[c]=NYAH<i>[c];
23 TEX=load_bitmap("http://allegro.cc/members/avatars/2891.png",NULL); b=create_bitmap_ex(16,W,H); while(!mouse_b) {poll_joystick();
24 if(J1(0)) pa-=0.04; if(pa<0) pa+=AL_PI*2;
25 if(J2(0)) pa+=0.04; if(pa>AL_PI*2) pa-=AL_PI*2;
26 if(J1(1)) {px+=(int)(ps*cos(pa)); py+=(int)(ps*sin(pa));}
27 if(J2(1)) {px-=(int)(ps*cos(pa)); py-=(int)(ps*sin(pa));}
28 if(joy[0].button[6].b) {px+=(int)(ps*cos(pa-AL_PI/2)); py+=(int)(ps*sin(pa-AL_PI/2));}
29 if(joy[0].button[7].b) {px-=(int)(ps*cos(pa-AL_PI/2)); py-=(int)(ps*sin(pa-AL_PI/2));}
30 if (COLL&&px>0&&py>0) {px=p_ox;py=p_oy;} else {p_ox=px;p_oy=py;}
31 for(i=0;i<H;i++)hline(b,0,i,W,(i<H/2)?MC(200,200,255-i):MC(0,i,0)); raycasting();
32 for(i=0;i<W;i++) {tall=(int)(64.0/view<i>*277.0); dist=(H-tall)/2;
33 masked_stretch_blit(TEX,b,tmap<i>,0,1,64,i,dist,1,tall);
34 } for(a=0;a<360;a+=.1)putpixel(b,(int)(W-13+(13*cos(a))),(int)(13+(13*sin(a))),31);
35 line(b,W-13,13,W-13+(13*cos(pa)),13+(13*sin(pa)),MC(255,0,0));
36 line(b,W-13,13,W-13+(13*cos(pa-0.5)),13+(13*sin(pa-0.5)),1337);
37 line(b,W-13,13,W-13+(13*cos(pa+0.5)),13+(13*sin(pa+0.5)),1337);
38 draw_sprite(b,MAP,W-36,0); putpixel(b,W-36+(px>>6),py>>6,c);
39 textprintf_ex(b,font,0,0,MC(0,255,0),0,"%d,%d,%.4f",px,py,pa); vsync();blit(b,screen,0,0,0,0,W,H);
40 c=AL_RAND; for(i=0;i<W;i++){putpixel(screen,i,view<i>,c); putpixel(screen,i,tmap<i>,0xf800);}
41 }}END_OF_MAIN();
42void raycasting()
43{double a=pa-0.5236; for(i=0;i<W;i++){view<i>=(int)(cos(a-pa)*CastRay(px,py,a,&tmap<i>)); a+=1.04719/W;}
44}
45float CastRay(int xpos,int ypos,double ang,int*t)
46{float XYchk,XXchk,YYchk,YXchk,XYinc,XXinc,YYinc,YXinc; if(ang<0.01&&ang>0)ang=0.01;
47 if(ang<AL_PI+0.01&&ang>AL_PI)ang=AL_PI+0.01; if(ang<AL_PI&&ang>AL_PI-0.01)ang=AL_PI-0.01;
48 if(cos(ang)==0)ang+=.01; double TAN=tan(ang);
49 if(TAN>=0.0&&TAN<0.01)TAN=0.01; if(TAN<=0.0&&TAN>-0.01)TAN=-0.01; if(TAN>999)TAN=999; if(TAN<-999)TAN=-999;
50 if(sin(ang)>0) //inc Y
51 {YYchk=(ypos/64)*64+64; YXchk=xpos+(YYchk-ypos)/TAN; YYinc=64; YXinc=64/TAN;
52 while(!getpixel(MAP,(int)YXchk>>6,(int)YYchk>>6)) {YXchk+=YXinc; YYchk+=YYinc;}
53 } else //dec Y
54 {YYchk=(ypos/64)*64-1; YXchk=xpos+(YYchk-ypos)/TAN; YYinc=-64; YXinc=-64/TAN;
55 while(!getpixel(MAP,(int)YXchk>>6,(int)YYchk>>6)) {YXchk+=YXinc; YYchk+=YYinc;}
56 }
57 if(cos(ang)>0) //inc X
58 {XXchk=(xpos/64)*64+64; XYchk=ypos+(XXchk-xpos)*TAN; XXinc=64; XYinc=64*TAN;
59 while(!getpixel(MAP,(int)XXchk>>6,(int)XYchk>>6)) {XXchk+=XXinc; XYchk+=XYinc;}
60 } else //dec X
61 {XXchk=(xpos/64)*64-1; XYchk=ypos+(XXchk-xpos)*TAN; XXinc=-64; XYinc=-64*TAN;
62 while(!getpixel(MAP,(int)XXchk>>6,(int)XYchk>>6)) {XXchk+=XXinc; XYchk+=XYinc;}
63 }
64 float x=(XXchk-xpos)*(XXchk-xpos)+(XYchk-ypos)*(XYchk-ypos),y=(YXchk-xpos)*(YXchk-xpos)+(YYchk-ypos)*(YYchk-ypos);
65 if(x<y){*t=(int)XYchk%64;return sqrt(x);}else{*t=(int)YXchk%64;return sqrt(y);}}

seems that we are interested in aybabtu's project:P
Nyah

Zaphos

Responses / rambling:
Oh, sorry! Erm ... now that I think about it, PI accuracy probably won't be an issue either, heh.

Did you edit in this ("The fix I'm using right now produces minor texture problems ...") part of your post (a few posts up) by the way? Or did I just somehow not read it when I wrote my last post in this thread?
Edit: and is it just me or did J13 curse his modification of aybabtu's code with ugliness?

Questions:
1) What's the texture inaccuracy being caused by that hack? (I can't see how that hack would cause texture problems ...)
2) Would anyone be interested in starting some form of allegro module collection (a set of easy to use files that would allow anyone to, say, have a raycaster, mode 7 gfx, etc, simply by downloading two files (and include and .c) and calling the appropriate functions? I think this raycaster thing would be a great first module, as there's so much community interest ...

23yrold3yrold

1) If my hack screws up the accuracy of tan at angles close to factors of 90, then it would explain why the texture is a mite screwy when looking right down the side of a wall (only half of them; the one on your immediate left when you start, for example).
2) Love to. Someone else is working on Mode 7 (amarillion) and I guess I can make up a raytracer lib since I'm interested right now :) Right now I'm playing a Flash game, so maybe later ;D

Zaphos

1) Did you try decreasing the amount of intentional error you create? Add .0001 instead of .01, for example?
2) Sweet! I can imagine this being a very cool resource to have. Would you like to host / do that stuff as well? Or should I get it started? I guess the grand opening would deserve a thread of its own ... and a news item, even.

23yrold3yrold

1) The crashes come back ...
2) I think a higher level library for Allegro would rule. I've already begun one with my tilemap class, animation class, screen update API, etc. A raycasting API would be a good addition, as would a Mode 7 one. I can't host as I have no where to do it, but I would either contribute to one or just let one accumulate as I code and code and code :) Feel free to start a thread brainstorming as to what such a lib would require ...

aybabtu

23: The reason I don't want to just use your engine is because I don't understand it. I want to work through mine and learn it.

J13: Would clear() and blit() really slow it down that much?
EDIT: J13: No offense, but is that how you normally write your code? Or did you forget the ENTER key?::)

EDIT 2: J13: It appears that clear() does slow it down...I can now pump a whopping 11::) fps out of it!

Ace

Eeeek. I need to get started on my own raycasting engine if I'm going to do this for the rpgdx compo this weekend. The last I checked there were only three entrants. :(

... Better chance of winning, I suppose.

- Ace

23yrold3yrold
Quote:

Would clear() and blit() really slow it down that much?

Evidently so; I lose a lot of FPS if I'm right up against a wall.

Quote:

23: The reason I don't want to just use your engine is because I don't understand it. I want to work through mine and learn it.

My code is your code! ;D I'm just using the math from that one site in place of your shoot-a-very-slow-ray-until-it-hits-something method.

Peter Hull

If you take the calculations for x_inc and y_inc out of the loop, does that make a difference?

Pete

aybabtu
Quote:

My code is your code! I'm just using the math from that one site in place of your shoot-a-very-slow-ray-until-it-hits-something method.

Okey...the raycasting part is the most important part. I'd much rather learn from my mistakes than just copy someones code. I'm starting to get the math behind the faster way, but I don't quite have it yet. Very seldomly do I just take some code that I don't understand. Plus, I'll learn so much more if I work through it. Thanks for the offer, but from now on, remember that I don't want someone doing it for me. :P

Quote:

If you take the calculations for x_inc and y_inc out of the loop, does that make a difference?

Yeah, because then it would:
A) Be very slow if you used sin() and cos() in your casting loop.
B) Or just not work at all...:o

Ace

Are you using cos/sin lookup tables? I believe that might give you a big speed boost. I noticed in your last code post that you are calling cos/sin 320 times every frame which SURELY kills performance.

- Ace

aybabtu

How could I use lookup tables? Wouldn't it be hard with the angle variable being incremented by less than a whole number? And, the angle var is gotten by using the pa variable, which could have anything between 0-255! I think it'd be hard... I could have something like
sin_table[255];
cos_table[255];
but that would only be good for whole numbered angles! Could anyone help me with this?

Zaphos

aybabtu: Well, you change the angle by a fixed amount at a time, so there's only a fixed amount of entries you'd need in your sin or cos table. But since you're using allegro's builtin fixed point math it should matter -- allegro's fixed math sin and cos already use a lookup table.

Ace

I'm not sure if this will work, but it is worth the try. From your code it appears angle has a precision of two decimal places.

So maybe try:

sin[angle*100] = sin(angle);

For all possible angles. It'll produce a huge table, but I'm sure you'd makeup for it with the fps gains.

Edit: Eeeeek, well nevermind then.

- Ace

aybabtu

I tried some tables and such, but it didn't make a difference. It's because of allegro stepping in to help speed up sin&cos with it's tables. Very nice of it, really.:P

EDIT: Screw allegro's "help"!! I #included <math.h>, then made a macro to convert degrees (0-360) to radians, and used the sin & cos functions without allegro's help. I got the idea after I RTFM and it said that it's sin and cos tables weren't very accurate. Well, guess what? IT'S BEAUTIFUL!!!! Here's a screenie:
[url http://www.angelfire.com/empire/jonhome/wolf3.gif]Image...[/url]
Here's the latest code:
(I know I overuse the DEG_TO_RAD() macro, but it's easier this way. Also, notice the DrawSlice() function, made by 23, and it gives me an extra FPS. Also, I used those shift operators to do division, and that gave me another FPS! Also, you can now control it by the mouse...controls are shown...)

#SelectExpand
1/* Raycasting engine 2 * June 2003 3 * < Controls > 4 * Mouse: 5 * Foward.........Right Button 6 * Turn Left......Move Left 7 * Turn Right.....Move Right 8 * Shoot..........Left Button 9 * Aim Up.........Move Foward 10 * Aim Down.......Move Backward 11 * Keyboard: 12 * Foward.........W Key 13 * Backward.......S Key 14 * Strafe Left....A Key 15 * Strafe Right...D Key 16 * Aim Up.........Up Arrow 17 * Aim Down.......Down Arrow 18 * Turn Left......Left Arrow 19 * Turn Right.....Right Arrow 20 * Shoot..........Spacebar 21 * Center Aim.....Q Key 22 */ 23 24#include <allegro.h> 25#include <math.h> 26 27#define TILE 64 28#define TILE_SHIFT 6 29 30#define MOUSE_CONTROL_SPEED 4 31 32#define DEG_TO_RAD(x) ((x)*0.0174532925) 33 34int level[9][9]={ 35{1,1,1,1,1,1,1,1,1}, 36{1,0,0,0,0,0,0,0,1}, 37{1,0,1,0,1,0,1,0,1}, 38{1,0,0,0,0,0,0,0,1}, 39{1,0,1,0,1,0,1,0,1}, 40{1,0,0,0,0,0,0,0,1}, 41{1,0,1,0,1,0,1,0,1}, 42{1,0,0,0,0,0,0,0,1}, 43{1,1,1,1,1,1,1,1,1}}; 44 45int view[320]; 46int texture_map[320]; 47 48int px=70; 49int py=70; 50int p_old_x=70; 51int p_old_y=70; 52int p_turn_s=3; 53int p_walk_s=7; 54float pa=1; 55 56int mouse_move_x=0; 57int mouse_move_y=0; 58int crosshairs_y=100; 59 60int fps=0; 61int max_fps=0; 62 63volatile int timer=0; 64void inc_timer() 65{ 66 timer++; 67}END_OF_FUNCTION(inc_timer); 68 69BITMAP*front; 70BITMAP*backdrop; 71BITMAP*texture; 72 73void draw_view(); 74void do_raycasting(); 75bool collisions(); 76void fill_tables(); 77 78void DrawSlice(BITMAP*texture,BITMAP*buffer,int xoff,int x,int y,int tall); 79 80int main() 81{ 82 allegro_init(); 83 install_timer(); 84 install_mouse(); 85 install_keyboard(); 86 set_color_depth(16); 87 set_gfx_mode(GFX_AUTODETECT,320,200,0,0); 88 front=create_bitmap(320,200); 89 backdrop=create_bitmap(320,200); 90 for(int i=0;i<100;i++) hline(backdrop,0,i,320,makecol(200,200,255-i)); 91 for(int i=200;i>100;i--) hline(backdrop,0,i,320,makecol(0,i,0)); 92 texture=load_bitmap("texture.bmp",NULL); 93 LOCK_VARIABLE(timer); 94 LOCK_FUNCTION(inc_timer); 95 install_int_ex(inc_timer,SECS_TO_TIMER(1)); 96 int da_fps=0; 97 while(!key[KEY_ESC]) 98 { 99 if(timer>0) 100 { 101 da_fps=fps; 102 fps=0; 103 timer=0; 104 } 105 else fps++; 106 if(max_fps<fps) max_fps=fps; 107 blit(backdrop,front,0,0,0,0,320,200); 108 do_raycasting(); 109 draw_view(); 110 111 get_mouse_mickeys(&mouse_move_x,&mouse_move_y); 112 crosshairs_y+=(int)(mouse_move_y/MOUSE_CONTROL_SPEED); 113 pa+=(int)(mouse_move_x/MOUSE_CONTROL_SPEED); 114 if(key[KEY_P]) save_bitmap("wolf.pcx",front,NULL); 115 if(key[KEY_A]) 116 { 117 px+=(int)(p_walk_s*cos(DEG_TO_RAD(pa-90))); 118 py+=(int)(p_walk_s*sin(DEG_TO_RAD(pa-90))); 119 } 120 if(key[KEY_D]) 121 { 122 px-=(int)(p_walk_s*cos(DEG_TO_RAD(pa-90))); 123 py-=(int)(p_walk_s*sin(DEG_TO_RAD(pa-90))); 124 } 125 if(key[KEY_Q]) crosshairs_y=100; 126 if(key[KEY_LEFT]) pa-=p_turn_s; 127 if(key[KEY_RIGHT]) pa+=p_turn_s; 128 if(key[KEY_UP]) crosshairs_y-=5; 129 if(key[KEY_DOWN]) crosshairs_y+=5; 130 if(key[KEY_W]||mouse_b&2) 131 { 132 px+=(int)(p_walk_s*cos(DEG_TO_RAD(pa))); 133 py+=(int)(p_walk_s*sin(DEG_TO_RAD(pa))); 134 } 135 if(key[KEY_S]) 136 { 137 px-=(int)(p_walk_s*cos(DEG_TO_RAD(pa))); 138 py-=(int)(p_walk_s*sin(DEG_TO_RAD(pa))); 139 } 140 141 if(collisions()==true) 142 { 143 px=p_old_x; 144 py=p_old_y; 145 } 146 else 147 { 148 p_old_x=px; 149 p_old_y=py; 150 } 151 if(pa<0) pa+=360; 152 if(pa>360) pa-=360; 153 textprintf(front,font,0,0,makecol(255,255,255),"FPS: %i Max: %i",da_fps,max_fps); 154 textprintf(front,font,0,8,makecol(255,255,255),"X: %i Y: %i A: %i",px,py,(int)pa); 155 textprintf(front,font,0,16,makecol(255,255,255),"tX: %i tY: %i",px/TILE,py/TILE); 156 hline(front,150,crosshairs_y,170,makecol(150,255,150)); 157 vline(front,160,crosshairs_y-10,crosshairs_y+10,makecol(150,255,150)); 158 vsync(); 159 blit(front,screen,0,0,0,0,320,200); 160 } 161 destroy_bitmap(front); 162 destroy_bitmap(texture); 163 destroy_bitmap(backdrop); 164 return 0; 165} 166 167void do_raycasting() 168{ 169 float x_inc; 170 float y_inc; 171 int distance=0; 172 float the_x=px; 173 float the_y=py; 174 float angle=DEG_TO_RAD(pa-30); 175 bool ended_on_y=false; 176 for(int i=0;i<320;i++) 177 { 178 x_inc=cos(angle)*3; 179 y_inc=sin(angle)*3; 180 while(level[(int)the_y>>TILE_SHIFT][(int)the_x>>TILE_SHIFT]==0) 181 { 182 the_x+=x_inc; 183 if(level[(int)the_y>>TILE_SHIFT][(int)the_x>>TILE_SHIFT]!=0) 184 { 185 ended_on_y=true; 186 break; 187 } 188 the_y+=y_inc; 189 if(level[(int)the_y>>TILE_SHIFT][(int)the_x>>TILE_SHIFT]!=0) 190 { 191 ended_on_y=false; 192 break; 193 } 194 distance+=3; 195 } 196 if(ended_on_y==true) texture_map<i>=(int)((int)the_y%TILE); 197 if(ended_on_y==false) texture_map<i>=(int)((int)the_x%TILE); 198 view<i>=(int)(cos(angle-DEG_TO_RAD(pa))*distance); 199 angle+=DEG_TO_RAD(0.1875); 200 distance=0; 201 the_x=px; 202 the_y=py; 203 } 204} 205 206void draw_view() 207{ 208 int tall=0; 209 int distance_from_top=0; 210 for(int i=0;i<320;i++) 211 { 212 tall=(int)(64.0/view<i>*277.0); 213 distance_from_top=(200-tall)/2; 214 //23yrold3yrold's faster stretching: 215 DrawSlice(texture,front,texture_map<i>,i,distance_from_top,tall); 216 //Old method of drawing slices: 217 //stretch_blit(texture,front,texture_map<i>,0,1,texture->w,i,distance_from_top,1,tall); 218 } 219} 220 221bool collisions() 222{ 223 if(level[py>>TILE_SHIFT][px>>TILE_SHIFT]!=0) return true; 224 if(level[(py+5)>>TILE_SHIFT][(px+5)>>TILE_SHIFT]!=0) return true; 225 if(level[(py+5)>>TILE_SHIFT][(px-5)>>TILE_SHIFT]!=0) return true; 226 if(level[(py-5)>>TILE_SHIFT][(px-5)>>TILE_SHIFT]!=0) return true; 227 if(level[(py-5)>>TILE_SHIFT][(px+5)>>TILE_SHIFT]!=0) return true; 228 return false; 229} 230 231void DrawSlice(BITMAP*texture,BITMAP*buffer,int xoff,int x,int y,int tall) 232{ 233 int srcy=0, num=0; 234 for(int i=y;i<y+tall;i++) 235 { 236 num+=64; 237 while(num>=tall) 238 { 239 num-=tall; 240 srcy++; 241 } 242 if(i<0) continue; 243 if(srcy>=64||i>=buffer->h) return; 244 ((short*)buffer->line<i>)[x]=((short*)texture->line[srcy])[xoff]; 245 } 246}

Pretty kewl...;D

23yrold3yrold

I see no picture. Does this mean your columns are 1 pixel wide instead of 2 now?

aybabtu

I just uploaded the pic, so you should see it now...sorry!

Yup. 1 pixel! And the textures look way nicer, too! (Notice the left-most wall in this one, then compare it to the "NO DISTORTIONS" screenshot...pretty nice!)

Bob

It'll run a lot faster if you rotate your texture by 90 degrees so that you read the X coord instead of the Y coord.

Untested code:

1void DrawSlice(BITMAP*texture,BITMAP*buffer,int xoff,int x,int y,int tall)
2{
3 int srcy=0, num=0;
4 for(int i=y;i<y+tall;i++)
5 {
6 num+=64;
7 while(num>=tall)
8 {
9 num-=tall;
10 srcy++;
11 }
12 if(i<0) continue;
13 if(srcy>=64||i>=buffer->h) return;
14 ((short*)buffer->line<i>)[x]=((short*)texture->line[xoff])[srcy];
15 }
16}

Replacing that while loop by a bunch of adds will also make it run a lot faster. If possible, see if you can drop those if statements from the inner loop too.

aybabtu

Alright...I'll try that rotate 90 degrees thing.

23yrold3yrold
Quote:

It'll run a lot faster if you rotate your texture by 90 degrees so that you read the X coord instead of the Y coord.

Oooohh! Is that because of cache missing or whatever you call it? Okay, I understand now ;D I'll have to play with this now ...

I'd still love to have my math problems magically disappear. Until then, I'm potentially optimising my errors, and that's no fun :P ...

Bob
Quote:

Oooohh! Is that because of cache missing or whatever you call it?

Yep :)

aybabtu

Arg.
To make it look even nicer, I have to take out some code that makes it run faster. What it does is multiplies the x_inc and y_inc by 3, and adds 3 to distance every step. But, this of course makes it innaccurate, and produces larger (3-4) pixel blocks close to the player. I've gotta learn how that thing on page 7 of that tutorial works. I understand it...sorta. I have two problems:
1) How do I get that first intersection?
2) Why does it separate the horizontal and vertical intersections?

Could someone help me understand it?:-/

23yrold3yrold

1) Basically, by rounding to the nearest 64 for one coordinate, then by using the tangent of the angle to get the other coordinate.
2) Because stepping through them seperately is a lot easier than going through them together. Look at how easy it is to just add twice every loop. Can only do that if they're checked seperately.

I still don't quite understand tan() enough to explain it. If it's not in amarillion's tutorial, it should be ;)

aybabtu

I'm okay with tan:
Tangent(angle)=opposite side/adjacent side
I also think I'm getting this thing...I'm going to go work on it now...

Thomas Harte

Going slightly off topic into the 'not raycasting' ideas I posted earlier, I've come up with a knockup of such an implementation (see attachment for code & screenshot) and am convinced that it is a 'better than raycasting' implementation. The technique uses a combination of the following:

- front to back (zero overdraw) portal based rendering
- one divide per column texture mapping (same as normal ray casting)

The FPS doesn't seem to be the astronomic figure I'd expected, but to put things in perspective, here are the top four time consuming functions from a profile build:

        Func          Func+Child           Hit
        Time   %         Time      %      Count  Function
---------------------------------------------------------
    2471.277  33.0     2471.277  33.0      686 _rectfill (alld40.dll)
     944.485  12.6     1258.176  16.8   109713 DrawSlither(struct BITMAP *,struct Texture *,int,int,int,int) (main.obj)
     774.079  10.3     1192.259  15.9   589954 _fmul (main.obj)
     740.479   9.9     2330.742  31.1     1904 AddWall(struct Wall *,unsigned int,long,long,int,int) (main.obj)

So, the bottleneck is clearly video memory access (i.e. drawing, not calculating), which is exactly the same cost as raycasting. Therefore I am confident that with properly optimised drawing code the same sorts of frame rates as ray casting could be seen.

With respect to fmul versus AddWall, fmul is used four times per wall (unless the wall is a reverse face - then just twice) and a further three times per slither if that slither actually appears on the screen. For slithers which do not appear on screen due to being obscured, no fmuls will usually be performed, however for areas where the wall would appear on screen were it longer (and retained the same orientation), one fmul will be performed per slither.

I know that the display sometimes flickers. I'm not sure if this is a buffer bug I've added or the usual array of incompatibilities between Allegro and Windows 2000.

AddWall becomes substantially faster as the screen fills up. Many more sectors would not substantially increase calculation costs.

A screenshot is only attached as I couldn't find anywhere to upload it in order to show it inline. Similarly Allegro.cc would not let me post the code inline due to length.

aybabtu

That's neat...seems more complex than raycasting, though...:)

EDIT:
New stuff for the raycaster:
Multiple textures. (I've got three coded in...I need to make a level editor!)
Sped it up and kept it nice looking...I'm getting 9-12 FPS walking...
Looking up and down, looking and rotating is really nice when controled by the mouse (i.e. smooth/cool!)
Heh...I've even got a gun in there now (I'm going to make it a fps.) It's the PPK from GoldenEye. The "Z" Key switches modes for the gun. This gun switches between silenced and not silenced. It's pretty cool.

EDIT 2: I just downloaded that FAT engine SDK...you must get it! What I think's cool is that it's got ALL the textures from Wolfenstein! Plus, they're 64x64 px, all aranged on a 640x384 sheet. Its cool!

23yrold3yrold

Yeah, textures are pretty easy. Just use different numbers in the array ;D

I'm going to add that other stuff too, but not until I've gotten rid of those texture problems. I'll keep that in the other thread though. Until then, it's back to my game ...

Guess I'll check out TH's code too :)

aybabtu

23 (and anyone else who's interested): I'm attaching a sheet with all the Wolfenstein textures!

23yrold3yrold
Quote:

I just downloaded that FAT engine SDK

What's this now? What does it do that that site doesn't teach?

Thomas Harte
Quote:

That's neat...seems more complex than raycasting, though...

Not really - the guts of the thing are within AddWall, and that is really nothing more than a ray caster which only considers one wall (and makes a few arrangements prior to drawing in order to pretend that the wall is axis aligned).

aybabtu
Quote:

What's this now? What does it do that that site doesn't teach?

It's that TICL thing that Carrus posted. It doesn't really teach anything new. But, it's got the wolfenstein textures, and the brown-suited enemies from wolfenstein.

I tried my hand at getting that better way to cast the rays to work...of course it didn't...oh well. I just can't get it to work. I don't even know if I want to get it to work. To be honest, 23, that bug in yours, which is probly caused by the tangent or something, makes that method very unappealing. Maybe I can be enlightened from that java source code...idunno. But, for now, I can make the detail level adjustable. Basically, I can multiply teh x_inc and y_inc, and distance by a number, which makes it go much faster. Of course, you lose accuracy, but even when you multiply it by 5, you can get more than 10 more fps, and the output is still acceptable. Some of the smaller lines and details are lost somewhat, but it's not a problem. I'll just have the detail level adjustable.

TH: Could you compile it into a binary? My DJGPP complains about MANY "errors". I tried fixing some, but I just gave up. How smooth is it? Would you think that you were in a raycaster when you're running it? What is a 2D portal engine?

Carrus85

The TICT FAT engine doesn't really assist you in doing things directly. However, it might prove more useful to look at the forum under FAT SDK. The optimizations neccesarry to get a Raycaster to work on a graphing calculator are drastic, maybe you could implement some of them.

The current engine also has built in support for sprites (similar to wolf3d, blake stone, etc.), Moving walls for those secret passages, doors, etc.

However, once again I must reiterate the fact that it will only prove useful for opimizition, if at all.

aybabtu

Hey...I think I should put depth shading in...how should I do it? Use a blending function or something? If so, I've never used one before...are they slow?

Zaphos

aybabtu: On TH's: my compiler and updated allegro only gave one error, which was fixed by renaming the variable "Texture Texture" in the wall struct to "Texture texture" then searching through the file to find all instances in which (somewallvariable)->Texture was being used, and fixed the variable name. For your outdated as anything setup, however, I'm afraid there might be more errors, which is entirely your fault. Update your software.

Goodbytes

TH, I think the word you're looking for is sliver, not slither.

aybabtu: nice textures! The art for Wolfenstein is a lot nicer than I had thought it was... as for lighting, it depends on whether you're using 8-bit colour or hi-colour/true-colour modes. If you're using 8-bit colour, you have to use palette tricks of some sort, and the fastest way is to use a lookup table. If you're using a higher colour depth, you use a lighting function... which are you using?

23yrold3yrold

The Wolfenstein textures are as ugly as I remember :P Anyway, I think I may have licked the crashing someone else was getting, and I changed my DrawSlice() function so now it doesn't dip down to 14 fps if you're up against a wall. Now it stays over 90 at all times, but the texture is a little messed up (I think my math needs a little work). At least the texture doesn't reverse anymore (aybabtu, use a texture with a word on it and see if any of your walls come out with the word backwards). And I can still see slivers of perpendicular walls sticking through some other walls. I would post this in my thread, but it's a day old with the last post being mine, so no one would see it ;) So, here's my latest:

#SelectExpand
1#include <math.h> 2#include <allegro.h> 3 4#define TILE 64 5#define TILESHIFT 6 6#define SCREENWIDTH 320 7#define SCREENHEIGHT 240 8#define M_PI 3.1415926535897932 9#define MAPWIDTH 20 10#define MAPHEIGHT 10 11 12char level[MAPWIDTH][MAPHEIGHT]={ 13{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 14{1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 15{1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 16{1, 0, 0, 0, 0, 0, 0, 0, 1, 1}, 17{1, 0, 0, 1, 1, 1, 1, 1, 1, 1}, 18{1, 0, 0, 0, 1, 0, 0, 0, 0, 1}, 19{1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 20{1, 1, 0, 0, 0, 0, 0, 0, 0, 1}, 21{1, 1, 1, 1, 1, 1, 1, 0, 0, 1}, 22{1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 23{1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 24{1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 25{1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 26{1, 0, 0, 0, 1, 1, 0, 0, 0, 1}, 27{1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 28{1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 29{1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 30{1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 31{1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 32{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}; 33 34int view[SCREENWIDTH]; 35int texture_map[SCREENWIDTH]; 36float px = 65; 37float py = 65; 38float p_old_x = 65; 39float p_old_y = 65; 40int ps = 2; // player speed 41float pa = 1; // player angle 42 43BITMAP* front; 44BITMAP* backdrop; 45BITMAP* texture; 46 47volatile int game_time = 0; 48volatile int fps_timer = 0; 49int fps = 0; 50int num_frames_drawn = 0; 51 52// Timer functions 53void Timer() { 54 ++game_time; 55}END_OF_FUNCTION(Timer); // end Timer() 56 57void FPSTimer() { 58 ++fps_timer; 59}END_OF_FUNCTION(FPSTimer); // end Timer() 60 61// float cast_ray(int x, int y, float a); 62float CastRay(int xpos, int ypos, double angle, int& t); 63void draw_view(); 64void do_raycasting(); 65bool collisions(); 66void DrawSlice(BITMAP* buffer, BITMAP* texture, int xoff, int x, int y, int tall); 67 68int main() 69{ 70 allegro_init(); 71 install_keyboard(); 72 set_color_depth(16); 73 set_gfx_mode(GFX_AUTODETECT, SCREENWIDTH, SCREENHEIGHT, 0, 0); 74 text_mode(-1); 75 76 LOCK_VARIABLE(game_time); 77 LOCK_VARIABLE(fps_timer); 78 LOCK_FUNCTION((void*)Timer); 79 LOCK_FUNCTION((void*)FPSTimer); 80 install_int_ex(Timer, BPS_TO_TIMER(120)); 81 install_int_ex(FPSTimer, BPS_TO_TIMER(1)); 82 83 front = create_bitmap(SCREENWIDTH, SCREENHEIGHT); 84 backdrop = create_bitmap(SCREENWIDTH, SCREENHEIGHT); 85 86 for(int i = 0 ; i < SCREENHEIGHT / 2 ; ++i) hline(backdrop, 0, i, SCREENWIDTH, makecol(200, 200, 255 - i)); 87 rectfill(backdrop, 0, SCREENHEIGHT / 2, SCREENWIDTH, SCREENHEIGHT, makecol(0,100,0)); 88 BITMAP* temp = load_bitmap("texture.bmp", NULL); 89 texture = create_bitmap(64, 64); 90 rotate_sprite(texture, temp, 0, 0, itofix(192)); 91 destroy_bitmap(temp); 92 93 while(!key[KEY_ESC]) 94 { 95 // clear(front); 96 blit(backdrop, front, 0, 0, 0, 0, SCREENWIDTH, SCREENHEIGHT); 97 do_raycasting(); 98 draw_view(); 99 100 /* 101 // draw the little compass/circle 102 line(front, 160, 120, 160 + (int)(25 * cos(pa)), 120 + (int)(25 * sin(pa)), makecol(0, 0, 255)); 103 line(front, 160, 120, 160 + (int)(25 * cos(pa - 0.523598)), 120 + (int)(25 * sin(pa - 0.523598)), makecol(255, 255, 0)); 104 line(front, 160, 120, 160 + (int)(25 * cos(pa + 0.523598)), 120 + (int)(25 * sin(pa + 0.523598)), makecol(255, 255, 0)); 105 circle(front, 160, 120, 25, makecol(255, 0, 0)); 106 textout_centre(front, font, "N", 160, 85, makecol(0, 0, 255)); 107 */ 108 109 ++num_frames_drawn; 110 if(fps_timer) 111 { 112 fps = num_frames_drawn; 113 fps_timer = num_frames_drawn = 0; 114 } 115 116 textprintf(front, font, 15, 5, makecol(0,0,255), "FPS: %d", fps); 117 118 // vsync(); 119 blit(front, screen, 0, 0, 0, 0, SCREENWIDTH, SCREENHEIGHT); 120 121 while(game_time > 0) 122 { 123 if(key[KEY_A]) 124 { 125 px -= (ps * cos(pa - M_PI / 2)); 126 py -= (ps * sin(pa - M_PI / 2)); 127 } 128 if(key[KEY_D]) 129 { 130 px += (ps * cos(pa - M_PI / 2)); 131 py += (ps * sin(pa - M_PI / 2)); 132 } 133 if(key[KEY_LEFT]) pa += 0.02; 134 if(key[KEY_RIGHT]) pa -= 0.02; 135 if(key[KEY_UP]) 136 { 137 px += (ps * cos(pa)); 138 py += (ps * sin(pa)); 139 } 140 if(key[KEY_DOWN]) 141 { 142 px -= (ps * cos(pa)); 143 py -= (ps * sin(pa)); 144 } 145 if(collisions() == true) 146 px = p_old_x, py = p_old_y; 147 148 p_old_x = px, p_old_y = py; 149 150 if(pa < 0) pa += M_PI * 2; 151 if(pa > M_PI * 2) pa -= M_PI * 2; 152 153 --game_time; 154 } 155 } 156 157 destroy_bitmap(front); 158 destroy_bitmap(texture); 159 destroy_bitmap(backdrop); 160 161 return 0; 162} 163END_OF_MAIN() 164 165void do_raycasting() 166{ 167 double angle = pa + 0.523598; 168 169 for(int i = 0 ; i < SCREENWIDTH ; ++i) 170 { 171 // get the distance of the ray 172 view<i> = (int)(cos(angle - pa) * CastRay((int)px, (int)py, angle, texture_map<i>)); 173 if(!view<i>) view<i> = 1; 174 175 // increment the angle 176 angle -= 1.04719 / SCREENWIDTH; 177 if(angle < 0) angle += M_PI * 2; 178 } 179} 180 181void draw_view() 182{ 183 int tall = 0; 184 185 for(int i = 0 ; i < SCREENWIDTH ; ++i) 186 { 187 tall = (int)(64.0 / view<i> * 277.0); // * (SCREENHEIGHT / 320); 188 // stretch_blit(texture, front, texture_map<i>, 0, 1, 64, i, (SCREENHEIGHT - tall) / 2, 1, tall); 189 DrawSlice(front, texture, texture_map<i>, i, (SCREENHEIGHT - tall) / 2, tall); 190 } 191} 192 193bool collisions() 194{ 195 return (bool)level[(int)px >> TILESHIFT][(int)py >> TILESHIFT]; 196} 197 198float CastRay(int xpos, int ypos, double angle, int& t) { 199 // initialize (X_Ycheck, X_Xcheck) with first vertical wall and 200 // (Y_Ycheck, Y_Xcheck) with the first horizontal one 201 float X_Ycheck, X_Xcheck, Y_Ycheck, Y_Xcheck; 202 float X_Yinc, X_Xinc, Y_Yinc, Y_Xinc; 203 204 // hacka hacka hacka .... 205 // if(angle < 0.01 && angle > 0) angle = 0.01; 206 // if(angle < M_PI + 0.01 && angle > M_PI) angle = M_PI + 0.01; 207 // if(angle < M_PI && angle > M_PI - 0.01) angle = M_PI - 0.01; 208 209 double tangent = tan(angle); 210 if(tangent >= 0.0 && tangent < 0.004) tangent = 0.004; 211 if(tangent <= 0.0 && tangent > -0.004) tangent = -0.004; 212 // if(tangent > 9999) tangent = 9999; 213 // if(tangent < -9999) tangent = -9999; 214 215 // sin(90) == 1; sin(270) == -1 216 if(sin(angle) > 0) // The y-values are increasing 217 // if(angle > 0 && angle < M_PI) 218 { 219 Y_Ycheck = (ypos / 64) * 64 + 64; 220 Y_Xcheck = xpos + (Y_Ycheck - ypos) / tangent; 221 Y_Yinc = 64; 222 Y_Xinc = 64 / tangent; 223 } else { // The y-values are decreasing 224 Y_Ycheck = (ypos / 64) * 64 - 1; 225 Y_Xcheck = xpos + (Y_Ycheck - ypos) / tangent; 226 Y_Yinc = -64; 227 Y_Xinc = -64 / tangent; 228 } 229 230 // check for the walls 231 while(((int)Y_Xcheck >> 6 < MAPWIDTH) && 232 ((int)Y_Ycheck >> 6 < MAPHEIGHT) && 233 ((int)Y_Xcheck >> 6 >= 0) && 234 ((int)Y_Ycheck >> 6 >= 0) && 235 level[(int)Y_Xcheck >> TILESHIFT][(int)Y_Ycheck >> TILESHIFT] == 0) 236 { 237 Y_Xcheck += Y_Xinc; 238 Y_Ycheck += Y_Yinc; 239 } 240 241 // cos(0) == 1; cos(180) == -1 242 // if(cos(angle) > 0) // The x-values are increasing 243 if(angle < M_PI / 2 || angle > M_PI + M_PI / 2) // The x-values are increasing 244 { 245 X_Xcheck = (xpos / 64) * 64 + 64; 246 X_Ycheck = ypos + (X_Xcheck - xpos) * tangent; 247 X_Xinc = 64; 248 X_Yinc = 64 * tangent; 249 } 250 else // The x-values are decreasing 251 { 252 X_Xcheck = (xpos / 64) * 64 - 1; 253 X_Ycheck = ypos + (X_Xcheck - xpos) * tangent; 254 X_Xinc = -64; 255 X_Yinc = -64 * tangent; 256 } 257 258 // check for the walls 259 while(((int)X_Xcheck >> 6 < MAPWIDTH) && 260 ((int)X_Ycheck >> 6 < MAPHEIGHT) && 261 ((int)X_Xcheck >> 6 >= 0) && 262 ((int)X_Ycheck >> 6 >= 0) && 263 level[(int)X_Xcheck >> TILESHIFT][(int)X_Ycheck >> TILESHIFT] == 0) 264 { 265 X_Xcheck += X_Xinc; 266 X_Ycheck += X_Yinc; 267 } 268 269 float xcheck = (X_Xcheck - xpos) * (X_Xcheck - xpos) + (X_Ycheck - ypos) * (X_Ycheck - ypos); 270 float ycheck = (Y_Xcheck - xpos) * (Y_Xcheck - xpos) + (Y_Ycheck - ypos) * (Y_Ycheck - ypos); 271 272 // the ?: stuff in here is to make sure the right texture coordinate is 273 // returned; otherwise, half the textures in the game are reversed 274 if(xcheck < ycheck) 275 { 276 t = (angle < M_PI / 2 || angle > M_PI + M_PI / 2) ? (int)X_Ycheck % TILE : 63 - ((int)X_Ycheck % TILE); 277 return sqrt(xcheck); 278 } 279 else 280 { 281 t = (angle > M_PI) ? (int)Y_Xcheck % TILE : 63 - ((int)Y_Xcheck % TILE); 282 return sqrt(ycheck); 283 } 284} 285 286void DrawSlice(BITMAP* buffer, BITMAP* texture, int xoff, int x, int y, int tall) 287{ 288 int srcy = 0, num = 0; 289 290 // skip down until we hit the top of the screen (for very close walls) 291 if(tall > SCREENHEIGHT) 292 { 293 num = 32 * (tall - SCREENHEIGHT); 294 295 if(num >= tall) 296 { 297 srcy = num / tall; 298 num = num % 64; 299 } 300 301 y = 0; 302 } 303 304 for(int i = y ; i < y + tall ; ++i) 305 { 306 num += 64; 307 308 while(num >= tall) 309 { 310 num -= tall; 311 ++srcy; 312 } 313 314 // if(i < 0) continue; 315 if(srcy >= 64 || i >= buffer->h) return; 316 317 // this assumes the texture is rotated (otherwise it's slower due to cache missing) 318 // ((short *)buffer->line<i>)[x] = (((short*)texture->line[xoff])[srcy] >> 1 & 0x7BEF); 319 ((short *)buffer->line<i>)[x] = ((short*)texture->line[xoff])[srcy]; 320 } 321}

I made a little test for shading the walls and it barely affected the FPS, so I'll probably give depth shading a shot soon ...

Johnny13

23:'for'loop initial declaration used outside C99 mode

Quote:

// check for the walls
while(((int)X_Xcheck >> 6 < MAPWIDTH) &&
((int)X_Ycheck >> 6 < MAPHEIGHT)

you still checking the level[] boundary? use getpixel in Mypost!:P
and plz shorten your code or Attach it! your codebox is now 9.9k! sp4mm3r!;)

and test the FPS yourself:

while(!key[KEY_ESC])
{if(key[KEY_1])mode=0;if(key[KEY_2])mode=1;
 if(mode) for(i=0;i<H;i++)hline(front,0,i,W,(i<H/2)?MC(133,160,255-i):MC(i,i,i));
 else blit(backdrop,front,0,0,0,0,W,H);

Ace

23yrold3yrold: It's not crashing for me anymore (yay!), but it does drop below 90 when I'm next to a wall. To about 60 fps. ;) Maybe my computer is being weird.

- Ace

23yrold3yrold
Quote:

23:'for'loop initial declaration used outside C99 mode

C++ coders care. ;)

Quote:

you still checking the level[] boundary?

Hell yes! Much faster than getpixel(). What would using getpixel() get me anyway?

Quote:

and plz shorten your code or Attach it! your codebox is now 9.9k!

Is that why your code has almost 0 whitespace?

And I am testing the fps myself (or was that directed at aybabtu?) ...

Ace: Cool 8-)

aybabtu

I've attached a .zip with a DOS binary, the source code, and my little texture set. Could you guys test it out and tell me what kind of FPS you get with the "Ray Skip" at 1, and at 5? Use the -/+ butons to change it. It makes it run a lot faster on 5, but you lose detail...I wanna see how fast it runs on ppl's computers.

Goodbytes: I'm using 16bit color. Down with palettes!

J13: That screenshot looks nifty...I kinda like it with the lines on top of the walls!

Zaphos said:

For your outdated as anything setup, however, I'm afraid there might be more errors, which is entirely your fault. Update your software.

Fine...I'll download allegro 4 or the newest WIP or something...
Anywayz, here's the latest code:
(Control view with mouse/arrow keys, move with WASD)

[WHOOPS! The post's too big with it...just download the attachment]

As you can see, I've eliminated another call to the cos() function, by using a table to fix the distortion!

EDIT: 23: Words are backwards on my textures only on certain sides of a cube. 2 sides are right, 2 sides are backwards. I tested it with the all powerful NYAH.

Thomas Fjellstrom

YaY!!! I was waiting for source and some textures :)

edit:
Ok, I get about 30fps normally in XWIN mode, not too shabby. XWIN is like GDI mode in windows.. SLOW. and If I look directly at a wall I get 40fps :) I'd try it in DGA2 mode, but my monitor doesn't do anything less than 640x480.

aybabtu

Are you going to FPS-test mine?

Thomas Fjellstrom

heh, edited.. :)

Goodbytes
aybabtu said:

Goodbytes: I'm using 16bit color. Down with palettes!

Good. Then lighting is easy enough... sorta. I guess. Or something. Yeah. ;D

Anyways, if you want to shade based on depth, as if the player has a light on his/her head or whatever, you'll probably want to shade the ceiling and floor as well as the walls. So, you need to darken your floor/ceiling gradient a little as it reaches the horizon.

Then, as for shading the walls, you can probably just subtract a little from the colour components of each pixel based on how far away it is. Allow me to rip some code from FBlend for a minute.

Okay, here's a sort of example program for ya:

1#include <allegro.h>
2 
3int main()
4{
5 allegro_init();
6 set_color_depth(16);
7 set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0);
8 install_keyboard();
9 
10 BITMAP* src = load_bitmap("src.bmp", 0);
11 BITMAP* dst = create_bitmap(src->w, src->h);
12 
13 // Important part #1: light levels
14 unsigned long lightlevel[32];
15 for(int i = 0; i < 32; ++i)
16 {
17 lightlevel<i> = (i | (i << 11) | (i << 22));
18 }
19 
20 int distance = 0;
21 
22 while(1)
23 {
24 // Important part #2: subtractive lighting
25 for(int y = 0; y < src->h; ++y)
26 {
27 for(int x = 0; x < src->w; ++x)
28 {
29 unsigned long c = _getpixel16(src, x, y);
30 unsigned long res;
31 c = ((c << 16) | c) & 0x7C0F81F;
32 c -= lightlevel[distance];
33 res = c & 0x8010020;
34 res -= (res >> 5);
35 c &= ~res;
36 c &= 0x7C0F81F;
37 c |= (c >> 16);
38 c &= 0xFFFF;
39 _putpixel16(dst, x, y, c);
40 }
41 }
42 
43 textprintf(screen, font, 0, 0, makecol(255, 255, 255), "Distance: %2d. [Q] to quit, [A] & [Z] to control distance. %d", distance, lightlevel[31]);
44 draw_sprite(screen, dst, 0, 10);
45 
46 clear_keybuf();
47 int k = readkey() & 0xff;
48 if(k == 'q')
49 break;
50 else if(k == 'a')
51 ++distance;
52 else if(k == 'z')
53 --distance;
54 distance = MID(0, distance, 31);
55 }
56}
57END_OF_MAIN();

This is C++ code, so compile it as so.

The two parts to note are the creation of the light table, and the actual subtractive blending parts, which are commented as important parts numbers one and two, respectively.

Now, credit must go to Bob for actually writing the subtractive blending part in FBlend, which I modified a teensy bit. The rest of the program is my fault. :)

Actually, I think it works well. Make a small bitmap called src.bmp, compile this, and put them in the same directory, and try it out yourself.

Anyhow, now on to how it works. It's kind of hard to explain... basically, in the subtractive blending part, the color is grabbed from the source bitmap(you should use a faster method than _getpixel16 if possible, btw) and then the individual colour components are separated apart, so where originally the binary representation of the colour looks like this:
OOOOOOOOOOOOOOOORRRRRGGGGGGBBBBB // 16-bit colour on a 32-bit int, 5 bits for red, 6 for green, 5 for blue
it gets transformed to look like this:
OOOOOGGGGGOOOOOORRRRROOOOOOBBBBB // 16-bit colour on a 32-bit int, but spread apart, and 5r5g5b instead of 5r6g5b
The lightlevel[] array is set up to match the above representation for 32 levels of light... for example, lightlevel[31] looks like this:
OOOOO11111OOOOOO11111OOOOOO11111 // 11111 = decimal 31 - for each colour component
Then, the light level is subtracted from the source colour, put back together into the packed 565 format, and drawn onto the destination bitmap. Again, use direct bitmap access instead of _putpixel16.

This is basically the same thing as doing

unsigned int r, g, b, c;
c = _getpixel16(src, x, y);
r = getr16(c); g = getg16(c); b = getb16(c);
r -= distance; g -= distance; b -= distance;
c = makecol16(r, g, b);
_putpixel16(dst, x, y, c);

But hopefully faster.

Finally, remember that since you only have 32 distance values, try to spread them out a little - i.e. you would probably want a slice that's 32 'pixels' away to actually be quite bright. In fact, you can probably map distance in 'tile units' - i.e. with a slice that is 1 tile length away being a distance value of 1.

Hope this helps.

23yrold3yrold
Quote:

EDIT: 23: Words are backwards on my textures only on certain sides of a cube. 2 sides are right, 2 sides are backwards. I tested it with the all powerful NYAH.

That's what happened to me. My latest code up there corrects this.

Quote:

YaY!!! I was waiting for source and some textures

Dude, that's all we've been posting ;)

Sweet mother, aybabtu, why does your code run at 0 FPS?!? :P Seriously, I thought it froze my computer. I haven't looked at your code yet to see what's wrong, but it's literally unplayable. Exited via crash. BTW, have you tried my latest? I get 150 FPS, dunno what that comes to on your box ...

BTW, if you aren't texturing the floor or roof, gradient shading becomes very easy ;D

Thomas Fjellstrom
Quote:

Dude, that's all we've been posting

Sory, didnt notice any textures. :P I compiled and ran a previous version of somebodys and it crashed :o I was about to report it, but realize that it was because using a NULL bitmap doesn't work to well.

Trezker

I've done some bugfixes and other stuff.
I don't know how things are with the M_PI define you complained about, it compiles fine here.
Have a look and do as you wish.

23yrold3yrold

I used my own texture. Just throw a 64x64 truecolor texture in with the executable and you're good to go. Try it with mine; how's it work for you?

Thomas Fjellstrom

Textures? I don't have no stinkin textures. Really. (um.. you want me to try yours now? demands... sheesh :P)

23yrold3yrold

I don't have any texture either; I just drew some scribbles in MSPaint ;D

Thomas Fjellstrom

;D. Ok, I forgot to mention, my fps that I reported was totally unoptimized, and unaccelerated, windowedmode... I'll try that other one again, just optomized...

edit: ok that wolf one is like 50-60 fps now...

edit: ok, yours chris :o 300fps. in 320x240. in XWIN mode.. I'll see what DGA mode does.. (cause aparently, my monitor can do 320x240... I thought it couldn't)

edit: more updates... with DGA it hits 300-370 (400 at max) fps, and at 640x480 in DGA mode, I get 80-100fps.

23yrold3yrold

BTW, can anyone help with this little bit of math? The if statement is to skip the offscreen pixels (HUGE fps boost) but it messes up the texture a bit. I've attached a screenshot which demonstrates this ...

1 
2void DrawSlice(BITMAP* buffer, BITMAP* texture, int xoff, int x, int y, int tall)
3{
4 int srcy = 0, num = 0;
5 
6 // skip down until we hit the top of the screen (for very close walls)
7 // this bit is currently a little buggy ...
8 if(tall > SCREENHEIGHT)
9 {
10 num = 64 * ((tall - SCREENHEIGHT) / 2);
11
12 if(num >= tall)
13 {
14 srcy = num / tall;
15 num = num % 64;
16 }
17
18 y = 0;
19 }
20
21 // draw that slice!
22 for(int i = y ; i < y + tall ; ++i)
23 {
24 num += 64;
25
26 while(num >= tall)
27 {
28 num -= tall;
29 ++srcy;
30 }
31
32 if(srcy >= 64 || i >= buffer->h) return;
33
34 // this assumes the texture is rotated (otherwise it's slower due to cache missing)
35 // ((short *)buffer->line<i>)[x] = (((short*)texture->line[xoff])[srcy] >> 1 & 0x7BEF);
36 ((short *)buffer->line<i>)[x] = ((short*)texture->line[xoff])[srcy];
37 }
38}

See anything wrong with that first half of the function?

Thomas Harte
Quote:

TH: Could you compile it into a binary? My DJGPP complains about MANY "errors". I tried fixing some, but I just gave up. How smooth is it? Would you think that you were in a raycaster when you're running it? What is a 2D portal engine?

Portal engines work on the principle of sectors. For my engine, a sector is a convex room. Some of the walls are thought to be portals. In ray casting terms of thought, when a ray hits a portal, it carries on through the portal into another sector rather than deciding that it has hit a wall.

To do all this, the engine knows which sector the player is currently in, and works on the following (pseudo-code) draw loop:

function DrawSector(s)
{
   for(all non-portal walls in sector)
      draw walls to the display

   for(all portals)
   {
      calculate area of screen that portal would cover if it were a solid wall
      call DrawSector with the connected sector, specifying to restrict to that area of wall
   }
}

Because the sectors are convex, if we know the start sector, this gives a no-overdraw front to back draw.

I shall try to dust off a copy of DJGPP and compile my code. It was developed on MSVC so I may have inadvertently used some Microsoft extensions (e.g. unnamed structs) without realising...

Quote:

TH, I think the word you're looking for is sliver, not slither.

Nah, its all to do with the first tutorial I read about Wolfenstein type things, many years ago, which compared them to snakes (don't ask).

MiquelFire

Chris: Where's yours? I don't have a compiler here at work (and don't feel like setting one up here)

23yrold3yrold

Okay, I'm attaching a zip with makefile, source, Win32 binary and texture file (32KB).

Zaphos

23: Your code stays over 150 on my computer even near walls, and tends to be >200 ... very nice! I can't really see the glitches you're talking about, though, so I can't really comment on what might be causing them. Perhaps you could post a screenie of a pronounced glitch? (Heh, you could even check miran's screenie module in the early modules submission thread to do it ...). This test result is from using your latest code posted in this thread, which is quite a few posts up, actually, so I guess you may have made progress since then.

EDIT: Gah! I idle a bit and look what happens ... takes me 20 minutes to write this post and to test 23's code and sooo many people have already posted. It's not being beaten ... it's being completely demolished :o

23yrold3yrold

I did post a screenshot (5 posts up) as an attachment. Guess you missed it, dawdle-boy ;). It will show up on any wall that is a) taller than the screen, and b) at an angle (you won't see it if you're standing facing straight at the wall).

Zaphos

For reference, to document the worst beating I've seen yet: the last post in this thread when I wrote the above response was TF saying:

Quote:

Textures? I don't have no stinkin textures. Really. (um.. you want me to try yours now? demands... sheesh )

Thomas Fjellstrom

Actually if you face the wall right up close, the ray infront gets quite abit bigger than it should, if you take a look at the size of the rays around it..

MiquelFire

23: Stays over 260 with this 1.70GHz machine I have here at work. When not close to a wall, I get around 313.

aybabtu: 2000 don't like DOS apps :(, so I couldn't test it here.

Will do a test at home on my 600 MHz system (which, I assume because of RAM and other network stuff, run laps around this computer :P)

23yrold3yrold

TF: If that's directed at me, I'm not seeing it ...

If Matthew closes this thread for length, I'd like to start another one, because I'd really like some help with those texture errors :-/ EDIT: nm, I just did ;)

aybabtu
Thomas JelloStorm said:

edit: ok that wolf one is like 50-60 fps now...

Yay! What's your system?

Goodbytes: Thanks...I'll try that stuff out tonight or something...

23: Your new code skips off screen pixels! Yay! Maybe even more FPS!

Miquel: Sorry it's DOS! I don't have MinGW or anything, but it shouldn't be hard to compile...you should just have to stick END_OF_MAIN in there.
On a 600Mhz system...you should get nice numbers. On my 233, I get ~20 frames...and with TF getting 50-60! Ah...life is good.:P

MiquelFire

Ahem I went over this already.

Thomas Fjellstrom

23: darned. well, it seems that must have been a fluke, or only happens in very rare circumstances... but I did see something else thats a bit odd.. hard to explain, just that I found if you're standing right up to a wall, and turn back and forth a bit the colors on the texture move :o In the attached image, notice the green, almost teal color, now If I use the arrow keys to look side to side, that teal grows and shrinks in size, after a bit of looking left, it totally disapears and the colors underneath takeover. weird.

Quote:

Yay! What's your system?

Athlon 900.

MiquelFire

You forgot the image TF

Thomas Fjellstrom

:o crap :(

sory ;)

and by green, almost teal, the two blocks, one at the top, and one at the bottom...

23yrold3yrold

Yikes O_o I see nothing like that when I'm playing ... just nice gray walls ...

aybabtu
23 said:

Sweet mother, aybabtu, why does your code run at 0 FPS?!?

Um...did you run the binary or compile the code? The binary is a DOS binary (DJGPP, remember?), so if you have winXP or 2000 or something, it probly won't work.:P

23yrold3yrold

I ran the binary, and use Win98.

Peter Hull

Chris, Can you explain what you're doing in DrawSlice? I can't figure it out (my fault :P )
I got similar fps on my system with just

void DrawSlice(BITMAP* buffer, BITMAP* texture, int xoff, int x, int y, int tall)
{
  stretch_blit(texture, buffer, xoff, 0, 1, 64, x, y, 1,tall);
}

but I may not have compiled yours with the correct optimisation. Also it rotated the textures by 90 compared to yours.

Pete

Trezker

I compared your raycaster with mine.
Wolf, 64 fps max
Me, 400 fps max
I'm a little happy here. :)
BTW, the binary worked fine here, XP.

And my engine has quite a bit of usefull features you might want to have a closer look at.

23yrold3yrold

I get better fps my way over using stretch_blit() (about 50% better). The rotation is because I treat rows like columns in DrawSlice() due to Bob's suggestion. Otherwise I'm doing evil cache missing or something :P ;)

Anyway, DrawSlice is based off my Bresenham line drawing code to step through the column pixels and get the right texture pixel to draw. It's not too difficult to figure out, methinks. If it still confuses you, post in my "Math help, please" thread since this one's getting a little long :)

Trezker: Yes, I should look at your code closer; thanks for reminding me :)

Thomas Fjellstrom

So, have you figured out whats up with the funky colors? Since you say its supposed to be shaded?

23yrold3yrold

I took the shading out of that code, TF. I don't see that for the life of me when I run it. Can't duplicate the error at all. Are you using my gray stone texture?

Trezker

Nice, the stretch_blit is tha main bottleneck in my code. That's why I don't let the player closer than 2 units, each block is 64, from the walls. If I use a better method, it'll do alot.

Thomas Fjellstrom

what grey stone texture? :P

23yrold3yrold

The one in my last zip (at miran's request)?

aybabtu
Quote:

I compared your raycaster with mine.
Wolf, 64 fps max
Me, 400 fps max
I'm a little happy here.

Hey...so am I! I know my casting method is far from the best, but 50-64 FPS is fine by me. Wow...400? You're useing the "right" method, huh? I'm gonna check out your source...

23 said:

I ran the binary, and use Win98.

Geez! That's crazy! It runs on both my old 586 (Win95) and my family's computer (Win98SE). Crazy...

Steve Terry

hey just tested it, looks great, but you may want to actually put a fps limiter on there to make it always run at 60fps or something, because when I'm moving around you don't go forward smoothly, for instance you go around a corner where the fps goes from 60 to 90, you run into it because a sudden change in velocity. Anyway nice little demo :)

aybabtu

Holy CRAP! A 30 frame jump! Wow...didn't think I'd see the day...well okay! If it's becomming a problem, I'll put a limit...! YAY!

I think I've coaxed another frame per second out of it. In my raycasting while loop, I had it testing to see if the_x and the_y were hitting a tile, but, if they do, the inside of the loop catches it and breaks out of it. So, I eliminated 2 divisions (well, shifts), and a usless conditional...it runs a little bit faster...I think.

EDIT:
How accurate should PI be? I mean, after the first 10 decimal places...it should be pretty usless, right? Or should I have as many as I can?

Ace

Pfffft, PI.... round that thing down to 3 and call it a day. ;)

Seriously though, using a long PI will definately give you more precision, there's only show much precision that's going to show up. Ten decimals should be plenty, probably overkill.

Edit: Dear lord... I'm going to have nightmares about pi tonight. In it, I'm going to be traveling through a raycasted dungeon and I'll run into various 2^1/2 enemies and when I finally get to the boss room, PI will be standing in the middle of it, carrying a missle launcher. Too bad I'm out of bullets and I'm done to 5% health.

- Ace

aybabtu
Quote:

Pfffft, PI.... round that thing down to 3 and call it a day.

Heheheheh.
3*10=30
3.14*10=31.4
-OR-
3*100=300
3.14*100=314
Quite a difference...;):P

EDIT: How long with Matthew let a thread go to...I see that Bruce Perry's "My avatar" thread is well over 200...

EDIT2:

Quote:

Dear lord... I'm going to have nightmares about pi tonight.

Yes! How dare you insult teh almighty PI!? Round down to 3...bah!

23yrold3yrold

Well, this thread is still on-topic :) I'm moving on to Tetris Attack for a while myself; I'll come back to this later ...

Thomas Harte
Quote:

Anyway, DrawSlice is based off my Bresenham line drawing code

Wolfenstein uses the broad equivalent of compiled sprites for every possible sized slice of every possible texture. But I'd dare imagine it uses some super-clever assumptions about run length stuff which Allegro does not with its compiled sprites - or else it couldn't possibly fit all that code into memory.

How many different textures does the average Wolfenstein level have?

And has this thread yet discussed the ways of inserting sprites and doors into the world?

23yrold3yrold
Quote:

And has this thread yet discussed the ways of inserting sprites and doors into the world?

Unfortunately, no.

Zaphos

Well, a very primative technique of drawing a baddie would be to:
1) keep an array of distances to walls
2) Use the x/z, y/z formula to determine the sprite's midpoint location, and the size/z formula to determine how much to scale it -- to do this, of course, you need to rotate the x,y,z so z+ or z- is away from you (pending left or right hand coordinate system)
3) Draw the sprite slice by slice, comparing its z to the wall array's z for each slice
4) For each slice you draw, fill in the corresponding spot in the wall array with the sprite's z so that later sprite draws layer correctly.

Of course, this technique is designed with same-height enemies in mind, and cannot have a taller enemy peeking over a wall or another baddie. But then, it's probably good enough for your average wolfenstein clone.

23yrold3yrold

Actually, I would just draw the enemies back to front, since you can see one enemy behind another because of transparency. You're keeping an array of distances to walls anyway, just grab all the enemies in your line of sight, get distances, draw back-to-front slice by slice, and I guess you got it.

Karel

I get around 70 fps with 1 frameskip and over 200 fps with 5 frameskips, with and without vync. 'Course, I'm on an Athlon 1800+ ;D

Zaphos

23: Oh, right. Heh, silly me and my rectangular enemies.

23yrold3yrold

Just populate your dungeon with giant cube slimes, Z ;D

aybabtu

I'm gonna work on drawing objects soon. I can't get the engine to run much faster, so I'm gonna move on. Should be pretty easy. Just use the distances in the view[] variable, and compare it's distance...I think.

Thomas Harte

Yeah. And in my portal engine you only need consider objects which overlap with sectors that were actually visited, so you usually end up considering less objects than a ray caster!

aybabtu

Thomas Harte: Can you attach a binary of your portal engine? I can't get it to compile with my version of allegro (3.11...bleh!) and DJGPP...

Thomas Harte

Oh, yeah, I'm going to get on top of that as soon as I get a working DJGPP install. Or are you happy with a Windows binary?

aybabtu

A windows binary is fine...but I'd prefer a DOS one, because sometimes I can't get the windows ones to work even on 98SE!

Karel

Aren't you taking my quote a bit out of context aybabtu? 8-)

23yrold3yrold

Now, what framerate did you get with mine? ;)

Karel

It says ~480 fps :o.

This is a really cool engine, if you'd improve it maybe you could make a Build-like engine, that would be awesome. Build > *.

Steve Terry

23: did you ever fix your rendering error? It really looks great though, and yeah I get excellent fps with your demo :) I hope you can work out the kinks, but another great idea is to have the player move slowly if up against the wall proportional to his angle. For instance instead of stopping once you hit a wall at 10 degrees offcenter then move slowly in that direction instead of a dead stop. Of course if the player hits perpendicular to a wall then his velocity will by 0.

23yrold3yrold

I already fixed the hit-wall-and-stop-dead thing in my other thread (which anyone is welcome to bump ;)). I detailed the finalest of final texture errors there, but I can't lick it. I put it away for now; I'm finishing my Tetris Attack clone right now, then I'm going back to The Mighty Stoopid. If someone wants to help me, I won't turn them down ;)

See fourth last post here for my latest progress. And thanks for the compliments :)

aybabtu

I got MinGW up and running, and today I'm getting Allegro going...so I won't be the only person that can play my binaries!
Karel: Well...um...heheheh...no.

Thomas Harte

Attached is a compiled and slightly fixed version of my 'not really raycasting' engine, along with source, alleg40.dll and everything else you need to use it. It runs at 800x600, keeping up with the frame rate of 60fps on my little celeron 533Mhz.

I'm aware that in a few cases (most notably on the very right edge of walls) slivers do not appear. I'm sure I could fix that. Also I'm aware that I don't really need cos and tan tables across an entire circle because cos(a) = -cos(-a) and tan(a+ half circle) = tan(a). That wouldn't take terribly long to fix.

aybabtu

Cool, Thomas! I only get about 10-16 fps depending on how close I am to a wall (the closer, the slower).

Thomas Harte

How does 10-16fps compare with the other alternatives when running at 800x600? In any case, the good news is that I've fixed all rendering errors this afternoon and sped things up about 10% by replacing every instance of 'fmul' with 'fixmul'.

EDIT: to put things in perspective, 800x600 (8bit) is 468.75kb. 320x200 (15/16bit) is just 125kb. And, comparitively, you get half the byte computations for free.

aybabtu

10-16 fps is pretty good because I get 11-18 on my 320x200 raycaster!

Zaphos

23's seems to only get 45 fps when I make it 800x600, and has a minor graphical glitch in the background. Then again, he is drawing some pretty sky gradient or something in the top, so maybe that's just really really slow ... but I think we can probably say that yours is faster, TH. Especially because 60 is the refresh rate of my monitor ;D
Those occassionally invisible slices of wall are kinda annoying though. Fixing that would be cool.

23yrold3yrold
Quote:

23's ... has a minor graphical glitch in the background.

Yes, and I hate it with all my being. It doesn't show up in nice low resolutions though ;)

Carrus85

I hate to be satins advocate, but shouldn't you guys start up another thread? This one is getting REAL crowded, it is kinda nice not having to sift through all of the pages.

23yrold3yrold

Whenever Matthew closes it, we'll all pile into Aybabtu's Depot thread ;)

gnolam

Use the lightbulb, Luke :)

(or change My Profile->Forums->General->Page Splits to a setting that you like)

aybabtu
Quote:

I hate to be satins advocate, but shouldn't you guys start up another thread? This one is getting REAL crowded, it is kinda nice not having to sift through all of the pages.

I have my pages set to 25ppp, and I like it. I don't think it's crowded...pages are such a nice feature for dial up users who's modems are crapping out and only connect them at 21.6 kbps...bleh.

Quote:

Whenever Matthew closes it, we'll all pile into Aybabtu's Depot thread

Well, you're all very welcome! How long is the longest thread ever? >225 posts, I think.

Thread #275744. Printed from Allegro.cc