3D Renderer

by Jim Buck

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/crafty/0.5.3/crafty-min.js"></script>
<p>The red box will follow your mouse (x and z). Scroll up and down to change the height of the box (y).</p>
<p>Notice how much the box moves when it is close to the camera? Now try moving it when it is very var from the camera. Notice the difference?</p>
<div class="clearfix">
  <div id="topDownDisplay" class="display"></div>
  <div id="cameraDisplay" class="display"></div>
</div>
<div id="coords"><div/>

CSS

html, body {
  margin: 8px;
  font-family: 'Helvetica';
  background-color: #ccc;
}

.clearfix:after {
  content: "";
  display: table;
  clear: both;
}

.display {
  float: left;
  position: relative;
  width:480px;
  height:480px;
  border:1px solid #000;
  overflow:hidden;
  background-color: #fff;
}

.display+.display {
  margin-left: 8px;
}

#topDownDisplay {
  
}

#topDownDisplay:before {
  content: 'Top Down';
  font-weight: bold;
}

#cameraDisplay {
  
}

#cameraDisplay:before {
  content: 'Camera';
  font-weight: bold;
}

TypeScript

var running;
var redraw;

var entities = [];
var mainEntity;
var camera = {
	fieldOfView: 3,
  nearClippingPlane: 3,
  farClippingPlane: 460,
  scrollSpeed: -10
};

var topDownDisplay = $('#topDownDisplay');
var cameraDisplay = $('#cameraDisplay');
var coords = $('#coords');

$(function(){
    reset();
    start();
});

topDownDisplay.on('mousemove', function(e){
    var offset = topDownDisplay.offset();
    var totalHeight = topDownDisplay.height();
    mainEntity.x  = e.pageX - offset.left;
    mainEntity.z  = (totalHeight - (e.pageY - offset.top));
    redraw = true;
}).on('mousewheel DOMMouseScroll', function(e){
        if(e.originalEvent.wheelDelta/120 > 0) {
            mainEntity.y = mainEntity.y + camera.scrollSpeed;
        } else {
            mainEntity.y = mainEntity.y - camera.scrollSpeed;
        }
        redraw = true;
    }).click(function(){
    	mainEntity.color = randColor();    
    });

function reset(){
		running = false;
    mainEntity = null;
    entities = [];
    topDownDisplay.empty();
    cameraDisplay.empty();
    mainEntity = createEntity(100, 200, 320, 240, 10, null, function(e){
        coords.text('x: ' + e.x + ' z: ' + e.z + ' y: ' + e.y);
    });
}

function start(){
    if(running)
        return;

    running = true;
    tick();    
}

function tick() {
	if(!running) return;
  
  if(redraw){
  	redraw = false;
    update();
		draw();
  }
  
  requestAnimationFrame(tick);
}

function stop(){
    running = false;
}

function update(){
    // Update positions...
    for(var e in entities){
        entities[e].update(entities[e]);
    }
}

function draw(){
    // Clear and redraw...
    topDownDisplay.empty();
    cameraDisplay.empty();
    entities.sort(function(a,b){return a.z-b.z});
    
    drawCamera();
    for(var e in entities) {
    	drawTopDown(entities[e]);
    	drawFront(entities[e]);
    }
}

function createEntity(height, width, x,y,z, color, callback){
    var entity = {
        id: entities.length,
        x, y, z,...