Perspective Floor

<< MakeMaze | FinalProjectsTrailIndex | StoryTextApplet >>

See a working version of it here.

You can read about the math involved here.

This applet changes the the view in 2 of the three possible directions...maybe you can see how to make the distance to eye change with a key press yourself!

Tile.java


import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.ArrayList;
/**
 * @author Chris Thiel, OFMCap 
 * @version 16 May 2012
 */


public class Tile 
{
	public static final int GAP=10, SIZE=55, LEFT=140, TOP=60;
	public static final int NORTH=0, SOUTH=1, EAST=2, WEST=3;

	private int visits, row, col;
	private Color color;
	private Rectangle box;
	public Tile(int r, int c)
	{
		setVisits(0);
		row=r;
		col=c;
		box = new Rectangle (LEFT+col*(SIZE+GAP), TOP+row*(SIZE+GAP), SIZE, SIZE);

	}

	public void draw(Graphics g)
	{
		Color oldColor=g.getColor();
		g.setColor(color);
		g.fillRect(box.x, box.y, box.width, box.height);
		g.setColor(oldColor);
	}
	public void draw(Graphics g, Perspective p)
	{
		Color oldColor=g.getColor();
		g.setColor(color);
		g.fillPolygon(p.convert(box));
		g.setColor(oldColor);
	}
	public Rectangle getBox(){return box;}
	public int getRow(){return row;}
	public int getCol(){return col;}
	public int getVisits(){return visits;}
	public void setVisits(int i){
		visits=i;
		if (visits%3==0)
			color=Color.YELLOW;
		if (visits%3==1)
			color=Color.GREEN;
		if (visits%3==2)
			color=Color.CYAN;
	}
	public void incVisits(){setVisits(visits+1);}
	public void setColor(Color c){color=c;}
	public Color getColor(){ return color;}
	public String toString(){
		return String.format("[%2d]",row)+String.format("[%2d]",col);
	}

}

Perspective.java


import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;

/**
 * @author Chris Thiel, OFMCap 
 * @version 16 May 2012
 */

public class Perspective 
{
	private double eyeX, eyeY, eyeToImage, maxDist;
	public Perspective(double eyeX, double eyeY, double eyeToImage, double maxDist){
		this.setEyeX(eyeX);
		this.setEyeY(eyeY);
		this.setEyeToImage(eyeToImage);
		this.setMaxDist(maxDist);
	}
	/**
	 * converts a flat rectangle to a perspective polygon
	 * @param r
	 * @return
	 */
	public Polygon convert(Rectangle r){
		Polygon result=new Polygon();
		int left=r.x;
		int right=r.x+r.width;
		int top=r.y;
		int bottom=r.y+r.height;

		result.addPoint(imageX(left,top), imageY(0,top));
		result.addPoint(imageX(right,top), imageY(0,top));
		result.addPoint(imageX(right,bottom), imageY(0,bottom));
		result.addPoint(imageX(left,bottom), imageY(0,bottom));
		return result;
	}
	public int imageX(double x, double z){
		double dx=this.eyeX-x;
		double D=(this.maxDist-z);
		return (int)(x+(dx*D/(this.eyeToImage+D)));
	}
	public int imageY(double y, double z){
		double dy=this.eyeY-y;
		double D=(this.maxDist-z);
		return (int)(this.maxDist-y-(dy*D/(this.eyeToImage+D)));
	}
	public Polygon topView(Rectangle r){
		Polygon result=new Polygon();
		result.addPoint(r.x, r.y);
		result.addPoint(r.x+r.width, r.y);
		result.addPoint(r.x+r.width, r.y+r.height);
		result.addPoint(r.x, r.y+r.height);
		return result;
	}
	public double getEyeX() {
		return eyeX;
	}
	public void setEyeX(double eyeX) {
		this.eyeX = eyeX;
	}
	public double getEyeY() {
		return eyeY;
	}
	public void setEyeY(double eyeY) {
		this.eyeY = eyeY;
	}
	public double getEyeToImage() {
		return eyeToImage;
	}
	public void setEyeToImage(double eyeToImage) {
		this.eyeToImage = eyeToImage;
	}
	public double getMaxDist() {
		return maxDist;
	}
	public void setMaxDist(double maxDist) {
		this.maxDist = maxDist;
	}
}

PerspectiveFloor.java


import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;


public class PerspectiveFloor extends Applet implements KeyListener
{
	public static final int ROWS=8, COLS=8;
	public static final int WIDTH=800, HEIGHT=600;
	private Tile[][] floor;
	private Rectangle grout;
	private Tile currentTile;
	String message;
	private Image imgBuffer;
    private Graphics gBuffer;
    private Perspective view;
    /**
     * @author Chris Thiel, OFMCap 
     * @version 16 May 2012
     */

	public void init()
	{
		imgBuffer = createImage(WIDTH,HEIGHT);
        gBuffer = imgBuffer.getGraphics();
        this.addKeyListener(this);

        message="Click for focus, then press Arrow keys to move";
		floor = new Tile[ROWS][COLS];
		for (int r=0;r<ROWS;r++)
			for(int c=0;c<COLS;c++)
				floor[r][c]=new Tile(r,c);
		currentTile=floor[ROWS/2][COLS/2];
		currentTile.setColor(Color.RED);
		grout = new Rectangle(Tile.LEFT-Tile.GAP, Tile.TOP-Tile.GAP, 
				COLS*(Tile.SIZE+Tile.GAP)+Tile.GAP, ROWS*(Tile.SIZE+Tile.GAP)+Tile.GAP);
		view=new Perspective(WIDTH/2, HEIGHT/2, 900.0, HEIGHT/2);
	}
	public void paint(Graphics g)
	{
		gBuffer.setColor(Color.WHITE);
		gBuffer.fillRect(0, 0, WIDTH, HEIGHT);
		gBuffer.setColor(Color.BLACK);
		gBuffer.drawString(message, 20, 20);
		gBuffer.drawString("Arrows move position, 'A' and 'Z' raise and lower view", 20, 40);
		gBuffer.drawString("'<' and '>' move view horizontally", 20, 60);
		gBuffer.fillPolygon(view.convert(grout));
		for (int r=0;r<ROWS;r++)
			for(int c=0;c<COLS;c++)
				floor[r][c].draw(gBuffer, view);
		g.drawImage(imgBuffer,0,0,this);
	}
	public void update(Graphics g)
    {
        paint(g); 
    }
	@Override
	public void keyPressed(KeyEvent e) {
		int keyCode=e.getKeyCode();
		int r=currentTile.getRow();
		int c=currentTile.getCol();
		Tile next=null;

        if(keyCode==38 && r>0){ //up
        		next=floor[r-1][c];
        } else if (keyCode==40 && r<ROWS-1){ //down
        		next=floor[r+1][c];
        } else if (keyCode==37 && c>0){ //left
        		next=floor[r][c-1];
        } else if (keyCode==39 && c<COLS-1){ //right
        		next=floor[r][c+1];
        } else if (keyCode==65 ){ //a -raise view
    			view.setEyeY(view.getEyeY()+50);
        } else if (keyCode==90 ){ //z lower view
    			view.setEyeY(view.getEyeY()-50);
        }  else if (keyCode==44 ){ //'<' move view to left
    			view.setEyeX(view.getEyeX()-50);
        } else if (keyCode==46 ){ //'>' move view to right
    			view.setEyeX(view.getEyeX()+50);
        }
        if (next!=null ){
        		currentTile.incVisits();
        		currentTile=next;
        		next.setColor(Color.RED);
        		message="Current Tile: "+currentTile.toString();
        }

        repaint();

	}
	@Override
	public void keyReleased(KeyEvent e) {}
	@Override
	public void keyTyped(KeyEvent e) {}

}