Sign in to follow this  

Raycasting Engine

This topic is 2664 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I want to learn how to make a first person shooter using raycasting, so I made this program to see if I could get the basic things like rendering walls and collision detection working. However, when I run the program, the screen fills entirely with the "default" wall color (which, according to my map, is never used). Another thing that I noticed is that the program is very slow, it gets about 1 frame per second on my laptop.

Edit: here's some links to the tutorials I used
http://www.permadi.com/tutorial/raycast/
http://www.student.kuleuven.be/~m0216922/CG/raycasting.html

Here is the entire source code (Edit: code tags don't do anything in this forum?):

//standard libraries
#include <stdio.h>
#include <math.h>

//SDL media library
#include "SDL/SDL.h"

//defines
#define PLAYER_HEIGHT 32
#define FOV 0.66 //not the actual FOV, but PLANE_Y (2 * atan(FOV/1.0) = 66)

#define PROJECTION_PLANE_WIDTH 320
#define PROJECTION_PLANE_HEIGHT 200

#define MAP_WIDTH 24
#define MAP_HEIGHT 24

int MAP[MAP_WIDTH][MAP_HEIGHT]=
{
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,2,2,2,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1},
{1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,3,0,0,0,3,0,0,0,1},
{1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,2,2,0,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,0,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};

int main(int argc, char *argv[]) {
if (SDL_Init(SDL_INIT_EVERYTHING) == -1) {
printf("SDL failed to initialize. Is SDL installed correctly?\n");
return 1;
} else {
printf("SDL initialized.\n");
atexit(SDL_Quit);
}

SDL_Surface *screen = SDL_SetVideoMode(PROJECTION_PLANE_WIDTH, PROJECTION_PLANE_HEIGHT, 8, SDL_SWSURFACE);
if (screen == NULL) {
printf("Failed to set video mode.\n");
return -1;
} else {
printf("Video mode set.");
}

SDL_WM_SetCaption("Raycaster", NULL);

//define some varibles for the player and camera
double POS_X = 24, POS_Y = 12; //start position
double DIR_X = -1, DIR_Y = 0; //initial direction vector
double PLANE_X = 0, PLANE_Y = FOV; //camera plane

//start an infinite loop
bool RUNNING = true;
while (RUNNING) {
//the loop where the actual raycasting and rendering is done
for (int x = 0; x < PROJECTION_PLANE_WIDTH; x++) {
//calculate ray position and direction
double CAMERA_X = 2 * x / double(PROJECTION_PLANE_WIDTH) - 1; //x coordinate in camera space

double RAY_POS_X = POS_X;
double RAY_POS_Y = POS_Y;

double RAY_DIR_X = DIR_X + PLANE_X * CAMERA_X;
double RAY_DIR_Y = DIR_Y + PLANE_Y * CAMERA_X;

//determine which map box we're in
int MAP_X = int(RAY_POS_X);
int MAP_Y = int(RAY_POS_Y);

//length of ray from current position to next x or y side
double SIDE_DIST_X;
double SIDE_DIST_Y;

//length of ray from one x or y side to the next x or y side
double DELTA_DIST_X = sqrt(1 + (RAY_DIR_Y * RAY_DIR_Y) / (RAY_DIR_X * RAY_DIR_X));
double DELTA_DIST_Y = sqrt(1 + (RAY_DIR_X * RAY_DIR_X) / (RAY_DIR_Y * RAY_DIR_Y));
double PERP_WALL_DIST;

//which direction to step (either 1 or -1)
int STEP_X;
int STEP_Y;

bool HIT; //was a wall hit?
bool SIDE; //was a NS or EW wall hit?

//calculate step and initial side distance
if (RAY_DIR_X < 0) {
STEP_X = -1;
SIDE_DIST_X = (RAY_POS_X - MAP_X) * DELTA_DIST_X;
} else {
STEP_X = 1;
SIDE_DIST_X = (MAP_X + 1.0 - RAY_POS_X) * DELTA_DIST_X;
}

if (RAY_DIR_Y < 0) {
STEP_Y = -1;
SIDE_DIST_Y = (RAY_POS_Y - MAP_Y) * DELTA_DIST_X;
} else {
STEP_Y = 1;
SIDE_DIST_Y = (MAP_Y + 1.0 - RAY_POS_Y) * DELTA_DIST_Y;
}

//perform DDA loop
while (!HIT) {
//jump to the next map square, or in x or y direction
if (SIDE_DIST_X < SIDE_DIST_Y) {
SIDE_DIST_X += DELTA_DIST_X;
MAP_X += STEP_X;
SIDE = false;
} else {
SIDE_DIST_Y += DELTA_DIST_Y;
MAP_Y += STEP_Y;
SIDE = true;
}

//check to see if the ray has hit a wall
if (MAP[MAP_X][MAP_Y] > 0) {
HIT = true;
}
}

//calculate distance projected on camera direction
if (SIDE == false) {
PERP_WALL_DIST = fabs((MAP_X - RAY_POS_X + (1 - STEP_X) / 2) / RAY_DIR_X);
} else {
PERP_WALL_DIST = fabs((MAP_Y - RAY_POS_Y + (1 - STEP_Y) / 2) / RAY_DIR_Y);
}

//calculate height of line to draw on screen
int LINE_HEIGHT = abs(int(PROJECTION_PLANE_HEIGHT / PERP_WALL_DIST));

//calculate lowest and highest pixel to fill in current line
int DRAW_START = -LINE_HEIGHT / 2 + PROJECTION_PLANE_HEIGHT / 2;
if (DRAW_START < 0) {
DRAW_START = 0;
}

int DRAW_END = LINE_HEIGHT / 2 + PROJECTION_PLANE_HEIGHT / 2;
if (DRAW_END >= PROJECTION_PLANE_HEIGHT) {
DRAW_END = PROJECTION_PLANE_HEIGHT - 1;
}

//choose wall color
int RGB_RED = 0;
int RGB_GREEN = 0;
int RGB_BLUE = 0;
switch (MAP[MAP_X][MAP_Y]) {
case 1:
//red
RGB_RED = 255;
break;
case 2:
//green
RGB_GREEN = 255;
break;
case 3:
//blue
RGB_BLUE = 255;
break;
case 4:
//white
RGB_RED = 255;
RGB_GREEN = 255;
RGB_BLUE = 255;
break;
default:
//yellow?
RGB_GREEN = 255;
RGB_BLUE = 255;
break;
}

//give x and y sides different brightness
if (SIDE == true) {
RGB_RED = RGB_RED / 2;
RGB_GREEN = RGB_GREEN / 2;
RGB_BLUE = RGB_BLUE / 2;
}

int WALL_COLOR = SDL_MapRGB(screen->format, RGB_RED, RGB_GREEN, RGB_BLUE);

//draw the pixels of a stripe as a vertical line
SDL_Rect *LINE = new SDL_Rect();
LINE->x = x;
LINE->y = DRAW_START;

LINE->w = 1;
LINE->h = DRAW_START - DRAW_END;

SDL_FillRect(screen, LINE, WALL_COLOR);

SDL_Flip(screen);

//blah blah blach;
delete LINE;
}
}
return 0;
}


[Edited by - bgraybr on August 29, 2010 11:54:20 AM]

Share this post


Link to post
Share on other sites
Hey Hey!

Could you post a screenshot so I can tell exactly what you mean?

Anyway, to draw your vertical lines much much faster. You should do something like this.


Uint32 *dest = (Uint32*) ((Uint8*)screen->pixels + (int)topY * screen->pitch + (xScanline << 2));
Uint32 next = (screen->pitch>>2);
Uint32 color;
for(y = (int)topY; y < (int)bottomY; ++y)
{
*dest = color; //USe SDL_MapRGB to set this color variable
dest+=next;
}






Let me know if it helps,
Jinroh.

Share this post


Link to post
Share on other sites
Here's a link to a screenshot: http://www.mediafire.com/imageview.php?quickkey=lwribs1ec08893a&thumb=4

The color concerns me because it's this color:

default:
//turquoise?
RGB_GREEN = 255;
RGB_BLUE = 255;
break;

...which is never used in the "MAP" array and shouldn't be appearing at all.

Share this post


Link to post
Share on other sites
I added a small amount of code to the end (detecting key presses and moving the camera around) and now the screen is filling with a different color, I definitely got some variables mixed up somewhere but I still can't find where it is.

Share this post


Link to post
Share on other sites
Ok. ^^ Thanks that helps me get an idea of what's wrong. I'll try and compile it tomorrow after work. I'll run through it with the debugger and see why the Default value of the Switch is getting called. ^^

EDIT: I still haven't gotten a chance to look at it. Work's been brutal this week. I'll try and help you out this weekend. ^_^ You could go ahead and set a break point at your SWITCH statement and step through it and see what's happening when you go through the SWITCH code. That's what I was going to do and it would be a good place to start. ^_^

[Edited by - Jinroh on September 2, 2010 6:36:13 AM]

Share this post


Link to post
Share on other sites

This topic is 2664 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this