I have a java project who makes the "windows' maze" and use the ray casting algorithm. Here's a screenshot :
Like you can see all the walls have the same height size. I would like to do the same but with different height size
private void castRay(int xOnScreen,double angle,double direction) {
R rx = castRayInX(angle,direction);
R ry = castRayInY(angle,direction);
// In case of out-of-space rays
if (rx.getDistance()==Double.MAX_VALUE && ry.getDistance()==Double.MAX_VALUE) {
graphics.setColor(BACKGROUND);
graphics.drawLine(xOnScreen,0,xOnScreen,this.image.getHeight());
return;
}
double distance = rx.getDistance();
double normal = rx.getNormal();
Color c = rx.getColor();
double coef = Math.cos((angle+direction+Math.PI)-normal);
Plot collision = rx.getPlot();
if (ry.getDistance()<rx.getDistance()) {
distance = ry.getDistance();
normal = ry.getNormal();
c = ry.getColor();
coef = Math.cos((angle+direction+Math.PI)-normal);
collision = ry.getPlot();
}
coef = Math.abs(coef);
int factor = map.length*SQUARE_SIZE;
double d = (double)(distance+factor)/factor;
coef *= 1/(d*d);
Color c2 = new Color((int)(c.getRed()*coef),(int)(c.getGreen()*coef),(int)(c.getBlue()*coef));
graphics.setColor(c2);
// graphics.setColor(c); // no illumination
distance *= Math.cos(angle); // lens correction
int h = (int)(this.screenDistance/distance*WALL_HEIGHT); // perspective height
int vh = this.image.getHeight();
graphics.drawLine(xOnScreen,(vh-h)/2,xOnScreen,(vh+h)/2);
drawEye(direction,collision);
}
private R castRayInX(double angleRay,double direction) {
double angle = angleRay+direction;
double x1 = eye.getX()+SQUARE_SIZE*Math.cos(angle);
double y1 = eye.getY()+SQUARE_SIZE*Math.sin(angle);
double slope = (y1-eye.getY())/(x1-eye.getX());
if (Math.cos(angle)==0) {
if (Math.sin(angle)>0)
return new R(Double.MAX_VALUE,3*Math.PI/2,BACKGROUND,null);
else
return new R(Double.MAX_VALUE,Math.PI/2,BACKGROUND,null);
}
if (Math.cos(angle)>0) {
int firstX = ((eye.getX()/SQUARE_SIZE)+1)*SQUARE_SIZE;
R r = new R(Double.MAX_VALUE,angle+Math.PI,BACKGROUND,null);
for (int x = firstX; x<map[0].length*SQUARE_SIZE; x += SQUARE_SIZE) {
int y = (int)(slope*(x-eye.getX())+eye.getY());
if (isOutside(x,y,Color.MAGENTA,this.showRayCastingX)) break;
Color c = colorAt(x,y);
if (c==null) c = colorAt(x,y-1);
if (c==null) c = colorAt(x-1,y);
if (c==null) c = colorAt(x-1,y-1);
if (c!=null) {
int DX = x-eye.getX();
double DY = y-eye.getY();
return new R(Math.sqrt(DX*DX+DY*DY),Math.PI,c,new Plot((int)x,(int)y, WALL_HEIGHT));
}
}
return r;
} else {
int firstX = ((eye.getX()/SQUARE_SIZE))*SQUARE_SIZE;
R r = new R(Double.MAX_VALUE,angle+Math.PI,BACKGROUND,null);
for (int x = firstX; x>=0; x -= SQUARE_SIZE) {
int y = (int)(slope*(x-eye.getX())+eye.getY());
if (isOutside(x,y,Color.MAGENTA,this.showRayCastingX)) break;
Color c = colorAt(x,y);
if (c==null) c = colorAt(x,y-1);
if (c==null) c = colorAt(x-1,y);
if (c==null) c = colorAt(x-1,y-1);
if (c!=null) {
int DX = x-eye.getX();
double DY = y-eye.getY();
return new R(Math.sqrt(DX*DX+DY*DY),0,c,new Plot((int)x,(int)y, WALL_HEIGHT));
}
}
return r;
}
}
private R castRayInY(double angleRay,double direction) {
// System.out.println("cast ray 2 Y "+angleRay+" "+direction);
double angle = angleRay+direction;
double x1 = eye.getX()+SQUARE_SIZE*Math.cos(angle);
double y1 = eye.getY()+SQUARE_SIZE*Math.sin(angle);
// System.out.println(eye+" "+x1+" "+y1);
double slope = (y1-eye.getY())/(x1-eye.getX());
if (Math.sin(angle)==0) {
if (Math.cos(angle)>0)
return new R(Double.MAX_VALUE,Math.PI,BACKGROUND,null);
else
return new R(Double.MAX_VALUE,0,BACKGROUND,null);
}
if (Math.sin(angle)>0) {
int firstY = ((eye.getY()/SQUARE_SIZE)+1)*SQUARE_SIZE;
R r = new R(Double.MAX_VALUE,angle+Math.PI,BACKGROUND,null);
for (int y = firstY; y<map.length*SQUARE_SIZE; y += SQUARE_SIZE) {
int x = (int)((y-eye.getY())/slope)+eye.getX();
if (isOutside(x,y,Color.CYAN,this.showRayCastingY)) break;
Color c = colorAt(x,y);
if (c==null) c = colorAt(x,y-1);
if (c==null) c = colorAt(x-1,y);
if (c==null) c = colorAt(x-1,y-1);
if (c!=null) {
double DX = x-eye.getX();
int DY = y-eye.getY();
return new R(Math.sqrt(DX*DX+DY*DY),3*Math.PI/2,c,new Plot((int)x,(int)y, WALL_HEIGHT));
}
}
return r;
} else {
int firstY = ((eye.getY()/SQUARE_SIZE))*SQUARE_SIZE;
R r = new R(Double.MAX_VALUE,angle+Math.PI,BACKGROUND,null);
for (int y = firstY; y>=0; y -= SQUARE_SIZE) {
int x = (int)((y-eye.getY())/slope)+eye.getX();
if (isOutside(x,y,Color.CYAN,this.showRayCastingY)) break;
Color c = colorAt(x,y);
if (c==null) c = colorAt(x,y-1);
if (c==null) c = colorAt(x-1,y);
if (c==null) c = colorAt(x-1,y-1);
if (c!=null) {
double DX = x-eye.getX();
int DY = y-eye.getY();
return new R(Math.sqrt(DX*DX+DY*DY),Math.PI/2,c,new Plot((int)x,(int)y, WALL_HEIGHT));
}
}
return r;
}
}
My R
class has a Plot (x, y, z)
for now I use WALL_HEIGHT
a color, a distance and a normal for the light. For now this works but I would like to add a new function like castRayInZ but I don't have all the mathematics theory behind. My maze is made from a map like that :
private String [][]map = { // each: SQUARE_SIZE x SQUARE_SIZE
{ "Y300", "Z500", "X230", "Y112", "Z321", "X120", "X354" },
{ "X89", " ", " ", " ", "Y120", " ", "X232" },
{ "Z124", " ", "X276", " ", "X123", " ", "X" },
{ "Y290", " ", " ", " ", " ", " ", "X100" },
{ "X32", "Z430", " ", "Y500", "X120", " ", "X123" },
{ "X222", " ", " ", " ", " ", " ", "X210" },
{ "X12", "Y98", "Y763", "X146", "Y111", "Y333", "X321" }
where X Y Z is for the color (X for Red, Y for Green and Z for Blue just testing my light function) and I add a height for each square of my map. I set all of length to SQUARE_LENGTH
for now maybe later I will reduce the size of each square to a pixel and enlarge my map by generating it. But I really want to know how can I change the height of each square. I'm working on it since 4 days now and I don't have any clues...
EDIT
I have some news, I changed the size of my walls but I have some strange stuff, here's a screenshot :
Like you can see I there's some strange things appear here. Here's my code :
private void castRay(int xOnScreen,double angle,double direction) {
R rx = castRayInX(angle,direction);
R ry = castRayInY(angle,direction);
// In case of out-of-space rays
if (rx.getDistance()==Double.MAX_VALUE && ry.getDistance()==Double.MAX_VALUE) {
graphics.setColor(BACKGROUND);
graphics.drawLine(xOnScreen,0,xOnScreen,this.image.getHeight());
return;
}
double distance = rx.getDistance();
double normal = rx.getNormal();
Color c = rx.getColor();
double coef = Math.cos((angle+direction+Math.PI)-normal);
Plot collision = rx.getPlot();
if (ry.getDistance()<rx.getDistance()) {
distance = ry.getDistance();
normal = ry.getNormal();
c = ry.getColor();
coef = Math.cos((angle+direction+Math.PI)-normal);
collision = ry.getPlot();
}
coef = Math.abs(coef);
int factor = map.length*SQUARE_SIZE;
double d = (double)(distance+factor)/factor;
coef *= 1/(d*d);
Color c2 = new Color((int)(c.getRed()*coef),(int)(c.getGreen()*coef),(int)(c.getBlue()*coef));
graphics.setColor(c);
distance *= Math.cos(angle); // lens correction
int h;
int hw = (int)(this.screenDistance/distance*WALL_HEIGHT); //WALL_HEIGHT value is 300px at default
if(rx.getPlot() != null)
h = (int)(this.screenDistance/distance*rx.getPlot().getZ()); // perspective height
else
h = (int)(this.screenDistance/distance*WALL_HEIGHT);
int vh = this.image.getHeight();
int y0 = (hw+vh)/2;
int y1 = (vh-h)/2;
graphics.drawLine(xOnScreen,y0,xOnScreen,y1);
drawEye(direction,collision);
My problem should be from castRayInX
function :
private R castRayInX(double angleRay,double direction) {
double angle = angleRay+direction;
double x1 = eye.getX()+SQUARE_SIZE*Math.cos(angle);
double y1 = eye.getY()+SQUARE_SIZE*Math.sin(angle);
double slope = (y1-eye.getY())/(x1-eye.getX());
if (Math.cos(angle)==0) {
if (Math.sin(angle)>0)
return new R(Double.MAX_VALUE,3*Math.PI/2,BACKGROUND,null);
else
return new R(Double.MAX_VALUE,Math.PI/2,BACKGROUND,null);
}
if (Math.cos(angle)>0) {
int firstX = ((eye.getX()/SQUARE_SIZE)+1)*SQUARE_SIZE;
R r = new R(Double.MAX_VALUE,angle+Math.PI,BACKGROUND,null);
for (int x = firstX; x<map[0].length*SQUARE_SIZE; x += SQUARE_SIZE) {
int y = (int)(slope*(x-eye.getX())+eye.getY());
if (isOutside(x,y,Color.MAGENTA,this.showRayCastingX)) break;
Color c = colorAt(x,y);
int z = heightAt(x,y);
if (c==null) c = colorAt(x,y-1);
if (c==null) c = colorAt(x-1,y);
if (c==null) c = colorAt(x-1,y-1);
if (z == 0) z = heightAt(x,y-1);
if (z == 0) z = heightAt(x-1,y);
if (z == 0) z = heightAt(x-1,y-1);
if (c!=null) {
int DX = x-eye.getX();
double DY = y-eye.getY();
return new R(Math.sqrt(DX*DX+DY*DY),Math.PI,c,new Plot((int)x,(int)y,(int)z));
}
}
return r;
} else {
int firstX = ((eye.getX()/SQUARE_SIZE))*SQUARE_SIZE;
R r = new R(Double.MAX_VALUE,angle+Math.PI,BACKGROUND,null);
for (int x = firstX; x>=0; x -= SQUARE_SIZE) {
int y = (int)(slope*(x-eye.getX())+eye.getY());
if (isOutside(x,y,Color.MAGENTA,this.showRayCastingX)) break;
Color c = colorAt(x,y);
int z = heightAt(x,y);
if (c==null) c = colorAt(x,y-1);
if (c==null) c = colorAt(x-1,y);
if (c==null) c = colorAt(x-1,y-1);
if (z == 0) z = heightAt(x,y-1);
if (z == 0) z = heightAt(x-1,y);
if (z == 0) z = heightAt(x-1,y-1);
if (c!=null) {
int DX = x-eye.getX();
double DY = y-eye.getY();
return new R(Math.sqrt(DX*DX+DY*DY),0,c,new Plot((int)x,(int)y,(int)z));
}
}
return r;
}
}
Should I make a castRayInZ
function ? Or should I get my z
value somewhere else ?
WALL_HEIHGT
. What are you having trouble with? – Bunk