candyapplecorn

QT Source

Dec 5th, 2014
273
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // COPYRIGHT CANDYAPPLECORN 2014
  2. // ALL RIGHTS RESERVED
  3. // Send me an email at [email protected] if you'd like to use this script
  4. // otherwise this script is copyrighted under the
  5. // http://creativecommons.org/licenses/by-nc-nd/4.0/
  6. // license
  7.  
  8. var c = document.getElementById("myCanvas");
  9.         var ctx = c.getContext('2d');
  10.         var gravity = 9.8;
  11.         var objects = 100;
  12.  
  13.         function quadTree(x, y, w){
  14.           // data - this could be a seperate object if written in C++
  15.           this. entities = [];
  16.  
  17.           // child nodes
  18.           this. children = [null, null, null, null];
  19.  
  20.           // node info
  21.           this. bounds = { x: x, y: y, x2: x + w, y2: y + w };
  22.  
  23.           this. center = { x: x + w / 2, y: y + w / 2 };
  24.  
  25.           this. width = w;
  26.  
  27.           this. maxEntities = 4;
  28.  
  29.           // functions
  30.  
  31.           // ------------------------------------------------
  32.           // boundsCheck returns true if co is out of bounds.
  33.           // invert its value to see if co is within bounds.
  34.           // if extra parameters sent, checks to see if co is
  35.           // within bounds of the parameterized square
  36.           this. boundsCheck = function (co, x, y, w) {
  37.             if (x == null)
  38.               return co.x < this.bounds.x || co.x > this.bounds.x2 || co.y < this.bounds.y || co.y > this.bounds.y2;
  39.             return co.x < x || co.x > x + w || co.y < y || co.y > y + w;
  40.           };
  41.  
  42.           // ------------------------------------------------
  43.           // childrenNull returns true if all children are null
  44.           this. childrenNull = function(){
  45.             return this.children[0] == null && this.children[1] == null && this.children[2] == null && this.children[3] == null;
  46.           };
  47.  
  48.           // ------------------------------------------------
  49.           // useless returns true if this node is void of children AND data
  50.           this. useless = function(){
  51.             return this.entities.length === 0 && this.childrenNull();
  52.           };
  53.  
  54.           // ------------------------------------------------
  55.           // which takes a coordinate and finds its quadrant.
  56.           // 0 = ne, 1 = se, 2 = sw, 3 = nw
  57.           this. which = function(co){
  58.             if      (co.x > this.center.x && co.y > this.center.y)     return 0;
  59.             else if (co.x > this.center.x && co.y <= this.center.y)    return 1;
  60.             else if (co.x <= this.center.x && co.y <= this.center.y)   return 2;
  61.             else if (co.x <= this.center.x && co.y > this.center.y)    return 3;
  62.           };
  63.  
  64.           // ------------------------------------------------
  65.           // split defines each null child.
  66.           this. split = function(){
  67.             this.children[0] = new quadTree (this.center.x, this.bounds.y, this.width/2);
  68.             this.children[1] = new quadTree (this.center.x, this.center.y, this.width/2);
  69.             this.children[2] = new quadTree (this.bounds.x, this.center.y, this.width/2);
  70.             this.children[3] = new quadTree (this.bounds.x, this.bounds.y, this.width/2);
  71.           };
  72.  
  73.           this. insert = function(co){
  74.             if(this.boundsCheck(co))
  75.               return false;
  76.  
  77.             if(this.entities.length < this.maxEntities){
  78.               this.entities.push(co);
  79.               return true;
  80.             }
  81.  
  82.             if(this.children[0] == null)
  83.               this.split();
  84.  
  85.             if (this.children[0].insert(co)) return true;
  86.             if (this.children[1].insert(co)) return true;
  87.             if (this.children[2].insert(co)) return true;
  88.             if (this.children[3].insert(co)) return true;
  89.           };
  90.  
  91.           // ------------------------------------------------
  92.           // getRange takes an optional range and returns an array
  93.           // of all data stored within nodes in that range.
  94.           this. getRange = function(x, y, w){
  95.             var results = [], self = this;
  96.             // IF NO RANGE PARAMETERS, GET EVERYTHING
  97.             if (x == null && y == null && w == null){
  98.  
  99.               for (var counter = 0; counter < this.entities.length; counter++)
  100.                 if(this.entities[counter] != null)
  101.                   results.push(this.entities[counter]);
  102.  
  103.               for (var counter2 = 0; counter2 < 4; counter2++) // unknown scope error
  104.                 if(this.children[counter2] != null){
  105.                   var tmp = this.children[ counter2 ].getRange();
  106.                   for(var counter3 = 0; counter3 < tmp.length; counter3++)
  107.                     if(tmp[counter3])
  108.                       results.push(tmp[counter3]);
  109.                 }
  110.  
  111.               return results;
  112.             }
  113.  
  114.             // x or y or w aren't null. check for bad input.
  115.             if (x == null || y == null || w == null) return;
  116.  
  117.             var x2 = x + w, y2 = y + w;
  118.             this.entities.forEach(function(element, index, array){
  119.               if(! self.boundsCheck(element, x, y, w) ) results.push( element );
  120.             });
  121.             // CAN BE OPTIMIZED - CURRENTLY ISN'T!
  122.             this.children.forEach(function(element, index, array){
  123.               if(element){
  124.                 var temp = self.children[index].getRange(x, y, w);
  125.                 temp.forEach(function(element, index, array){
  126.                   if (element)
  127.                     results.push(element);
  128.                 });
  129.               }
  130.             });
  131.             return results;
  132.           };
  133.         }
  134.  
  135.         quadTree.prototype.update = function(){
  136.           var self = this; // EXTREEEMELY IMPORTANT, forEach overrides "this"
  137.           this.entities.forEach(function (e, i, a){
  138.             self.collision();
  139.             var x = Math.floor(e.speed * e.hor);
  140.             var y = Math.floor(e.speed * e.ver);
  141.             e.x += x > 0 ? x + 1 : x - 1;
  142.             e.y += y > 0 ? y + 1 : y - 1;
  143.             if (e.x > c.width || e.x < 0 || e.y > c.height || e.y < 0)
  144.               a.splice(i, 1);
  145.           });
  146.           for(var counter = 0; counter < this.children.length; counter++){
  147.             if (this.children[counter])
  148.               this.children[counter].update();
  149.           }
  150.         };
  151.  
  152.         quadTree.prototype.draw = function(){
  153.           for(var counter = 0; counter < 4; counter++)
  154.             if ( this.children[counter] )
  155.               this.children[counter].draw();
  156.  
  157.  
  158.           for(var counter2 = 0; counter2 < this.entities.length; counter2++)
  159.             if(this.entities[counter2]){
  160.               ctx.fillStyle = "green";
  161.               ctx.beginPath();
  162.               ctx.arc(this.entities[counter2].x, this.entities[counter2].y, 3, 0, 2 * Math.PI, true);
  163.               ctx.fill();
  164.               ctx.stroke();
  165.             }
  166.           if (this.entities.length){
  167.             ctx.strokeStyle = "black";
  168.             ctx.lineWidth = 1;
  169.             ctx.beginPath();
  170.             ctx.moveTo(this.bounds.x, this.center.y);
  171.             ctx.lineTo(this.bounds.x2, this.center.y);
  172.             ctx.stroke();
  173.             ctx.beginPath();
  174.             ctx.moveTo(this.center.x, this.bounds.y);
  175.             ctx.lineTo(this.center.x, this.bounds.y2);
  176.             ctx.stroke();
  177.           }
  178.         };
  179.  
  180.         quadTree.prototype.collision = function(){
  181.           if (this.entities.length > 1){
  182.             this.entities.forEach(function(element, index, array){
  183.               for(var counter = 0; counter < array.length; counter++){
  184.                 if (counter == index)
  185.                   continue;
  186.                 var distance = Math.sqrt((element.x - array[counter].x) * (element.x - array[counter].x) + (element.y - array[counter].y) * (element.y - array[counter].y));
  187.                 if(distance < 6){
  188.                   element.hor = Math.cos( Math.random() * 2 * Math.PI );
  189.                   element.ver = Math.sin( Math.random() * 2 * Math.PI );
  190.                   array[counter].hor = element.ver;
  191.                   array[counter].ver = element.hor;
  192.                 }
  193.               }
  194.             });
  195.           }
  196.         };
  197.  
  198.         function entity( x1, y1, speed1, hor1, ver1){
  199.           this.x = x1 || 0;
  200.           this.y = y1 || 0;
  201.           // Extra stuff:
  202.           this.speed = speed1 || 1;
  203.           this.hor = hor1 || 1/2;
  204.           this.ver = ver1 || 1/2;
  205.         }
  206.  
  207.         var q = new quadTree(0, 0, c.width);
  208.  
  209.         for(var counter = 0; counter < objects; counter++){
  210.           q.insert(
  211.             new entity(
  212.               Math.floor(c.width/2),//Math.random() * c.width),
  213.               Math.floor(c.height/2),//Math.random() * c.height),
  214.               Math.random() * gravity,
  215.               Math.cos( Math.random() * 2 * Math.PI ),
  216.               Math.sin( Math.random() * 2 * Math.PI )
  217.             )
  218.           );
  219.         }
  220.  
  221.         function animate(){
  222.           var form = document.getElementById("form");
  223.           objects = form.elements[0].value;
  224.           gravity = form.elements[1].value;
  225.           q.update();
  226.           var newE = q.getRange();
  227.           q = new quadTree(0, 0, c.width);
  228.           document.getElementById("below").innerHTML = "There are " + newE.length + " objects.";
  229.           for(var counter2 = 0; counter2 < objects - newE.length; counter2++){
  230.             q.insert(
  231.               new entity(
  232.                 Math.floor(c.width/2),//Math.random() * c.width),
  233.                 Math.floor(c.height/2),//Math.random() * c.height),
  234.                 Math.random() * gravity,
  235.                 Math.cos( Math.random() * 2 * Math.PI ),
  236.                 Math.sin( Math.random() * 2 * Math.PI )
  237.               )
  238.             );
  239.           }
  240.           for(var counter = 0; counter < newE.length; counter++){
  241.             q.insert(newE[counter]);
  242.           }
  243.           ctx.fillStyle = "#FFFFFF";
  244.           ctx.fillRect(0, 0, c.width, c.height);
  245.           q.draw();
  246.         }
  247.  
  248.           function Quad_Tree_Initializer(){
  249.   var quadTreeDIV = document.getElementById("quadTree");
  250. quadTreeDIV.active = false;
  251.  
  252.   var interv = setInterval(animate, 1000/30);
  253.   window.setTimeout(clearInterval, 1000, interv);
  254.  
  255. quadTreeDIV.addEventListener('mouseover', function(){
  256.   if(!quadTreeDIV.active)
  257.   quadTreeDIV.interv = setInterval(animate, 1000/30);
  258.   quadTreeDIV.active = true;
  259. });
  260.  
  261. quadTreeDIV.addEventListener('mouseout', function(){
  262.   clearInterval(quadTreeDIV.interv);
  263.   quadTreeDIV.active = false;
  264. })
  265. }
  266.  
  267. Quad_Tree_Initializer();
Advertisement
Add Comment
Please, Sign In to add comment