/* ................................................................................... Raycaster (c) 1999-2000 Johan Van den Brande http://www.vandenbrande.com ................................................................................... A very simple raycaster with floor and ceiling mapping. Uses 64x64 tiles. todo: * wait for images to load * find an 'exception' bug */ import java.applet.*; import java.awt.*; import java.awt.image.*; import java.awt.event.*; public class raycaster extends java.applet.Applet implements Runnable, KeyListener { Thread runner; Image dbImg; int pixels[]; int txtPels1[]; int txtPels2[]; int txtPelsFloor[]; int txtPelsCeiling[]; float cosTab[], invcosTab[]; float sinTab[], invsinTab[]; float tanTab[], invtanTab[]; float distTab[]; MemoryImageSource source; static final int numberofdirections=1024; static final int wdwWidth=320; static final int wdwHeight=256; static final int wdwSize=wdwWidth*wdwHeight; static final byte W=1; static final byte s=0; static final byte X=2; static final int mapWidth=16; static final int mapHeight=16; static final int gridH=64; static final int gridW=64; static final float viewangle= (float) (Math.PI/3); static final int iFOV = (int) numberofdirections/6; static final int txtHeight=64; static final int txtWidth=64; static final int xColor = 255<<24 | 200<<16 | 200<<8 | 200; static final int yColor = 255<<24 | 150<<16 | 150<<8 | 150; static final int wallHeight=64; static final int columns=wdwWidth; static final float distanceViewPlane=300; boolean keyU, keyD, keyL, keyR; int bkgColor; float turnSpeed; float personX; float personY; float direction; int iDirection; byte[] map= { W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W, W,s,s,s,s,s,s,W,s,s,s,s,s,s,s,W, W,s,W,W,W,W,s,W,s,W,W,W,W,W,s,W, W,s,W,s,s,s,s,W,s,s,s,s,s,W,s,W, W,s,W,s,X,X,s,W,s,W,W,W,s,W,s,W, W,s,W,s,X,X,s,W,s,s,s,W,s,W,s,W, W,s,W,s,s,s,s,W,W,W,s,W,s,W,s,W, W,s,W,W,W,W,W,W,s,W,s,W,s,W,s,W, W,s,s,s,W,s,s,s,s,W,s,W,s,W,s,W, W,s,W,s,W,s,s,W,s,W,s,s,s,W,s,W, W,s,W,s,W,W,s,W,s,W,s,W,W,W,s,W, W,s,W,s,s,s,s,W,s,W,s,s,s,s,s,W, W,s,W,W,W,W,W,W,s,s,s,s,s,W,s,W, W,s,W,s,s,s,s,W,W,W,W,W,s,W,s,W, W,s,s,s,W,W,s,s,s,s,s,s,s,s,s,W, W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W }; public void init() { int i, value; float alpha; keyU=keyD=keyL=keyR=false; addKeyListener(this); turnSpeed=1; Image txtMap1 = getImage(getDocumentBase(), "txtMap1.gif"); Image txtMap2 = getImage(getDocumentBase(), "Metal8_1.gif"); Image txtFloor = getImage(getDocumentBase(), "txtMap2.gif"); Image txtCeiling = getImage(getDocumentBase(), "rrock1_2.gif"); pixels = new int[wdwSize]; txtPels1 = new int[64*64]; txtPels2 = new int[64*64]; txtPelsFloor = new int[64*64]; txtPelsCeiling = new int[64*64]; value=(255 << 24) | 0 ;//getBackground().getRGB(); bkgColor=value; for (i=0;i=0) { xFirstY+=gridH; deltaX=(float) (gridH * invtanTab[iDirectionCast]); deltaY=gridH; } else { xFirstY-=1; deltaY=-gridH; deltaX=(float) (-1*gridH * invtanTab[iDirectionCast]); } xFirstX= (float) personX + (float) ((xFirstY-personY) * invtanTab[iDirectionCast]); cnt=0; while (true) { xInt=(int) ((int) xFirstX/gridW) & 15; yInt=(int) ((int) xFirstY/gridH) & 15; if ((xMap=map[yInt*16+xInt])!=s) { break; } xFirstX+=deltaX; xFirstY+=deltaY; cnt++; if (cnt>255) { break; } } // find Y intercept yFirstX=(float) (((int) (personX/gridW))*gridW); if (directionX>=0) { yFirstX+=gridW; deltaX=gridW; deltaY=(float) (gridW*tanTab[iDirectionCast]); } else { yFirstX-=1; deltaX=-gridW; deltaY=(float) (-1*gridW*tanTab[iDirectionCast]); } yFirstY= (float) personY + (float) ((yFirstX-personX)*tanTab[iDirectionCast]); cnt=0; while (true) { xInt=(int) ((int) yFirstX/gridW) & 15; yInt=(int) ((int) yFirstY/gridH) & 15; if ((yMap=map[yInt*16+xInt])!=s) { break; } yFirstX+=deltaX; yFirstY+=deltaY; cnt++; if (cnt>255) { break; } } distanceX=(float) ((xFirstX-personX)* invcosTab[iDirectionCast]); distanceY=(float) ((yFirstY-personY)* invsinTab[iDirectionCast]); if (distanceX<=distanceY) { txtCol=(int) xFirstX % 64; distance=distanceX; iColor=xColor; WALL=xMap; } else { txtCol=(int) yFirstY % 64; distance=distanceY; iColor=yColor; WALL=yMap; } distance*=cosTab[(iDirection-iDirectionCast) & (numberofdirections-1)]; columnHeight=(float) (wallHeight*distanceViewPlane/distance); // System.out.println(iDirectionCast); drawWallSlice(pixels,column,(int) (128 - columnHeight/2),(int) columnHeight, iColor, txtCol, WALL); // draw floor line from bottom of wall to viewplane. drawFloor(pixels,column,(int) (128 + columnHeight/2), iDirectionCast); directionCast+=deltaCast; } } public void drawWallSlice(int [] pixels, int column,int ypos,int columnHeight, int iColor, int txtcolumn, byte map) { int i,h,ic, t; float c,deltap; int offset; int pels[]; switch (map) { case W: pels=txtPels1; break; case X: pels=txtPels2; break; default: pels=txtPels1; } // System.out.println(txtcolumn); // clip ypos ypos=(ypos<0)?0:ypos; ypos=(ypos>255)?255:ypos; h=ypos + columnHeight; h=(h>255)?255:h; // column&=255; deltap=64F/columnHeight; t=(columnHeight>255)?columnHeight-256:0; txtcolumn&=63; c=(float) t*deltap/2; offset=ypos*wdwWidth + column; // System.out.println(deltap + "\t|\t" + columnHeight); for (i=ypos;i10)?10:turnSpeed; } if (keyL) { iDirection-=(int) turnSpeed; iDirection=(iDirection<0)?numberofdirections-1:iDirection; iDirection&=numberofdirections-1; turnSpeed+=1; turnSpeed=(turnSpeed>10)?10:turnSpeed; } if (!(keyL || keyR)) { turnSpeed-=1; turnSpeed=(turnSpeed<0)?0:turnSpeed; } } }