-
Raycasting
Hello all, I am new to the forums. I basically need help with my code. A while back I started to create a simple non-textured raycaster which I am failing. I read a few tutorials (no-code) and I got a great understanding of the Raycasting theory however I lack skill in my trigonometry which has made my end result look poor. Before I post my source code I will explain the modules. (Don't worry they are small) I basically have 3 modules.
1) Hero.h (which contains my Hero class, short for now)
2) Globals.h (just global data, screen_height, FOV etc)
3) cast.cpp (main source, where my bugs are)
I am programming in C++ and using the Allegro game library.
Problems i'm having:
1) walking, sometimes walls don't change in height however turning seems ok.
2) I'm not sure how to correctly cast my rays (checking grid intersections) so my code might be skipping walls.
3) please point out the rest.
OK, here is the code...
HERO.H
Code:
class Player
{
public:
Player( ):posX(128),
posY(128), // grid (1,1)
facing_direction(90.0f) // facing 90* degrees
{}
// use default destructor for now
// data members
int posX;
int posY;
float facing_direction;
};
GLOBALS.H
Code:
typedef unsigned short USHORT;
const USHORT WALL = 1;
const USHORT MOVE = 4; // number of units to move in a given direction
const USHORT SCREEN_WIDTH = 640;
const USHORT SCREEN_HEIGHT = 480;
const USHORT HALF_SCREEN_HEIGHT = 240;
const USHORT GRID_SIZE = 64;
const float FOV = 60.0f;
int wall_distance[SCREEN_WIDTH];
float angle[SCREEN_WIDTH];
// 1 = wall
// 0 = no wall
int map[6][6] = {{ 1, 1, 1, 1, 1, 1 },
{ 1, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 1 },
{ 1, 1, 1, 1, 1, 1 }};
CAST.CPP
Code:
#include <math.h>
#include <allegro.h>
#include <cstdlib>
#include "globals.h"
#include "hero.h"
BITMAP *buffer;
// prototypes
void calculateAngles(Player & ref);
void castRays(Player & ref);
void drawScene(void);
// end of prototypes
int main(void)
{
// setup
allegro_init();
install_keyboard();
set_color_depth(16);
set_gfx_mode(GFX_AUTODETECT, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
buffer = create_bitmap(SCREEN_WIDTH, SCREEN_HEIGHT);
for(int i=0;i<SCREEN_WIDTH;i++)
wall_distance[i] = 0;
// end of setup
// instantiation
Player Hero;
Player & HeroRef = Hero;
// end of instantiation
// main loop
while(!key[KEY_ESC])
{
_sleep(2); // free some CPU time
// check for movements
if(key[KEY_RIGHT])
{
Hero.facing_direction += 0.10f;
}
if(key[KEY_LEFT])
{
Hero.facing_direction -= 0.10f;
}
if(key[KEY_DOWN])
{
Hero.posY++;
}
if(key[KEY_UP])
{
Hero.posY--;
}
// calculate ray angles to later cast
calculateAngles(HeroRef);
// cast rays based on calculated angles
castRays(HeroRef);
// draw vertical line slices to the buffer based on wall distance
drawScene();
// show buffer to the screen
acquire_screen();
blit(buffer, screen, 0, 0, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
release_screen();
clear_bitmap(buffer);
// reset wall_distance
for(int i=0;i<SCREEN_WIDTH;i++)
wall_distance[i] = 0;
}
// clean up
destroy_bitmap(buffer);
// end of clean up
return(0);
}
END_OF_MAIN();
// function definitions
void calculateAngles(Player & ref)
{
for(int i=0;i<SCREEN_WIDTH;i++)
{
angle[i] = ref.facing_direction + (( i * (FOV / 320.0f)) - (FOV / 2.0f));
if(angle[i] < 0.0f)
angle[i] += 360.0f;
if(angle[i] >= 360.0f)
angle[i] -= 360.0f;
}
}
END_OF_FUNCTION(calculateAngles(Player & ref));
void castRays(Player & ref)
{
int ray_x;
int ray_y;
for(int i=0;i<SCREEN_WIDTH;i++)
{
ray_x = ref.posX;
ray_y = ref.posY;
// allow ray to travel until a wall is found
while(map[ray_x/GRID_SIZE][ray_y/GRID_SIZE] != WALL)
{
ray_x = int(GRID_SIZE/4 * cos(angle[i] * M_PI / 180.0f));
ray_y = -int(GRID_SIZE/4 * sin(angle[i] * M_PI / 180.0f));
}
// wall found, calculate the distance from the player
wall_distance[i] = abs((ray_y - ref.posY) / sin(ref.facing_direction));
}
}
END_OF_FUNCTION(castRays(Player & ref));
void drawScene(void)
{
// draw vertical lines
for(int i=0;i<SCREEN_WIDTH;i++)
{
vline(buffer, i, HALF_SCREEN_HEIGHT-(wall_distance[i]/2), wall_distance[i], makecol(3, 170, 218));
}
}
END_OF_FUNCTION(drawScene(void));
I have tried to give as much information I can but if i'm missing something please let me know. Thanks for reading this.
Damien
-
Raycasting can be done several ways.
1. Tan(theta)=opp/adj. Split rays into x and y components. So on a grid 100x100 narrow the intersections test down to 10 per axis instead of 100x100.
2. Use Bresehnam's line algorithm to trace your ray through the map.
3. Find left and right extents of raycast and linear interpolate from left to right for distance steps.
-
So it's best not to use cos and sin? Where can I find that Algorithm?
Damien
-
Look up PXDTUT7 - if I recall the number correctly. It's over at www.programmersheaven.com
Also you may want to go to this site. www.peroxide.dk. They were creating Ultima 1: A Legend is Reborn and at one time it was sanctioned by Origin. However that has since fallen through and they have renamed the project Era. You may be able to email Telemachos asking for the previous tutorials he put out. It seems that one's earlier than PXDTUT9 are no longer available on his site.