Skip to content

Instantly share code, notes, and snippets.

@jsyang
Created September 7, 2011 18:28
Show Gist options
  • Save jsyang/1201325 to your computer and use it in GitHub Desktop.
Save jsyang/1201325 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Swarming - jsFiddle demo by g105b</title>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.4.4.min.js'></script>
<link rel="stylesheet" type="text/css" href="/css/normalize.css">
<link rel="stylesheet" type="text/css" href="/css/result-light.css">
<style type='text/css'>
html, body{
padding:0px;
margin:0px;
/*overflow:hidden;*/
background-color:#000;
}
#canvas{
width:100%;
height:100%;
background-color:#000;
position:absolute;
top:0px;
left:0px;
}
#output{
white-space:pre;
font-family:monospace;
font-size:12px;
position:absolute;
bottom:0px;
left:0px;
color:#a40;
}
</style>
<script type='text/javascript'>
//<![CDATA[
$(function(){
//3D attempts
var O = (function() {
var outputDiv = null;
var setOutputDiv = function(id) {
outputDiv = document.getElementById(id);
outputDiv.firstChild.nodeValue = "";
};
var O = function(str) {
outputDiv.firstChild.nodeValue += str;
};
var C = function() {
outputDiv.firstChild.nodeValue = "";
};
return {
O: O,
S: setOutputDiv,
C: C
};
}());
var Profiler = (function() {
var watches = {};
var names = [];
/**
* @constructor
*/
var Watch = function() {
this.time = 0;
this.updated = 0;
this.s = null;
};
Watch.prototype.start = function() {
this.s = Date.now();
};
Watch.prototype.stop = function() {
this.time += Date.now() - this.s;
this.updated++;
};
var addWatch = function(name) {
watches[name] = new Watch();
names.push(name);
};
var startWatch = function(name) {
if (watches[name] === undefined) {
addWatch(name);
}
watches[name].start();
};
var stopWatch = function(name) {
watches[name].stop();
};
var getOutput = function() {
var str = "";
var totalTime = 0;
var i = 0;
for (i = 0; i < names.length; i++) {
totalTime += watches[names[i]].time;
}
for (i = 0; i < names.length; i++) {
/*str+= "[" +
names[i] +":" +
Math.floor(10000*watches[names[i]].time/totalTime)/100 +
"]\n";*/
str += "[" + names[i] + ": " + Math.floor(10000 * watches[names[i]].time / totalTime) / 100 + "%, " + Math.floor(
1000 * 100 * watches[names[i]].time / watches[names[i]].updated) / 100 + "ms]\n";
}
return str;
};
return {
add: addWatch,
start: startWatch,
end: stopWatch,
output: getOutput
};
}());
var Matrix = (function() {
var createNewArray = function(rows, cols) {
var newArray = [];
for (var i = 0; i < rows; i++) {
newArray[i] = [];
for (var j = 0; j < cols; j++) {
newArray[i][j] = 0;
}
}
return newArray;
};
/**
* @constructor
*/
var Matrix = function(rows, cols) {
this._a = createNewArray(rows, cols);
this.r = rows;
this.c = cols;
};
Matrix.prototype.getSafe = function(inr, inc) {
if (inr < 0) {
throw ("Matrix row < 0");
}
if (inc < 0) {
throw ("Matrix col < 0");
}
if (inr >= this.r) {
throw ("Matrix row >= rows");
}
if (inc >= this.c) {
throw ("Matrix col >= cols");
}
return this._a[inr][inc];
};
Matrix.prototype.get = function(inr, inc) {
return this._a[inr][inc];
};
Matrix.prototype.setSafe = function(inr, inc, val) {
if (inr < 0) {
throw ("Matrix row < 0");
}
if (inc < 0) {
throw ("Matrix col < 0");
}
if (inr >= this.r) {
throw ("Matrix row >= rows");
}
if (inc >= this.c) {
throw ("Matrix col >= cols");
}
this._a[inr][inc] = val;
};
Matrix.prototype.set = function(inr, inc, val) {
this._a[inr][inc] = val;
};
//Set a matrix using an array
Matrix.prototype.setA = function(a) {
for (var r = 0; r < this.r; r++) {
for (var c = 0; c < this.c; c++) {
this._a[r][c] = a[r][c];
}
}
};
Matrix.prototype.toString = function() {
var str = "";
str += "[";
for (var r = 0; r < this.r; r++) {
if (r > 0) {
str += "\n ";
}
for (var c = 0; c < this.c; c++) {
if (c > 0) {
str += ", ";
}
str += Math.floor(this._a[r][c] * 1000) / 1000;
}
}
str += "]\n";
return str;
};
var multiply = function(mat1, mat2) {
//tests that i may remove
//compatibility:
/*if (mat1.c != mat2.r) {
throw ("Matrix dimension mismatch");
}*/
var result = new Matrix(mat1.r, mat2.c);
var val = 0; //the result of each mult
//The actual calculation
//each row in mat1
for (var r = 0; r < mat1.r; r++) {
//mult by each col in mat2
for (var c = 0; c < mat2.c; c++) {
//multiply each cell
val = 0;
for (var k = 0; k < mat1.c; k++) {
val += mat1._a[r][k] * mat2._a[k][c];
}
//placed in r,c of output
result._a[r][c]= val;
}
}
return result;
};
return {
Matrix: Matrix,
mult: multiply
};
}());
var _3d = (function() {
/**
* @constructor
*/
var Point = function(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
};
/**
* @constructor
*/
var Angle = function(tx, ty, tz) {
this.tx = tx;
this.ty = ty;
this.tz = tz;
};
/**
* @constructor
*/
var Tri = function(pt1, pt2, pt3, style) {
this.a = pt1;
this.b = pt2;
this.c = pt3;
this.style = style;
};
//Locations for the transformation matrices
var camLoc = new Point(0, 0, 0);
var camRot = new Angle(0, 0, 0);
var viewLoc = new Point(0, 0, 0);
//'Cached' matrices so we don't keep doing the trig.
var matx = new Matrix.Matrix(3, 3);
var maty = new Matrix.Matrix(3, 3);
var matz = new Matrix.Matrix(3, 3);
var matt = new Matrix.Matrix(3, 3);
var setProjection = function(cLoc, cRot, vLoc) {
Profiler.start("EwTrig");
//Cheats
camLoc = new Point(cLoc[0], cLoc[1], cLoc[2]);
camRot = new Angle(cRot[0], cRot[1], cRot[2]);
viewLoc = new Point(vLoc[0], vLoc[1], vLoc[2]);
/*O.O(camRot.tx);
O.O(camRot.ty);
O.O(camRot.tz);*/
matx.setA([[1, 0, 0],
[0, Math.cos(camRot.tx), -Math.sin(camRot.tx)],
[0, Math.sin(camRot.tx), Math.cos(camRot.tx)]]);
maty.setA([[Math.cos(camRot.ty), 0, Math.sin(camRot.ty)],
[0, 1, 0],
[-Math.sin(camRot.ty), 0, Math.cos(camRot.ty)]]);
matz.setA([[Math.cos(camRot.tz), -Math.sin(camRot.tz), 0],
[Math.sin(camRot.tz), Math.cos(camRot.tz), 0],
[0, 0, 1]]);
matt = Matrix.mult(Matrix.mult(matx, maty), matz);
/*O.O(matx);
O.O(maty);
O.O(matz);
O.O(matt);*/
Profiler.end("EwTrig");
};
//The money function.
var perspectiveProjection = function(pt) {
//Profiler.start("Project");
var d = null; //new Matrix.Matrix(3,1);
var t = new Matrix.Matrix(3, 1); //translated
t.setA([[pt.x - camLoc.x],
[pt.y - camLoc.y],
[pt.z - camLoc.z]]);
d = Matrix.mult(matt, t);
var mappedx = (d.get(0, 0) - viewLoc.x) * (viewLoc.z / d.get(2, 0));
var mappedy = (d.get(1, 0) - viewLoc.y) * (viewLoc.z / d.get(2, 0));
//O.O(d);
//O.O("["+mappedx+","+mappedy+"]\n");
//Profiler.end("Project");
return {
x: mappedx,
y: mappedy,
z: d.get(2, 0)
};
};
return {
map: perspectiveProjection,
set: setProjection,
Point: Point,
Tri: Tri
};
}());
var Canvas = (function() {
var ctx = document.getElementById('canvas').getContext('2d');
var updateCanvasDimensions = function() {
ctx.canvas.width = ctx.canvas.clientWidth;
ctx.canvas.height = ctx.canvas.clientHeight;
ctx.setTransform(
1, 0, 0, 1, ctx.canvas.clientWidth / 2, ctx.canvas.clientHeight / 2);
ctx.strokeStyle = "#00ff00";
ctx.lineWidth = 1;
ctx.fillStyle = "rgba(0,255,0,0.1)";
ctx.lineJoin = "bevel";
ctx.linecap = "square";
};
var clear = function() {
//ctx.save();
ctx.clearRect(
-ctx.canvas.width / 2,
-ctx.canvas.height / 2,
ctx.canvas.width, ctx.canvas.height
);
//drawRectangle(-2, -2, 5, 5);
//ctx.fillStyle = "rgba(32,32,64,1)";
//ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
//ctx.restore();
};
var setLayer = function(layer) {
//ctx.setTransform(0.6, 0.0, 0.4, 0.4, 20+10*layer, 20+60*layer);
var z = -layer * 0.6644 + 0; //*48;
var v6 = 2.44948974278318;
var v2 = 1.4142135623731;
var v3 = 1.73205080756888;
//workign, but sizeways
//ctx.setTransform(v3/v6, 1/v6, 0, v3/v6, -v3/v6*z, 1/v6*z);
/*ctx.setTransform(0.707106781186548, 0.408244363752573,
0, 0.81650050761069, -0.707106781186547 * z, 0.408244363752573 * z);
*/
//ctx.setTransform(-v2/v6, -1/v6, v2/v6, -2/v6, 0, 0, 0);
/*ctx.setTransform(0.707106781186548, 0.577353045773777, -0.707106781186547, 0.577353045773777, 0 * z, 0.577344715981264 * z );
*/
//CORRECT:
ctx.setTransform(0.707106781186548, -0.577353045773777, 0.707106781186547, 0.577353045773777, 0 * z, 0.577344715981264 * z);
//Messing around:
/*ctx.setTransform(0.707106781186548, -0.241844762647975, 0.707106781186547, 0.241844762647975, 0 * z, 0.939692620785908 * z); */
ctx.scale(0.5, 0.5);
ctx.translate(-300, 500);
};
var testBetweenLayers = function() {
makeBox(64, 64, 64, 64, 128, 32);
makeBox(80, 96, 96, 32, 64, 32);
makeBox(64, 256, 64, 32, 32, 32);
makeBox(256, 96, 64, 160, 32, 160);
makeBox(320, 128, 128, 32, 128, 32);
makeBox(256, 256, 64, 160, 32, 160);
};
var boxFaceFront = function(x, y, z, d, w, h) {
ctx.beginPath();
setLayer(z);
ctx.moveTo(x + 0.5, y + 0.5);
setLayer(z + h);
ctx.lineTo(x + 0.5, y + 0.5);
setLayer(z + h);
ctx.lineTo(x + 0.5, y + w + 0.5);
setLayer(z);
ctx.lineTo(x + 0.5, y + w + 0.5);
ctx.closePath();
ctx.fill();
ctx.stroke();
};
var boxFaceSide = function(x, y, z, d, w, h) {
ctx.beginPath();
setLayer(z);
ctx.moveTo(x + 0.5, y + w + 0.5);
setLayer(z + h);
ctx.lineTo(x + 0.5, y + w + 0.5);
setLayer(z + h);
ctx.lineTo(x + d + 0.5, y + w + 0.5);
setLayer(z);
ctx.lineTo(x + d + 0.5, y + w + 0.5);
ctx.closePath();
ctx.fill();
ctx.stroke();
};
var boxFaceTop = function(x, y, z, d, w, h) {
ctx.beginPath();
setLayer(z + h);
ctx.moveTo(x + 0.5, y + 0.5);
setLayer(z + h);
ctx.lineTo(x + 0.5, y + w + 0.5);
setLayer(z + h);
ctx.lineTo(x + d + 0.5, y + w + 0.5);
setLayer(z + h);
ctx.lineTo(x + d + 0.5, y + 0.5);
ctx.closePath();
ctx.fill();
ctx.stroke();
};
var makeBox = function(x, y, z, d, w, h) {
//Sides: 0yz(front), xDz, xyH
ctx.fillStyle = "rgba(128,0,0,0.8)";
ctx.strokeStyle = "#ffff00";
ctx.lineWidth = 3;
ctx.lineCap = "round";
ctx.lineJoin = "round";
boxFaceFront(x, y, z, d, w, h);
boxFaceSide(x, y, z, d, w, h);
boxFaceTop(x, y, z, d, w, h);
};
var drawLine = function(xs, ys, xe, ye, col) {
//O.O("[" + xs + "," + ys + "]-[" + xe + "," + ye + "]\n");
ctx.beginPath();
ctx.moveTo(xs + 0.5, ys + 0.5);
ctx.lineTo(xe + 0.5, ye + 0.5);
//ctx.closePath();
ctx.strokeStyle = col || "#ffff00";
ctx.lineWidth = 1;
//ctx.lineJoin = "round";
//ctx.linecap = "square"
ctx.stroke();
};
var drawLine3d = function(pts,pte, col) {
var ptmaps = _3d.map(pts);
var ptmape = _3d.map(pte);
var cull = false;
if (ptmaps.z < 0) {
cull = true;
}
if (ptmape.z < 0) {
cull = true;
}
if (cull) {
return;
}
ctx.beginPath();
ctx.moveTo(ptmaps.x + 0.5, ptmaps.y + 0.5);
ctx.lineTo(ptmape.x + 0.5, ptmape.y + 0.5);
//ctx.closePath();
ctx.strokeStyle = col || "rgba(255,255,255,0.5)";
ctx.lineWidth = 1;
//ctx.lineJoin = "round";
//ctx.linecap = "square"
ctx.stroke();
};
var drawRectangle = function(xs, ys, w, h) {
ctx.fillStyle = "rgba(255,128,16,1)";
ctx.fillRect(xs, ys, w, h);
};
var drawTri = function(tri) {
Profiler.start("Map");
var pt1 = _3d.map(tri.a);
var pt2 = _3d.map(tri.b);
var pt3 = _3d.map(tri.c);
Profiler.end("Map");
Profiler.start("Canvas");
var col = "#00ff00";
var cull = false;
if (pt1.z < 0) {
cull = true;
}
if (pt2.z < 0) {
cull = true;
}
if (pt3.z < 0) {
cull = true;
}
if (cull) {
col = "#440000";
return;
}
/*drawLine(pt1.x, pt1.y, pt2.x, pt2.y,col);
drawLine(pt2.x, pt2.y, pt3.x, pt3.y,col);
drawLine(pt3.x, pt3.y, pt1.x, pt1.y,col);*/
ctx.beginPath();
ctx.moveTo(pt1.x + 0.05, pt1.y + 0.05);
ctx.lineTo(pt2.x + 0.05, pt2.y + 0.05);
ctx.lineTo(pt3.x + 0.05, pt3.y + 0.05);
ctx.closePath();
//ctx.strokeStyle = col || "#ffff00";
//ctx.lineWidth = 1;
//ctx.fillStyle = "rgba(0,255,0,0.1)";
//attribute DOMString lineCap; // "butt", "round", "square" (default "butt")
//attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter")
//ctx.lineJoin = "bevel";
//ctx.linecap = "square";
if (tri.style){
ctx.fillStyle = tri.style.fill;
ctx.strokeStyle = tri.style.stroke;
}
ctx.fill();
ctx.stroke();
Profiler.end("Canvas");
};
var drawDot = function(pt, colour, s){
var ptmap = _3d.map(pt);
ctx.fillStyle = colour;
var size = s*5000/ptmap.z;
ctx.fillRect(ptmap.x-size/2, ptmap.y-size/2, size, size);
/*ctx.moveTo(ptmap.x-size/2, ptmap.y-size/2);
ctx.arc(ptmap.x-size/2, ptmap.y-size/2, size, 0, 7, false);
ctx.fill();*/
};
return {
init: updateCanvasDimensions,
getWidth: function() {
return ctx.canvas.width;
},
getHeight: function() {
return ctx.canvas.height;
},
Line: drawLine,
Layer: setLayer,
Rect: drawRectangle,
test: testBetweenLayers,
drawTri: drawTri,
drawDot:drawDot,
drawLine3d:drawLine3d,
clear: clear
};
}());
var Tests = (function() {
var tris = [];
var testTetra = function() {
var pt1 = new _3d.Point(100, 100, 10);
var pt2 = new _3d.Point(210, 100, 10);
var pt3 = new _3d.Point(100, 210, 10);
var pt4 = new _3d.Point(100, 100, 210);
var tri1 = new _3d.Tri(pt1, pt2, pt3);
var tri2 = new _3d.Tri(pt2, pt3, pt4);
var tri3 = new _3d.Tri(pt1, pt3, pt4);
var tri4 = new _3d.Tri(pt1, pt2, pt4);
Canvas.drawTri(tri1);
Canvas.drawTri(tri2);
Canvas.drawTri(tri3);
Canvas.drawTri(tri4);
};
var pyramid = function(x, y, w, h,p, col) {
if(!col){ col =[Math.floor(Math.random()*256),
Math.floor(Math.random()*256),
Math.floor(Math.random()*256)];
}
var stroke = "rgba("+0*col[0]+","+0*col[1]+","+0*col[2]+",1.0)";
var fill = "rgba("+col[0]+","+col[1]+","+col[2]+",0.8)";
var style = {stroke:stroke, fill:fill};
var pt1 = new _3d.Point(x, y, 0);
var pt2 = new _3d.Point(x + w, y, 0);
var pt3 = new _3d.Point(x + w, y + h, 0);
var pt4 = new _3d.Point(x, y + h, 0);
var pt5 = new _3d.Point(x + w / 2, y + h / 2, p||50);
//base
tris.push(new _3d.Tri(pt1, pt2, pt3, style));
tris.push(new _3d.Tri(pt1, pt3, pt4, style));
//faces
tris.push(new _3d.Tri(pt1, pt2, pt5, style));
tris.push(new _3d.Tri(pt2, pt3, pt5, style));
tris.push(new _3d.Tri(pt3, pt4, pt5, style));
tris.push(new _3d.Tri(pt4, pt1, pt5, style));
};
var cube = function(x, y, w, h) {
var col =[Math.floor(Math.random()*256),
Math.floor(Math.random()*256),
Math.floor(Math.random()*256)];
var stroke = "rgba("+0*col[0]+","+0*col[1]+","+0*col[2]+",1.0)";
var fill = "rgba("+col[0]+","+col[1]+","+col[2]+",0.8)";
var style = {stroke:stroke, fill:fill};
var d = h;
var pt1 = new _3d.Point(x, y, 0);
var pt2 = new _3d.Point(x + w, y, 0);
var pt3 = new _3d.Point(x + w, y + h, 0);
var pt4 = new _3d.Point(x, y + h, 0);
var pt5 = new _3d.Point(x, y, d);
var pt6 = new _3d.Point(x + w, y, d);
var pt7 = new _3d.Point(x + w, y + h, d);
var pt8 = new _3d.Point(x, y + h, d);
//base
tris.push(new _3d.Tri(pt1, pt2, pt3, style ));
tris.push(new _3d.Tri(pt1, pt3, pt4, style ));
//top
tris.push(new _3d.Tri(pt5, pt6, pt7, style ));
tris.push(new _3d.Tri(pt5, pt7, pt8, style ));
//front
tris.push(new _3d.Tri(pt1, pt5, pt8, style ));
tris.push(new _3d.Tri(pt1, pt4, pt8, style ));
//back
tris.push(new _3d.Tri(pt2, pt6, pt7, style ));
tris.push(new _3d.Tri(pt2, pt3, pt7, style ));
//left
tris.push(new _3d.Tri(pt1, pt5, pt6, style ));
tris.push(new _3d.Tri(pt1, pt2, pt6, style ));
//right
tris.push(new _3d.Tri(pt4, pt3, pt7, style ));
tris.push(new _3d.Tri(pt4, pt8, pt7, style ));
};
var pyramidField = function() {
for (var x = -1500; x < 1500; x += 150) {
for (var y = -1500; y < 1500; y += 150) {
if (Math.random() < 0.2) {
pyramid(x, y, 50, 50,50);
}
else {
if (Math.random() < 0.4) {
cube(x, y, 50, 50);
}
}
}
}
};
/*var makeSolid = function(branch, radius, points){
var step = Math.PI*2/points;
var point1 = null;
for (var i =0; i<Math.PI*2; i+=step){
}
};*/
var tree = function(){
var Stump = {s:new _3d.Point(0,0,0), e:new _3d.Point(0,0,100)};
};
var draw = function() {
Profiler.start("Sort");
/*tris.sort(function(t1, t2){
var t1c = {x:(t1.a.x+t1.b.x+t1.c.x)/3,
y:(t1.a.y+t1.b.y+t1.c.y)/3,
z:(t1.a.z+t1.b.z+t1.c.z)/3};
var t2c = {x:(t2.a.x+t2.b.x+t2.c.x)/3,
y:(t2.a.y+t2.b.y+t2.c.y)/3,
z:(t2.a.z+t2.b.z+t2.c.z)/3};
var t1z = _3d.map(t1c).z;
var t2z = _3d.map(t2c).z;
return t2z-t1z;
});*/
Profiler.end("Sort");
//Profiler.start("Draw");
for (var i = 0; i < tris.length; i++) {
Canvas.drawTri(tris[i]);
}
//Profiler.end("Draw");
};
var grid = function(dx, dy, l){
var col =[Math.floor(Math.random()*256),
Math.floor(Math.random()*256),
Math.floor(Math.random()*256)];
var stroke = "rgba("+0*col[0]+","+0*col[1]+","+0*col[2]+",1.0)";
var fill = "rgba("+col[0]+","+col[1]+","+col[2]+",0.8)";
var style = {stroke:stroke, fill:fill};
var b;
for (var x = -l; x < l; x += dx) {
for (var y = -l; y < l; y += dy) {
b = Math.floor(Math.random()*2)*255;
col = [b,b,b];
stroke = "rgba("+col[0]+","+col[1]+","+col[2]+",1.0)";
fill = "rgba("+col[0]+","+col[1]+","+col[2]+",1.0)";
style = {stroke:stroke, fill:fill};
var pt1 = new _3d.Point(x, y, 0);
var pt2 = new _3d.Point(x + dx, y, 0);
var pt3 = new _3d.Point(x + dx, y + dy, 0);
var pt4 = new _3d.Point(x, y + dy, 0);
tris.push(new _3d.Tri(pt1, pt2, pt3, style ));
tris.push(new _3d.Tri(pt1, pt3, pt4, style ));
}
}
};
var terrain = function(nx,ny,s, h){
var x;
var y;
var vec1;
var vec2;
var normal = [];
var nleng = 0;
//Set up random heights:
var hField = [];
for (x = 0; x < nx+1; x += 1) {
hField[x] = [];
for (y = 0; y < ny+1; y += 1) {
hField[x][y] = Math.floor(Math.random()*h-h/2);
}
}
//Make the map
var stroke = "rgba(0,127,0,1.0)";
var fill = "rgba(128,127,127,1.0)";
var style = {stroke:stroke, fill:fill};
var r,g,b;
for (x = 0; x < nx; x += 1) {
for (y = 0; y < ny; y += 1) {
var pt1 = new _3d.Point(x*s-nx*s/2, y*s-ny*s/2, hField[x][y]);
var pt2 = new _3d.Point(x*s+s-nx*s/2 , y*s-ny*s/2, hField[x+1][y]);
var pt3 = new _3d.Point(x*s+s-nx*s/2, y*s+s-ny*s/2, hField[x+1][y+1]);
var pt4 = new _3d.Point(x*s-nx*s/2, y*s+s-ny*s/2, hField[x][y+1]);
vec1 = [pt1.x-pt2.x, pt1.y-pt2.y, pt1.z-pt2.z];
vec2 = [pt1.x-pt3.x, pt1.y-pt3.y, pt1.z-pt3.z];
normal = [
vec1[1] * vec2[2] - vec1[2] * vec2[1],
vec1[2] * vec2[0] - vec1[0] * vec2[2],
vec1[0] * vec2[1] - vec1[1] * vec2[0]
];
nleng = Math.sqrt(normal[0]*normal[0]+
normal[1]*normal[1]+
normal[2]*normal[2]);
normal = [normal[0]/nleng, normal[1]/nleng, normal[2]/nleng];
r=Math.floor((normal[2])*0);
g=Math.floor((normal[2])*64);
b=Math.floor((normal[2])*0);
//O.O(normal[2]);
fill = "rgba("+r+","+g+","+b+",0.7)";
style = {stroke:stroke, fill:fill};
tris.push(new _3d.Tri(pt1, pt2, pt3, style ));
vec1 = [pt1.x-pt3.x, pt1.y-pt3.y, pt1.z-pt3.z];
vec2 = [pt1.x-pt4.x, pt1.y-pt4.y, pt1.z-pt4.z];
normal = [
vec1[1] * vec2[2] - vec1[2] * vec2[1],
vec1[2] * vec2[0] - vec1[0] * vec2[2],
vec1[0] * vec2[1] - vec1[1] * vec2[0]
];
nleng = Math.sqrt(normal[0]*normal[0]+
normal[1]*normal[1]+
normal[2]*normal[2]);
normal = [normal[0]/nleng, normal[1]/nleng, normal[2]/nleng];
c=Math.floor((normal[2])*255);
fill = "rgba("+r+","+g+","+b+",0.7)";
style = {stroke:stroke, fill:fill};
tris.push(new _3d.Tri(pt1, pt3, pt4, style ));
}
}
};
var dots = (function(){
var list = [];
var lasers = [];
var explosions = [];
var dotSize=1;
var getCount = function(){
return list.length;
};
var create = function(n){
for(var i = 0; i < n; i++){
var x = Math.random()*2000-1000;
var y = Math.random()*2000-1000;
var z = Math.random()*500+50;
var pt = new _3d.Point(x,y,z);
var vec = new _3d.Point(
Math.random()-0.5,
Math.random()-0.5,
Math.random()-0.5
);
var a = new _3d.Point(0,0,0);
var trail = [
pt,pt,pt,pt,pt
];
list.push({p:pt, v:vec, a:a, t:trail, strain:1});
}
};
var createAt = function(x,y,z,t){
var pt = new _3d.Point(x,y,z);
var vec = new _3d.Point(
10*Math.random()-0.5,
10*Math.random()-0.5,
10*Math.random()-0.5
);
var a = new _3d.Point(0,0,0);
var trail = [
pt,pt,pt,pt,pt
];
list.push({
p:pt, v:vec, a:a, t:trail, strain:1, type:t,
maxLife:500,life:500, laserCD:10, laserHeat:0
});
};
var draw = function(){
var i;
var col;
var colStr;
var alpha;
var dmg;
//explosions
for(i = 0; i< explosions.length; i++){
col = Math.floor(255*explosions[i].t/explosions[i].tmax);
colStr = "rgba("+
255+","+
(col)+","+
0+","+0.75+")";
if (explosions[i].smoke){
colStr = "rgba("+
(255-col)+","+
(255-col)+","+
(255-col)+","+0.25+")";
}
var m = explosions[i].size;
var k = 4*m/(explosions[i].tmax*explosions[i].tmax);
var s = m-k*Math.pow((explosions[i].t-explosions[i].tmax/2),2);
Canvas.drawDot(
{x:explosions[i].x,y:explosions[i].y, z:explosions[i].z},
colStr,
s
);
//O.C();
//O.O(explosions.length + colStr+ "|"+JSON.stringify(xxx)); *
}
//shadow
for(i = 0; i< list.length; i++){
col = dotTypes[list[i].type].colour;
colStr = "rgba("+
Math.floor(col.r)+","+
Math.floor(col.g)+","+
Math.floor(col.b)+","+0.1+")";
Canvas.drawDot(
{x:list[i].p.x,y:list[i].p.y, z:0},
"rgba(0,0,0,0.5)",
dotSize
);
Canvas.drawLine3d(
{x:list[i].p.x,y:list[i].p.y, z:0},
{x:list[i].t[0].x,y:list[i].t[0].y, z:0},
"rgba(0,0,0,0.5)"
);
Canvas.drawLine3d(
list[i].p,
{x:list[i].p.x,y:list[i].p.y, z:0},
colStr
);
}
for(i = 0; i< list.length; i++){
if (list[i].strain<0.5){list[i].strain = 0.5;}
if (list[i].strain>2){list[i].strain = 2;}
var x = ((list[i].strain-0.5)/1.5*255);
x = Math.floor(x);
x=x%256;
//var col = "rgba("+x+",255,255,0.75)";
col = dotTypes[list[i].type].colour;
alpha = 1;//0.3+0.7*Math.floor(10-(list[i].life/100)*10)/10;
dmg = 1-list[i].life/list[i].maxLife;
colStr = "rgba("+
Math.floor(dmg*255+(1-dmg)*col.r)+","+
Math.floor(dmg*0+(1-dmg)*col.g)+","+
Math.floor(dmg*0+(1-dmg)*col.b)+","+alpha+")";
Canvas.drawDot(list[i].p, colStr, dotSize);
dmg=0;
colStr = "rgba("+
Math.floor(dmg*255+(1-dmg)*col.r)+","+
Math.floor(dmg*0+(1-dmg)*col.g)+","+
Math.floor(dmg*0+(1-dmg)*col.b)+","+alpha+")";
Canvas.drawLine3d(list[i].p, list[i].t[0], colStr);
}
//lasers
for(i = 0; i< lasers.length; i++){
col = dotTypes[lasers[i].from.type].colour;
alpha = lasers[i].pew*0.2;
colStr = "rgba("+col.r+","+col.g+","+col.b+","+alpha+")";
Canvas.drawLine3d(lasers[i].from.p,lasers[i].to.p, colStr);
}
};
var calculate = function(){
var rules = {
repulse:50,
align:80,
attract:250,
friction:0.995,
cap:200
};
var power = 0;
var dist;
var vec;
var ctr;
var closest;
var closeDist;
for(var i = 0; i< list.length; i++){
ctr=0;
closest = null;
for(var j = 0; j< list.length; j++){
if (i===j){continue;}
dist = Math.sqrt(
Math.pow(list[i].p.x-list[j].p.x,2)+
Math.pow(list[i].p.y-list[j].p.y,2)+
Math.pow(list[i].p.z-list[j].p.z,2)
);
vec = {
x:list[i].p.x-list[j].p.x,
y:list[i].p.y-list[j].p.y,
z:list[i].p.z-list[j].p.z
};
if(
dist < 150 &&
list[i].laserHeat ===0 &&
list[i].type !== list[j].type &&
(closest===null || dist < closeDist)
){
closest = list[j];
closeDist = dist;
}
if (dist<300 && ctr<5){
ctr++;
list[i].v.x -= 1*vec.x/(dist+100);
list[i].v.y -= 1*vec.y/(dist+100);
list[i].v.z -= 1*vec.z/(dist+100);
}
if(dist<400 && ctr>5){
list[i].a.x += 100*vec.x;
list[i].a.y += 100*vec.y;
list[i].a.z += 100*vec.z;
}
if (dist<100){
list[i].v.x += 2*vec.x/(dist+100);
list[i].v.y += 2*vec.y/(dist+100);
list[i].v.z += 2*vec.z/(dist+100);
}
if (dist<25){
list[i].v.x += 100*vec.x/(dist+100);
list[i].v.y += 100*vec.y/(dist+100);
list[i].v.z += 100*vec.z/(dist+100);
}
}
//fire laser!
if(closest !== null){
list[i].laserHeat = list[i].laserCD;
lasers.push({
from:list[i],
to:closest,
pew:5
});
}
//pull towards middle:
dist = Math.sqrt(
Math.pow(list[i].p.x-0,2)+
Math.pow(list[i].p.y-0,2)+
Math.pow(list[i].p.z-500,2)
);
vec = {
x:list[i].p.x-0,
y:list[i].p.y-0,
z:list[i].p.z-500
};
list[i].a.x -= 0.000001*vec.x;
list[i].a.y -= 0.000001*vec.y;
list[i].a.z -= 0.000001*vec.z;
//normalise
var norm = Math.sqrt(
Math.pow(list[i].v.x,2) +
Math.pow(list[i].v.y,2) +
Math.pow(list[i].v.z,2)
);
list[i].strain = norm;
if(norm>2 || norm<0.5){
list[i].v.x= 8 * list[i].v.x/norm;
list[i].v.y= 8 * list[i].v.y/norm;
list[i].v.z= 8 * list[i].v.z/norm;
}
//bouncing
var bncfrc = 1;
if (list[i].p.z<0 && list[i].v.z < 0){
list[i].v.z = -list[i].v.z;
}
if (list[i].p.y<-1000){
list[i].v.y += bncfrc;
}
if (list[i].p.x<-1000){
list[i].v.x += bncfrc;
}
if (list[i].p.z>1000){
list[i].v.z -= bncfrc;
}
if (list[i].p.y>1000){
list[i].v.y -= bncfrc;
}
if (list[i].p.x>1000 ){
list[i].v.x -= bncfrc;
}
/*if(
list[i].p.x < -1000 ||
list[i].p.y < -1000 ||
list[i].p.z < -100 ||
list[i].p.x > 1000 ||
list[i].p.y > 1000 ||
list[i].p.z > 1000
)
{
list[i].p = {x:0, y:0, z:200};
list[i].t = [
list[i].p,list[i].p,list[i].p,list[i].p,list[i].p
];
}*/
}
};
var p = 0;
var update = function(){
p=p+1;
var i;
for(i = 0; i< lasers.length; i++){
lasers[i].pew--;
if(lasers[i].pew <=0){
lasers[i].to.life-=25;
explosions.push({
x:lasers[i].to.p.x+25*(Math.random()-0.5),
y:lasers[i].to.p.y+25*(Math.random()-0.5),
z:lasers[i].to.p.z+25*(Math.random()-0.5),
t:0,
tmax:10,
size:2,
smoke:false
});
lasers.splice(i,1);
i--;
continue;
}
}
for(i = 0; i< explosions.length; i++){
explosions[i].t++;
if(explosions[i].t>=explosions[i].tmax){
if(explosions[i].smoke){
explosions.splice(i,1);
i--;
continue;
}
else
{
explosions[i].smoke = true;
explosions[i].t=0;
explosions[i].tmax=100;
explosions[i].size*=3;
}
}
}
for(i = 0; i< list.length; i++){
if(list[i].life <=0){
explosions.push({
x:list[i].p.x,
y:list[i].p.y,
z:list[i].p.z,
t:0,
tmax:50,
size:5,
smoke:false
});
list.splice(i,1);
i--;
continue;
}
/*if(list[i].life<list[i].maxLife){
list[i].life++;
}*/
if(list[i].laserHeat > 0){
list[i].laserHeat--;
}
list[i].p.x = list[i].p.x + list[i].v.x;
list[i].p.y = list[i].p.y + list[i].v.y;
list[i].p.z = list[i].p.z + list[i].v.z;
list[i].v.x = list[i].v.x + list[i].a.x;
list[i].v.y = list[i].v.y + list[i].a.y;
list[i].v.z = list[i].v.z + list[i].a.z;
if(p%1===0){
p=0;
list[i].t.shift();
list[i].t.push(new _3d.Point(
list[i].p.x,
list[i].p.y,
list[i].p.z
));
}
}
};
return {
create:create,
draw:draw,
update:update,
calculate:calculate,
createAt:createAt,
getCount:getCount
};
}());
var dotTypes=[
{colour:{r:255,g:96,b:96}},
{colour:{r:96,g:96,b:255}},
{colour:{r:96,g:255,b:96}},
{colour:{r:255,g:96,b:255}},
{colour:{r:255,g:255,b:255}}
];
var game = (function(){
var spawners=[];
var newSpawner = function(x,y,t,p,n,z){
spawners.push({
t:t,
x:x,
y:y,
z:z,
period:p,
tick:0,
num:n
});
pyramid(x,y,40,40,z);
};
var tick = function(){
//O.C();
//O.O(dots.getCount());
if (dots.getCount() > 200){return;}
for(var i =0; i<spawners.length; i++){
spawners[i].tick++;
if(spawners[i].tick > spawners[i].period){
spawners[i].tick = 0;
for (var j = 0; j<spawners[i].num; j++){
dots.createAt(
spawners[i].x,
spawners[i].y,
spawners[i].z,
spawners[i].t
);
}
}
}
};
return{
newSpawner:newSpawner,
tick:tick
};
}());
return {
test1: testTetra,
test2: pyramidField,
draw: draw,
grid: grid,
ter:terrain,
pyramid :pyramid,
dots:dots,
game:game
};
}());
var Flier = (function(){
var loc = {x:120, y: 100, z:300};
var face = {tx: Math.PI / 2, ty:0, tz:0};
var step = 10;
var mouseLast = null;
var moveForward = function(){
loc.y+=step;
};
var moveBackward = function(){
loc.y-=step;
};
var moveLeft = function(){
loc.x-=step;
};
var moveRight = function(){
loc.x+=step;
};
var moveDown = function(){
loc.z-=step;
};
var moveUp = function(){
loc.z+=step;
};
var handler = function(e){
switch(e.keyCode)
{
case 37: Flier.l();break;
case 38: Flier.f();break;
case 39: Flier.r();break;
case 40: Flier.b();break;
case 32: Flier.u();break;
case 67: Flier.d();break;
case 13: paused = !paused; break;
case 116:alert("NO!");return false;
default:
alert(e.keyCode);
break;
}
Flier.remap();
};
var update = function(){
_3d.set([loc.x, loc.y, loc.z], [face.tx, face.ty, face.tz], [0, 0, 250]);
Canvas.clear();
Tests.draw();
};
return {
u:moveUp,
d:moveDown,
l:moveLeft,
r:moveRight,
f:moveForward,
b:moveBackward,
h:handler,
remap:update
};
}());
$(function(){
O.S("output");
Canvas.init();
_3d.set([1200, 1200, 100], [0, 0, 0], [0, 0, 20]);
Tests.ter(5,5,400, 80);
//Tests.pyramid(-20,-20,40,40,200);
//Tests.pyramid(200,-20,40,40,100);
//Tests.dots.create(200);
Tests.game.newSpawner(-900,900,0,200,5,500);
//Tests.game.newSpawner(-600,900,0,200,1,100);
//Tests.game.newSpawner(-900,600,0,200,1,100);
Tests.game.newSpawner(900,-900,1,200,5,500);
//Tests.game.newSpawner(600,-900,1,200,1,100);
//Tests.game.newSpawner(900,-600,1,200,1,100);
Tests.game.newSpawner(-900,-900,2,200,5,500);
//Tests.game.newSpawner(-600,-900,2,200,1,100);
//Tests.game.newSpawner(-900,-600,2,200,1,100);
Tests.game.newSpawner(900,900,3,200,5,500);
//Tests.game.newSpawner(600,900,3,200,1,100);
//Tests.game.newSpawner(900,600,3,200,1,100);
Tests.game.newSpawner(0,0,4,4000,35,200);
var ang = 0;
var up = false;
var h = 800;
var rad = 2500;
window.setInterval(function() {
Canvas.clear();
_3d.set([rad*Math.cos(ang), rad*Math.sin(ang), h+500], [Math.PI / 2 + Math.PI/4 * ((h-400) / 600), 0, 3*Math.PI/2-ang], [0, 0, 500]);
Tests.draw();
Tests.dots.update();
Tests.dots.calculate();
Tests.dots.draw();
Tests.game.tick();
if (up) {
//h++;
} else {
//h--;
}
if (h < 200) {
up = true;
}
if (h > 800) {
up = false;
}
ang += 0.002;
/*Profiler.start("Output");
O.C();
O.O(Profiler.output());
Profiler.end("Output");*/
//Tests.dots.create(1);
}, 33);
});
});
//]]>
</script>
</head>
<body>
<canvas id="canvas"></canvas>
<div id="output">
</div>
<div id="test"></div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment