- Online Community Forums » Programming Questions » how to draw sprites in a raycasting engine?

This thread is locked; no one can reply to it. rss feed Print
how to draw sprites in a raycasting engine?
Bill Hogan
Member #4,578
April 2004

can anyone give me some information on how to draw moving sprites in a raycasting engine? i have the engine working...but i can't seem to get sprites working 100% of the time. any help is much appreciated.

David Layne
Member #2,053
March 2002

Well, the basic idea is to just transform the sprite to onscreen coordinates and then draw it in vertical z-buffered slivers.

To do this, first compute the angle between the player and the sprite using some atan2 calls. Then you can transform this to screen coordinates by comparing this angle to the view angle of the player.

Basically, here is the idea. Lets say your player has a 60 degree field of view, and the view angle is currently 90 degrees (so the rays that are cast range from 120 degrees for the leftmost screen collumn and 60 degrees for the rightmost collumn). This means that we can assign each x coordinate on the screen a corresponding theta. Our goal is to figure out what the angle the player would have to be facing to be looking directly at the sprite, and then transform that angle into screen coordinates and draw the sprite.

Assuming your sprites are all centered vertically, you only need the x coordinate on screen. The code I use to transform sprites in Wormenstein is as follows:

1// Try to render a sprite
2xInc = (theSprites<i>.x - x); // theSprites<i>.x = sprites x coordinate in game world, x = player's x coordinate in world
3yInc = (theSprites<i>.y - y); // Same as above
5thetaTemp = atan2(yInc, xInc); // Find angle between player and sprite
6thetaTemp *= degreeConverter; // Convert to degrees
7if (thetaTemp < 0) thetaTemp += 360; // Make sure its in proper range
9// Wrap things around if needed
10yTmp = theta + 30 - thetaTemp; // Theta + 30 = angle of ray that generates leftmost collum of the screen
11if (thetaTemp > 270 && theta < 90) yTmp = theta + 30 - thetaTemp + 360;
12if (theta > 270 && thetaTemp < 90) yTmp = theta + 30 - thetaTemp - 360;
14// Compute the screen x coordinate
15xTmp = yTmp * w / 60.0;

In that code block, theta is the player's view angle, thetaTemp is just a float, degreeConverter is a constant you multiply an angle in radians by to convert to degrees (180/pi), and xTmp, yTmp, xInc, and yInc are all just floats. The variable w is the width of the screen in pixels. Note that for this to work, theta must be >= 0 and < 360, so make sure you guarntee that it is in that range first. If you want to change the field of view, change the 60 to fov and the 30s to fov/2. However, if you set the fov too high you will have to modify the if statements to wrap things around correctly.

The if statements are to deal with cases where the magnitude of the angles is small but the angles are far apart (like 1 degree and 359 degrees. You cant just subtract them, you need the interior angle). This code is also for a fixed FOV of 30 degrees, which is where the +30s and the 60 in the last line come from.

At the end of that code block, xTmp will hold the x value of the center of the sprite in screen coordinates, so subtract half the sprite's width to find the left side x coordinate.

You will of course need to compute the distance from the player to the sprite to find out how much to scale the sprite by, but that code will transform the sprite into screen coordinates.

Note that you will have do draw the sprites in back to front order for them to be drawn correctly. To do this i just add the x, y screen coordinate of each sprite along with its size and frame number as I go along, and then sort the vector by scale going from least to greatest and then render them all.

Once you get sprite rendering going, let me know and i'll give you a few suggestions for speeding things up if you need help there.

Member #3,463
April 2003

code tag me if you can

[nonnus29]Plus the api is crap ... I'd rather chew broken glass then code with those.

Kitty Cat
Member #2,815
October 2002

Could always use quad3d w/ POLYTYPE_ATEX_LIT_MASKED(_MASKED_LIT?)...

"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Bill Hogan
Member #4,578
April 2004

Thank you very much for the information, David! However, for some reason, I'm still have trouble with this. Here is my code:

1void draw_object (BITMAP *bmp, BITMAP *obj, float angle, float x, float y)
3 float xInc = (64 - x);
4 float yInc = (128 - y);
5 float thetaTemp = atan2(yInc, xInc);
6 thetaTemp *= 180/M_PI;
7 if (thetaTemp < 0) thetaTemp += 360;
8 float yTmp = angle + 30 - thetaTemp;
9 if (thetaTemp > 270 && angle < 90)
10 yTmp = angle + 30 - thetaTemp + 360;
11 if (angle > 270 && thetaTemp < 90)
12 yTmp = angle + 30 - thetaTemp - 360;
14 float xTmp = yTmp * 320 / 60.0;
15 draw_sprite(bmp,obj,xTmp,10);

For some reason, xTmp is holding some strange values (all negative??) Any idea what I'm doing wrong here?
Again, thank you very much for the help. :)

David Layne
Member #2,053
March 2002


A few points. First of all, you do realize that by drawing the sprite with the draw_sprite() function, the sprites will not be scaled nor will they be drawn with zbuffering, right? I assume you are just doing this to test the sprite code, and plan to change it later.

The first thing you should do is make sure that angle is >= 0 and < 360, so add these lines to the top of the function:

while (angle < 0) angle += 360;
while (angle >= 360) angle -= 360;

Also, you might be having problems if your using a different coordinate system than I am. My engine is designed to run in the first quadrant of the cartesian plane, and I have 90 degrees defined as looking directly parallel to the y axis. If your engine is using a different systems, you could be having problems.

Also, I assume that your using degrees for your angle measurements? If not, your going to have to convert everything to degrees.

If your still having trouble with this, and you don't mind posting your source code, I'd be glad to look through the whole program and try to figure out where the problem is.


Go to: