Advertisement
Guest User

awiudbiuawdb

a guest
Jan 24th, 2020
113
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <script src="https://koda.nu/simple.js">
  2.  
  3.   // Get canvas
  4.   let ctx = document.getElementById("canvas").getContext("2d");
  5.   ctx.imageSmoothingEnabled = false;
  6.  
  7.   let realUpdatesPerSecond = 0;
  8.   let fps = 0;
  9.  
  10.   // Degrees to radians
  11.   function rad(a) {
  12.     return a * (pi / 180);
  13.   }
  14.  
  15.   // Radians to degrees
  16.   function deg(a) {
  17.     return a * (180 / pi);
  18.   }
  19.    
  20.   // Find quadrant of an angle in degrees
  21.   function quadOf(a) {
  22.     return (floor(abs(360-a%360)/90))%4;
  23.   }
  24.  
  25.   let map = [
  26.     [1,1,3,1,3,1,1],
  27.     [1,0,0,0,0,0,1],
  28.     [3,0,0,2,0,0,3],
  29.     [1,0,2,2,2,0,1],
  30.     [3,0,0,2,0,0,3],
  31.     [1,0,0,0,0,0,1],
  32.     [1,1,3,1,3,1,1],    
  33.   ];
  34.  
  35.   let wallTexture = new Image();
  36.   wallTexture.src = "http://www.areyep.com/Texturelibrary/walltextures/WoodbrickL.gif";
  37.   let wallFlag = new Image();
  38.   wallFlag.src = "http://www.areyep.com/Texturelibrary/walltextures/WoodbrickeagleL.gif";
  39.   let brickTexture = new Image();
  40.   brickTexture.src = "http://www.areyep.com/Texturelibrary/walltextures/BluegreyL.gif";
  41.  
  42.   let styles = [
  43.     wallTexture,
  44.     brickTexture,
  45.     wallFlag,
  46.     [0,255,0]
  47.   ];
  48.  
  49.   let entities = [];
  50.  
  51.   //Draw darkening transparent rectangle
  52.   function darkerRect(x,y,a,b,n) {
  53.     ctx.beginPath();
  54.     ctx.rect(x,y,a,b);
  55.     ctx.closePath();
  56.     ctx.fillStyle = "rgba(0,0,0,"+n+")";
  57.     ctx.fill();
  58.   }
  59.  
  60.   class Entity {
  61.     constructor(x,y,width,isRotationAnchored=false,ang=0) {
  62.       this.x = x;
  63.       this.y = y;
  64.       this.width = width;
  65.       this.isRotationAnchored = isRotationAnchored;
  66.       this.ang = ang;
  67.     }
  68.   }
  69.  
  70.   class Player {
  71.     constructor(x,y,ang=0) {
  72.       this.x = x;
  73.       this.y = y;
  74.       this.xv = 0;
  75.       this.yv = 0;
  76.       this.rot = ang;
  77.      
  78.       this.projDist = 170; // Increase fov by lowering the distance of the projection screen
  79.     }
  80.    
  81.     traceRayGrid(ang) {
  82.       // Get necessary values for ray tracing
  83.       let foundWall = 0;
  84.       let closestPointDist = 0;
  85.       let pointOnWall; // Find where along the wall ray hit to draw textures
  86.       let quadrant = quadOf(ang);
  87.      
  88.       let ox = this.x % 1;
  89.       let oy = this.y % 1;
  90.       let xIter = 0; // Amount of iterations among X intersections
  91.       let yIter = 0; // Amounf of iterations among Y intersections
  92.       let xDir, yDir; // Defines if x and y is positive or negative (= 1 or -1) in the current quadrant
  93.      
  94.       // Setup xDir/yDir depending on quadrant
  95.       if (quadrant === 0) {
  96.         xDir =  1;
  97.         yDir = -1;
  98.       } else if (quadrant === 1) {
  99.         xDir = -1;
  100.         yDir = -1;
  101.       } else if (quadrant === 2) {
  102.         xDir = -1;
  103.         yDir =  1;
  104.       } else if (quadrant === 3) {
  105.         xDir =  1;
  106.         yDir =  1;
  107.       }
  108.      
  109.       // Setup rest of variables
  110.       let xIntersect = this.x + ((.5+.5*yDir)-oy) / tan(rad(ang)); // X pos of first X intersection
  111.       let yIntersect = this.y + ((.5+.5*xDir)-ox) * tan(rad(ang)); // Y pos of first Y intersection
  112.       let xStep = 1/tan(rad(ang)) * yDir; // Step in X between X intersections
  113.       let yStep = tan(rad(ang)) * xDir; // Step in Y between Y intersections
  114.       let x = floor(this.x) + .5+.5*xDir; // X pos of first Y intersection
  115.       let y = floor(this.y) + .5+.5*yDir; // Y pos of first X intersection
  116.      
  117.       let distToNextXIntersect, distToNextYIntersect;
  118.      
  119.       // Perform ray trace  
  120.       while (foundWall === 0) {
  121.         // Find distance to next intersection for both axis
  122.         distToNextXIntersect = sqrt((xIntersect + xIter*xStep - this.x)**2 + (y - this.y)**2);
  123.         distToNextYIntersect = sqrt((yIntersect + yIter*yStep - this.y)**2 + (x - this.x)**2);
  124.  
  125.         if (distToNextXIntersect < distToNextYIntersect) {
  126.           // X intersection is closest, look for a wall
  127.           if (map[y - .5+.5*yDir][floor(xIntersect + xIter*xStep)]) {
  128.             // Wall on current X intersection point, draw rectangle at intersected square
  129.             foundWall = map[y - .5+.5*yDir][floor(xIntersect + xIter*xStep)];
  130.             pointOnWall = .5 + .5*yDir - (xIntersect + xIter*xStep) % 1 * yDir; // Flip the image based on quadrant to always get the right image
  131.             closestPointDist = distToNextXIntersect;
  132.           } else {
  133.             // No wall found, iterate
  134.             xIter++;
  135.             y += yDir;
  136.           }
  137.          
  138.         } else {
  139.           // Y intersection is closest, look for a wall
  140.           if (map[floor(yIntersect + yIter*yStep)][x - .5+.5*xDir]) {
  141.             // Wall on current Y intersection point, draw rectangle at intersected square
  142.             foundWall = map[floor(yIntersect + yIter*yStep)][x - .5+.5*xDir];
  143.             pointOnWall = .5 - .5*xDir + (yIntersect + yIter*yStep) % 1 * xDir;
  144.             closestPointDist = distToNextYIntersect;
  145.           } else {
  146.             // No wall found, iterate
  147.             yIter++;
  148.             x += xDir;
  149.           }
  150.         }
  151.       }
  152.          
  153.       return {closestPoint: closestPointDist, wallType: foundWall-1, pointOnWall: pointOnWall};
  154.     }
  155.    
  156.     traceRayLine(x1,y1,x2,y2,x3,y3,x4,y4) { // 1,2 is entity; 3,4 is ray
  157.       let d = (x1-x2)*(y3-y4)-(y1-y2)*(x3-x4); // Denominator
  158.      
  159.       if (d != 0) { // Lines are not parallell
  160.         let t = (x1-x3)*(y3-y4)-(y1-y3)*(x3-x4) / d;
  161.         let u = -(x1-x2)*(y1-y3)-(y1-y2)*(x1-x3) / d;
  162.        
  163.         console.log("not parallel" + " t: "+t+" u: "+u);
  164.        
  165.         // If rays intersect find dist and point on line
  166.         if (t>0 && t<1 && u>0) {
  167.           console.log("intersects");
  168.           let xIntersect = x1 + t*(x2-x1);
  169.           let yIntersect = y1 + t*(y2-y1);
  170.           let dist = sqrt((xIntersect-this.x)**2 + (yIntersect-this.y)**2);
  171.           let pointOnLine;
  172.          
  173.           // Use X delta to find point on line if not 0, else use Y
  174.           let xd = x1 - x2;
  175.           if (xd != 0) {
  176.             pointOnLine = (xIntersect - x1) / xd;
  177.           } else {
  178.             let yd = y1 - y2;
  179.             pointOnLine = (yIntersect - y1) / yd
  180.           }
  181.           return {dist: dist, pointOnLine: pointOnLine};
  182.         } else {
  183.           return false;
  184.         }
  185.       } else {
  186.         return false;
  187.       }
  188.     }
  189.    
  190.     draw2d() {
  191.       let gridSize = 20;
  192.       let xOffset = 100;
  193.       let yOffset = 100;
  194.      
  195.       for (let y=0; y<map.length; y++) {
  196.         for (let x=0; x<map[y].length; x++) {
  197.           if (map[y][x] != 0) {
  198.             let type = map[y][x];
  199.             let style = styles[type-1];
  200.            
  201.             if (style.constructor === Array) {
  202.               // If color
  203.               rectangle(xOffset + x*gridSize,yOffset + y*gridSize,gridSize,gridSize,mixColor(style[0],style[1],style[2]));
  204.             } else if (typeof style == "object") {
  205.               // If texture
  206.               ctx.drawImage(style, xOffset + x*gridSize,yOffset + y*gridSize,gridSize,gridSize);
  207.             }
  208.           }
  209.         }
  210.       }
  211.      
  212.       // Draw player last
  213.       circle(xOffset + (this.x * gridSize),yOffset + (this.y * gridSize),6,"orange");
  214.       line(xOffset + (this.x * gridSize),yOffset + (this.y * gridSize),xOffset + (this.x * gridSize) + 16 * cos(rad(this.rot)),yOffset + (this.y * gridSize) + 16 * sin(rad(this.rot)),2,"orange");
  215.     }
  216.    
  217.     draw3d() {
  218.       let trace, dist, wallSize, trueAng;
  219.       let distLen = 10; // How far the player can see colors/textures
  220.       let distK = 1000; // Constant that changes how "large" everything looks (larger constant -> taller walls)
  221.       let vpWidth = totalWidth;
  222.       let vpHeight = totalHeight;
  223.       let columns = floor(vpWidth/6); // Amount of "pixels" in the x axis
  224.       let rows = floor(vpHeight/10); // Amount of "pixels" in the y axis
  225.       let pixelHeight = vpHeight / rows;
  226.       let fov = deg(Math.atan(vpWidth / this.projDist));
  227.       let columnWidth = vpWidth/columns;
  228.      
  229.       let applyShadingToTextures = false;
  230.      
  231.       // First draw "floor" and "ceiling"
  232.       rectangle(0,vpHeight/2,vpWidth,vpHeight/2,"darkgrey");
  233.       rectangle(0,0,vpWidth,vpHeight/2,"grey");
  234.      
  235.       for (let i=0; i<columns; i+=fov/columns) {
  236.         trueAng = deg(Math.atan((i-columns/2) / this.projDist)) + this.rot;
  237.         trace = this.traceRayGrid(trueAng);
  238.         dist = trace.closestPoint * cos(rad(trueAng-this.rot));
  239.         wallSize = floor((distK/dist)/pixelHeight)*pixelHeight; // Make wall sizes look "pixelated"
  240.        
  241.         // Draw texture or color
  242.         if (styles[trace.wallType].constructor === Array) {
  243.           rectangle(i*columnWidth,(vpHeight-wallSize)/2,columnWidth*fov/columns+1,wallSize,mixColor((1-dist/distLen)*styles[trace.wallType][0],(1-dist/distLen)*styles[trace.wallType][1],(1-dist/distLen)*styles[trace.wallType][2]));
  244.         } else if (typeof styles[trace.wallType] == "object") {
  245.           let img = styles[trace.wallType];
  246.           ctx.drawImage(img, floor(trace.pointOnWall * img.naturalWidth), 0, 1, img.naturalHeight, i*columnWidth, (vpHeight-wallSize)/2, columnWidth*fov/columns+1, wallSize);
  247.           // Draw transparent rectangle on top to darken at distances if setting is on
  248.           if (applyShadingToTextures) {
  249.             darkerRect(i*columnWidth,(vpHeight-wallSize)/2,columnWidth*fov/columns,wallSize,dist/distLen);
  250.           }
  251.         } else {
  252.           rectangle(i*columnWidth,(vpHeight-wallSize)/2,columnWidth*fov/columns+1,wallSize,mixColor((1-dist/distLen)*255,(1-dist/distLen)*255,(1-dist/distLen)*255));
  253.         }
  254.        
  255.         // Trace all entities in range and draw the closest one
  256.         /*
  257.         let closestEntDist = 2;
  258.         let closestEnt;
  259.         for (let ent=0; ent<entities.length; ent++) {
  260.           let entity = entities[ent];
  261.           // Only check if closer/close enough
  262.           if (Math.sqrt((entity.x-this.x)**2+(entity.y-this.y)**2) < closestEntDist) {
  263.             let xPointDist, yPointDist;
  264.             if (entity.isRotationAnchored == false) {
  265.               xPointDist = entity.width * Math.cos(rad(this.rot-0));
  266.               yPointDist = entity.width * Math.sin(rad(this.rot-0));
  267.             } else {
  268.               xPointDist = entity.width * Math.cos(rad(entity.rot-90));
  269.               yPointDist = entity.width * Math.sin(rad(entity.rot-90));
  270.             }
  271.             let entTrace = this.traceRayLine(entity.x+xPointDist,entity.y+yPointDist,entity.x-xPointDist,entity.y-yPointDist,this.x,this.y,Math.cos(rad(trueAng)),Math.sin(rad(trueAng)));
  272.             closestEntDist = entTrace.dist;
  273.             closestEnt = entity;
  274.           }
  275.         }
  276.        
  277.         if (closestEntDist < 2) {
  278.           let entDrawSize = floor((100/distance(this.x,this.y,closestEnt.x,closestEnt.y))/pixelHeight)*pixelHeight;
  279.           text(0,20,20,closestEntDist);
  280.           rectangle(i*columnWidth,(vpHeight-entDrawSize)/2,columnWidth*fov/columns+1,entDrawSize,"grey");
  281.         }*/
  282.       }
  283.     }
  284.    
  285.     doInputCalculations() {
  286.       if (keyboard.right) {this.rot += 50 / realUpdatesPerSecond}
  287.       if (keyboard.left) {this.rot -= 50 / realUpdatesPerSecond}
  288.      
  289.       if (player.rot > 360) {player.rot -= 360}
  290.       if (player.rot < 0) {player.rot += 360}
  291.      
  292.       let xMovement = cos(rad(this.rot)) * .4 / realUpdatesPerSecond;
  293.       let yMovement = sin(rad(this.rot)) * .4 / realUpdatesPerSecond;
  294.  
  295.       if (keyboard.w) {
  296.         this.xv += xMovement;
  297.         this.yv += yMovement;
  298.       }
  299.       if (keyboard.s) {
  300.         this.xv -= xMovement;
  301.         this.yv -= yMovement;
  302.       }
  303.       if (keyboard.a) {
  304.         this.xv += yMovement;
  305.         this.yv -= xMovement;
  306.       }
  307.       if (keyboard.d) {
  308.         this.xv -= yMovement;
  309.         this.yv += xMovement;
  310.       }
  311.     }
  312.    
  313.     doPhysicsCalculations() {
  314.       // Friction
  315.       this.xv *= .9;
  316.       this.yv *= .9;
  317.      
  318.       let maxVel = 1.5 / realUpdatesPerSecond;
  319.      
  320.       let velVectorAngle = Math.atan(this.yv / this.xv);
  321.       let maxVelX = abs(maxVel * cos(velVectorAngle));
  322.       let maxVelY = abs(maxVel * sin(velVectorAngle));
  323.      
  324.       // Cap out velocity
  325.       if (this.xv > maxVelX) {
  326.         this.xv = maxVelX;
  327.       } else if (this.xv < -maxVelX) {
  328.         this.xv = -maxVelX;
  329.       }
  330.       if (this.yv > maxVelY) {
  331.         this.yv = maxVelY;
  332.       } else if (this.yv < -maxVelY) {
  333.         this.yv = -maxVelY;
  334.       }
  335.     }
  336.    
  337.     doCollisionCalculations() {
  338.       // Yes I know this is cheap and sucks but I can't be bothered to make a better one rn
  339.       let xvDir = this.xv/abs(this.xv) || 1;
  340.       if (map[floor(this.y)][floor(this.x+this.xv+.1*xvDir)] != 0) {
  341.         this.xv = 0;
  342.         this.yv *= .8; //Simulate friction while sliding against the wall
  343.       }
  344.       let yvDir = this.yv/abs(this.yv) || 1;
  345.       if (map[floor(this.y+this.yv+.1*yvDir)][floor(this.x)] != 0) {
  346.         this.yv = 0;
  347.         this.xv *= .8; //Simulate friction while sliding against the wall
  348.       }
  349.     }
  350.    
  351.     applyVelocity() {
  352.       this.x += this.xv;
  353.       this.y += this.yv;
  354.     }
  355.   }
  356.  
  357.   let player = new Player(1.5,1.5,0);
  358.   let testEnt = new Entity(3.5,1.5,.2);
  359.   entities[0] = testEnt;
  360.  
  361.   updatesPerSecond = 90;
  362.  
  363.   let lastUpdateTime = performance.now();
  364.  
  365.   function update() {
  366.     clearScreen();
  367.    
  368.     player.doInputCalculations();
  369.     player.doPhysicsCalculations();
  370.     player.doCollisionCalculations();
  371.     player.applyVelocity();
  372.    
  373.     if (keyboard.up) {
  374.       player.projDist += 2;
  375.     } else if (keyboard.down) {
  376.       player.projDist -= 2;
  377.       if (player.projDist == 0) {
  378.         player.projDist = 2;
  379.       }
  380.     }
  381.    
  382.     player.draw3d();
  383.     if (keyboard.m) {
  384.       player.draw2d();
  385.     }
  386.    
  387.     realUpdatesPerSecond = floor(1000/(performance.now()-lastUpdateTime));
  388.     // Only update fps counter every once in a while to make it more readable
  389.     let updateFpsCounter = ((floor(performance.now() / 10) % 20) === 0);
  390.     if (updateFpsCounter) {
  391.       fps = realUpdatesPerSecond;
  392.     }
  393.     text(0,10,10,fps + " fps","black");
  394.     lastUpdateTime = performance.now();
  395.   }
  396.  
  397. </script>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement