I am attempting to write a raycasting engine.
I studied the tutorial found at http://www.instructables.com/id/Making-a-Basic-3D-Engine-in-Java/ and the C++ raycasting tutorials found at http://lodev.org/cgtutor/raycasting.html, and after a few attempts I got the rays to be cast in the right direction and therefore got a (semi) working output.
I got the walls to show up in the world and i added movement into the game and i was able to move around. However, the walls (which are supposed to be a cube) only show two sides of the cube no matter what direction I'm facing in the world. So instead of showing a solid cube, it'll jump from the side of the cube that is actually closest to the camera, and show the far side of the cube instead, and this only happens when im facing towards the origin (0,0) of the 2d array that my map is stored in. This error is shown in the image above.
I think that this error is due to integer rounding and the locations of the walls detected by the ray being rounded down, yet i cant seem to come up with a solution. I'm actually casting two rays for each pixel column, one to detect vertical walls and one to detect horizontal walls. The distances of each are calculated and compared, and then the shortest distance wall gets drawn.
My question is how to cause the walls to be drawn correctly
public class Screen {
//VARIABLE DECLARATIONS
//-----------------------
int FOV = 60; //field of view in degrees
int screenwidth = 800; //variable holds the vertical resolution of the screen
int screenheight = 600; //variable holds the horizontal resolution of the screen
double camx; //cameras x coordinate
double camy; //cameras y coordinate
double camAngle; //direction of camera in degrees
double rayAngle; //angle of ray being cast in radians
int x = 0; //holds the current pixel column being looped through
double IncrementAngle = (double)FOV / (double)screenwidth; //calculates the change in the rays angle for each horizontal pixel
int[][] map; //stores the 2d map that represents the 3d world of the game
public Screen() {
public int[] update(int[] pixels, int[][] m, double ca, double cx, double cy, int fov) {
FOV = fov;
IncrementAngle = (double)FOV / (double)screenwidth; //calculates the change in the rays angle for each horizontal pixel
camAngle = ca;
camx = cx;
camy = cy;
map = m;
int x = 0;
Color c; //declares new color
//fills background
for (int n = 0; n < pixels.length; n++) pixels[n] = Color.BLACK.getRGB();
for (double ray = (double)(FOV / 2); ray > (double)(-FOV / 2); ray -= IncrementAngle) {
double vdist = Integer.MAX_VALUE, hdist = Integer.MAX_VALUE;
double perpendicularDist = 0;
double theta;
double lineheight;
int drawstart, drawend;
int side = 0;
int r = 0, g = 0, b = 0, a = 0; //variables that determinbe what colours will be drawn (red, green, blue, and alpha for
transparency)
rayAngle = Math.toRadians(camAngle + ray);
try {
vdist = VertDist(rayAngle);
}
catch (ArrayIndexOutOfBoundsException e) {}
try {
hdist = HorDist(rayAngle);
}
catch (ArrayIndexOutOfBoundsException e) {}
theta = Math.abs(rayAngle - Math.toRadians(camAngle)); //angle difference between the ray being cast and the cameras
direction
if (hdist < vdist) {
perpendicularDist = hdist * Math.cos(theta);
lastSide = 0;
r = Color.GRAY.getRed();
g = Color.GRAY.getGreen();
b = Color.GRAY.getBlue();
a = Color.GRAY.getAlpha();
}
else {
perpendicularDist = vdist * Math.cos(theta);
lastSide = 1;
r = Color.DARK_GRAY.getRed();
g = Color.DARK_GRAY.getGreen();
b = Color.DARK_GRAY.getBlue();
a = Color.DARK_GRAY.getAlpha();
}
//creates pulsating effect with wall colours
r -= pulse;
g += pulse * 2;
b -= pulse;
c = new Color(r, g, b, a);
lineheight = screenheight / perpendicularDist;
drawstart = (int)(-lineheight / 2) + (screenheight / 2);
drawend = (int)(lineheight / 2) + (screenheight / 2);
if (drawstart < 0) drawstart = 0;
if (drawend >= screenheight) drawend = screenheight - 1;
for (int y = drawstart; y < drawend; y++) {
pixels[x + (y * screenwidth)] = c.getRGB();
}
if (x < screenwidth) x++;
else x = 0;
}
//returns pixels array to main class to be shown to screen
return pixels;
}
public double VertDist(double angle) {
double rx = 0, ry = 0;
double stepX = 0, stepY = 0;
double FstepX = 0, FstepY = 0;
double Fxcomp = 0, Fycomp = 0;
double xcomp = 0, ycomp = 0;
double mapx = camx, mapy = camy;
boolean hit = false;
double obliqueDist = 0;
rx = Math.cos(angle);
ry = Math.sin(angle);
if (rx < 0) {
stepX = -1;
FstepX = (camx - ((int)camx)) * stepX;
}
else if (rx > 0) {
stepX = 1;
FstepX = ((int)(camx + 1)) - camx;
}
ycomp = (stepX * Math.tan(angle) * -1);
Fycomp = Math.abs(FstepX) * ycomp;
if (map[(int)(mapx)][(int)(mapy)] > 0) hit = true;
mapx += FstepX;
mapy += Fycomp;
if (map[(int)(mapx)][(int)(mapy)] > 0) hit = true;
else {
while (!hit && mapx > 0 && mapy > 0) { //loops while a wall has not been found and while positive indexes are still being
checked
mapx += stepX;
mapy += ycomp;
if (map[(int)(mapx)][(int)(mapy)] > 0) {
hit = true;
//if (Math.toDegrees(rayAngle) < 270 && Math.toDegrees(rayAngle) > 90) {
// mapy -= stepX;
// mapx -= ycomp;
//}
}
}
}
mapx = Math.abs(mapx - camx);
mapy = Math.abs(mapy - camy);
obliqueDist = Math.sqrt((mapx*mapx) + (mapy*mapy));
//change to be not fixed angle based
//if (angle > Math.toRadians(135) && angle < Math.toRadians(225)) {
// obliqueDist -= Math.sqrt(stepX*stepX + ycomp*ycomp);
//}
return obliqueDist;
}
public double HorDist(double angle) {
double rx, ry;
double stepX = 0, stepY = 0;
double FstepX = 0, FstepY = 0;
double Fxcomp, Fycomp;
double xcomp, ycomp;
double mapx = camx, mapy = camy;
boolean hit = false;
double obliqueDist = 0;
rx = Math.cos(angle);
ry = Math.sin(angle);
if (ry < 0) {
stepY = 1;
FstepY = ((int)(camy + 1)) - camy;
}
else if (ry > 0) {
stepY = -1;
FstepY = (camy - (int)camy) * stepY;
}
xcomp = stepY / (Math.tan(angle) * -1);
Fxcomp = Math.abs(FstepY) * xcomp;
if (map[(int)(mapx)][(int)(mapy)] > 0) hit = true;
mapx += Fxcomp;
mapy += FstepY;
if (map[(int)(mapx)][(int)(mapy)] > 0) hit = true;
else {
while (!hit) {
mapx += xcomp;
mapy += stepY;
if (map[(int)(mapx)][(int)(mapy)] > 0) hit = true;
}
}
mapx = Math.abs(mapx - camx);
mapy = Math.abs(mapy - camy);
obliqueDist = Math.sqrt((mapx*mapx) + (mapy*mapy));
//change to be not fixed angle based
//if (angle > Math.toRadians(45) && angle < Math.toRadians(135)) {
// obliqueDist -= Math.sqrt(xcomp*xcomp + stepY*stepY);
//}
return obliqueDist;
} }