Browse Source

implement raycasting

Kyle Perik 1 year ago
parent
commit
fee6e9d731
1 changed files with 49 additions and 38 deletions
  1. 49 38
      index.js

+ 49 - 38
index.js

@@ -1,25 +1,24 @@
1
-
2
-// Example
1
+function range(n) {
2
+    if (n <= 0) return [];
3
+    return range(n - 1).concat([n - 1]);
4
+}
3 5
 
4 6
 const canvas = document.getElementById('pixelCanvas');
5 7
 
8
+canvas.width = document.body.clientWidth;
9
+canvas.height = document.body.clientHeight;
10
+
6 11
 var initialState = {
7 12
     mouse: {
8 13
         x: 20,
9 14
         y: 20,
10 15
     },
11
-    lines: [
12
-        { s: { x: 10, y: 32 }, e: { x: 15, y: 45 } },
13
-        { s: { x: 15, y: 45 }, e: { x: 30, y: 35 } },
14
-        { s: { x: 30, y: 35 }, e: { x: 10, y: 32 } },
15
-        { s: { x: 50, y: 20 }, e: { x: 35, y: 15 } },
16
-        { s: { x: 35, y: 15 }, e: { x: 40, y: 5 } },
17
-        { s: { x: 40, y: 5 }, e: { x: 50, y: 20 } },
18
-        { s: { x: 0, y: 0 }, e: { x: 100, y: 0 } },
19
-        { s: { x: 100, y: 0 }, e: { x: 100, y: 100 } },
20
-        { s: { x: 100, y: 100 }, e: { x: 0, y: 100 } },
21
-        { s: { x: 0, y: 100 }, e: { x: 0, y: 0 } },
22
-    ]
16
+    lines: [].concat(...range(30).map(i => {
17
+        var points = range(3).map(
18
+            j => ({ x: Math.random() * 20 + (i * 40 / 150 * 40), y: Math.random() * 20 + (i * 40) % 150 })
19
+        );
20
+        return points.map((p, j) => ({ s: p, e: points[j + 1] || points[0] }));
21
+    }))
23 22
 };
24 23
 
25 24
 canvas.width = document.body.clientWidth;
@@ -27,11 +26,6 @@ canvas.height = document.body.clientHeight;
27 26
 
28 27
 var pixelCanvas = getPixelCanvas(canvas, 4, initialState);
29 28
 
30
-function range(n) {
31
-    if (n <= 0) return [];
32
-    return range(n - 1).concat([n - 1]);
33
-}
34
-
35 29
 function line(sx, sy, ex, ey, color, pc) {
36 30
     var xlen = ex - sx;
37 31
     var ylen = ey - sy;
@@ -41,24 +35,32 @@ function line(sx, sy, ex, ey, color, pc) {
41 35
     );
42 36
 }
43 37
 
38
+var round = Math.round;
39
+var floor = Math.floor;
40
+var ceil = Math.ceil;
41
+var max = Math.max;
42
+var min = Math.min;
43
+
44 44
 function poly(points, color, pc) {
45 45
     var bounds = {
46
-        top: points.slice().sort((a, b) => a.y - b.y)[0].y,
47
-        bottom: points.slice().sort((a, b) => b.y - a.y)[0].y,
48
-        left: points.slice().sort((a, b) => a.x - b.x)[0].x,
49
-        right: points.slice().sort((a, b) => b.x - a.x)[0].x,
46
+        top: round(min(...points.map(p => p.y))),
47
+        bottom: round(max(...points.map(p => p.y))),
48
+        left: round(min(...points.map(p => p.x))),
49
+        right: round(max(...points.map(p => p.x))),
50 50
     };
51 51
     range(bounds.bottom - bounds.top).forEach(
52 52
         ry => {
53 53
             var y = ry + bounds.top;
54 54
             var intersects = points.map((p, i) => {
55
+                var nextp = points[(i + 1) % points.length];
55 56
                 var c = collision(
56
-                    p, points[(i + 1) % points.length],
57
+                    { x: round(p.x), y: round(p.y) }, { x: round(nextp.x), y: round(nextp.y) },
57 58
                     { x: bounds.left, y: y }, { x: bounds.right, y: y }
58 59
                 );
59
-                if (!(c[0] >= 0 && c[0] <= 1 && c[1] >= 0 && c[1] <= 1)) return null;
60
-                return c[1] * (bounds.right - bounds.left) + bounds.left;
61
-            }).filter(i => i);
60
+                if (!(c[0] >= 0 && c[0] <= 1
61
+                        && c[1] >= 0 && c[1] <= 1)) return null;
62
+                return round(c[1] * (bounds.right - bounds.left) + bounds.left);
63
+            }).filter(i => i).sort((a, b) => a - b);
62 64
             intersects.slice(0, intersects.length - 1).forEach((x, i) => {
63 65
                 rect(x, y, intersects[i + 1] - x, 1, color, pc);
64 66
             });
@@ -72,25 +74,34 @@ listen('mousemove', (last, e, pc) => {
72 74
         y: e.clientY / pc.size,
73 75
     };
74 76
     var size = getSize(pc);
75
-    rect(0, 0, size.x, size.y, 'white', pc);
77
+    rect(0, 0, size.x, size.y, 'black', pc);
76 78
     rect(newmouse.x, newmouse.y, 1, 1, 'black', pc);
77 79
     last.lines.forEach(l => {
78 80
         line(l.s.x, l.s.y, l.e.x, l.e.y, 'black', pc);
79 81
     });
80
-    var points = last.lines.map(l => l.s);
82
+    var allLines = last.lines.concat(
83
+        { s: { x: 1, y: 1 }, e: { x: size.x, y: 1 } },
84
+        { s: { x: size.x, y: 1 }, e: { x: size.x, y: size.y } },
85
+        { s: { x: size.x, y: size.y }, e: { x: 1, y: size.y } },
86
+        { s: { x: 1, y: size.y }, e: { x: 1, y: 1 } },
87
+    );
88
+    var points = allLines.map(l => l.s);
81 89
     var collisions = [].concat(...points.map(p => {
82 90
         var vec = { x: p.x - newmouse.x, y: p.y - newmouse.y };
83 91
         var dist = getdist(vec.x, vec.y);
84 92
         var smol = { x: vec.x / dist * 0.01, y: vec.y / dist * 0.01 };
85 93
         return [
86
-            getFirstCollision(newmouse, { x: p.x - smol.y, y: p.y + smol.x }, last.lines),
87
-            getFirstCollision(newmouse, { x: p.x + smol.y, y: p.y - smol.x }, last.lines),
94
+            getFirstCollision(newmouse, { x: p.x - smol.y, y: p.y + smol.x }, allLines),
95
+            getFirstCollision(newmouse, { x: p.x + smol.y, y: p.y - smol.x }, allLines),
88 96
         ].filter(x => x).sort((a, b) => getdist(p.x - b.x, p.y - b.y) - getdist(p.x - a.x, p.y - a.y));
89
-    })).filter(p => p);
90
-    collisions.forEach(p => {
91
-        line(
92
-            p.x, p.y, newmouse.x, newmouse.y,
93
-            'rgba(150, 150, 150, .5)',
97
+    })).filter(p => p).sort((a, b) => (
98
+        Math.atan2(newmouse.x - a.x, newmouse.y - a.y)
99
+            - Math.atan2(newmouse.x - b.x, newmouse.y - b.y)
100
+    ));
101
+    collisions.forEach((c, i) => {
102
+        poly(
103
+            [newmouse, c, collisions[i + 1] || collisions[0]],
104
+            'white',
94 105
             pc
95 106
         );
96 107
     });
@@ -107,8 +118,8 @@ function getdist(x, y) {
107 118
 function collision(start1, end1, start2, end2) {
108 119
     var dist1 = { x: end1.x - start1.x, y: end1.y - start1.y };
109 120
     var dist2 = { x: end2.x - start2.x, y: end2.y - start2.y };
110
-    var l2 = ((start2.x - start1.x) * dist1.y + (start1.y - start2.y) * dist1.x) / (dist2.y * dist1.x - dist2.x * dist1.y);
111
-    var l1 = (start2.x - start1.x + dist2.x * l2) / dist1.x;
121
+    var l2 = ((start2.x - start1.x) * dist1.y + (start1.y - start2.y) * dist1.x) / (dist2.y * dist1.x - dist2.x * dist1.y) || 0;
122
+    var l1 = (start2.x - start1.x + dist2.x * l2) / dist1.x || (start2.y - start1.y + dist2.y * l2) / dist1.y;
112 123
     return [l1, l2];
113 124
 }
114 125