Compare commits

...

9 commits

13 changed files with 343 additions and 81 deletions

15
anime.html Normal file
View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>Dumb Physics Engine</title>
<meta name="description" content="Converts SVGs into a set of circles and use those circles for dumb collision checking">
<link rel="stylesheet" href="style.css">
</head>
<body>
<img src="anime.png">
<svg id="hiragana-ni"></svg>
<svg id="hiragana-small-ya"></svg>
<svg id="hiragana-a"></svg>
<script src="script.js"></script>
</body>
</html>

BIN
anime.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

46
b.svg Normal file
View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="200"
height="200"
viewBox="0 0 200 200"
version="1.1"
id="svg1"
sodipodi:docname="b.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="2.183982"
inkscape:cx="136.21907"
inkscape:cy="128.20618"
inkscape:window-width="1536"
inkscape:window-height="902"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 62.920833,22.328767 c -0.56898,15.096246 -3.307054,30.01181 -4.616352,45.027771 -2.016369,23.125149 -1.657893,29.595926 -2.636383,51.298572 -0.344254,7.63545 -0.896476,15.26087 -1.212665,22.89754 -0.404668,9.77366 -1.041894,19.77777 0.02504,29.52069 0.22274,2.03399 0.0531,4.27882 1.094617,6.04007 1.89801,3.2096 14.824157,-2.27826 14.854246,-2.28582 2.625745,-0.66005 5.29271,-1.17243 7.975326,-1.53819 23.346838,-3.18316 67.367348,0.31093 74.224728,-30.45433 0.972,-4.36083 0.44544,-9.07157 -0.72259,-13.38403 -5.32934,-19.67638 -16.98081,-28.20266 -33.5325,-38.14706 -5.8523,-3.516117 -11.5295,-7.488632 -17.88591,-9.980337 -13.041099,-5.112096 -30.424554,-7.218615 -43.280316,-0.30406"
id="path1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

46
d.svg Normal file
View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="200"
height="200"
viewBox="0 0 200 200"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
sodipodi:docname="d.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="2.183982"
inkscape:cx="136.21907"
inkscape:cy="128.20618"
inkscape:window-width="1536"
inkscape:window-height="902"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 123.29471,17.851924 c 0.51273,2.588687 1.24991,5.142879 1.53819,7.766061 0.58376,5.311795 0.78792,10.659209 1.07316,15.995367 1.70041,31.811571 1.42514,28.743224 0.83885,64.916898 -0.34192,21.09547 0.71038,31.68324 -6.27259,51.8584 -1.58707,4.58536 -3.85919,9.24844 -7.462,12.49867 -6.76053,6.09893 -20.424072,-2.75308 -24.437518,-4.7809 -5.571837,-2.8152 -19.537644,-10.37121 -23.482408,-17.20803 -5.351039,-9.27408 -5.737078,-21.45199 -2.285819,-31.38619 3.501565,-10.07901 14.384144,-19.095512 23.131844,-23.900938 4.386238,-2.409518 9.443823,-3.323029 14.224661,-4.802366 3.58684,-1.109877 7.12144,-2.708109 10.86748,-2.961907 2.62843,-0.178078 5.16922,1.035441 7.71777,1.702739 2.53075,0.66264 4.9762,2.940757 7.5085,2.28403 1.43871,-0.373115 0.45192,-2.938058 0.67788,-4.407087"
id="path1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -6,7 +6,7 @@
height="200"
viewBox="0 0 200 200"
version="1.1"
id="hiragana-a"
id="svg1"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
sodipodi:docname="hiragana-a.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
@ -24,7 +24,7 @@
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="1.3575939"
inkscape:cx="-103.49192"
inkscape:cx="-102.75532"
inkscape:cy="160.57821"
inkscape:window-width="1536"
inkscape:window-height="902"
@ -39,16 +39,17 @@
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linejoin:round"
d="m 12.784166,48.2633 c 6.810296,-0.0161 13.608098,-0.70428 20.417184,-0.656946 8.339073,0.05797 16.662758,0.833983 25.001807,0.895073 34.613369,0.253565 37.757077,-1.380655 75.497083,-1.862985 9.91666,-0.126739 19.84279,-0.01771 29.74891,0.456642 24.06701,1.15225 14.13856,4.282188 22.44406,1.479181"
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 21.013028,52.575053 c 6.39466,-0.01512 12.777587,-0.661298 19.171111,-0.616852 7.830134,0.05443 15.645821,0.783085 23.475932,0.840446 32.500896,0.23809 35.452742,-1.296393 70.889459,-1.749285 9.31144,-0.119005 18.63177,-0.01663 27.93331,0.428772 22.59819,1.081927 13.27568,4.020844 21.07429,1.388906"
id="path1" />
<path
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linejoin:round"
d="M 77.515495,8.2192151 C 75.516564,32.199537 75.530182,56.33753 75.541992,80.400969 c 0.0056,11.348185 -0.02805,22.701441 0.317652,34.042571 0.353335,11.59151 1.100709,23.16309 1.778856,34.73524 1.053836,17.98307 4.207218,12.37774 0.282507,18.48794"
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 81.793766,14.974882 c -1.876935,22.516789 -1.864148,45.181627 -1.853058,67.77646 0.0053,10.655598 -0.02634,21.315958 0.298265,31.964928 0.331771,10.88407 1.033532,21.74944 1.670292,32.61534 0.989519,16.88555 3.950449,11.62231 0.265265,17.3596"
id="path2" />
<path
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linejoin:round"
d="m 125.70777,69.526531 c -0.69486,3.385925 -3.63293,17.853348 -4.07195,19.06547 -8.71461,24.060549 -19.52078,47.577849 -34.680923,68.388329 -5.193067,7.12857 -11.141846,14.13769 -18.645251,18.77272 -12.126114,7.49057 -27.245849,4.86443 -34.058991,-9.14824 -7.660344,-15.75512 -5.83572,-36.61123 3.067622,-51.35112 3.931406,-6.50862 9.029684,-12.95456 15.761122,-16.490912 16.544317,-8.691539 41.019976,-8.7624 58.602761,-4.619642 24.18531,5.698413 40.76727,10.598274 54.53221,31.135644 3.54089,5.28304 7.29148,11.80223 6.15485,18.05974 -1.42005,7.81773 -7.43918,14.32401 -13.0577,19.94234 -15.76644,15.76589 -18.71398,16.59872 -31.88644,22.27876"
id="path4" />
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 125.43119,85.286289 c -8.18275,22.592121 -20.5392,49.830321 -34.774113,69.370721 -4.876132,6.69352 -10.461853,13.27487 -17.507321,17.62701 -11.386051,7.03342 -25.58302,4.56756 -31.980351,-8.58991 -7.192829,-14.79358 -5.479563,-34.37683 2.880403,-48.21713 3.69147,-6.1114 8.478597,-12.16394 14.799212,-15.484461 15.534608,-8.16109 38.516503,-8.227625 55.0262,-4.337703 22.70926,5.350634 38.27922,9.951454 51.20408,29.235414 3.32479,4.96061 6.84648,11.08193 5.77922,16.95755 -1.33339,7.3406 -6.98517,13.44981 -12.26079,18.72525 -14.8042,14.80368 -17.57185,15.58568 -29.94039,20.91906"
id="path4"
sodipodi:nodetypes="csssssssssc" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -6,7 +6,7 @@
height="200"
viewBox="0 0 200 200"
version="1.1"
id="hiragana-ni"
id="svg1"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
sodipodi:docname="hiragana-ni.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
@ -24,7 +24,7 @@
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="1.7276112"
inkscape:cx="-45.438465"
inkscape:cx="-45.438464"
inkscape:cy="107.08428"
inkscape:window-width="1536"
inkscape:window-height="902"
@ -39,16 +39,16 @@
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-opacity:1;stroke:currentColor;stroke-width:20;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 27.966735,16.083962 c -1.000438,1.124839 -2.372955,2.006558 -3.001316,3.374511 -0.890902,1.939519 -1.163631,4.125026 -1.417007,6.244278 -0.773668,6.470962 -1.184352,12.980894 -1.65866,19.480661 -1.990683,27.279717 -2.379566,30.990179 -1.454185,59.744588 0.793536,24.65759 1.788458,47.0885 5.760979,71.28514 0.564082,3.43584 1.988484,6.67372 2.982725,10.01058"
style="fill:none;fill-opacity:1;stroke:currentColor;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 30.276367,23.144761 c -0.906482,1.0192 -2.150098,1.818112 -2.719447,3.057593 -0.807232,1.757368 -1.054348,3.737623 -1.283928,5.657844 -0.701009,5.86324 -1.073123,11.761789 -1.502886,17.651128 -1.803727,24.717732 -2.156088,28.079725 -1.317615,54.133654 0.719011,22.34186 1.620494,42.66617 5.219935,64.59037 0.511106,3.11316 1.801734,6.04695 2.702601,9.07043"
id="path7" />
<path
style="fill:none;fill-opacity:1;stroke:currentColor;stroke-width:20;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 61.803371,47.19668 c 1.248756,-0.907498 2.287696,-2.21703 3.746279,-2.722487 3.4894,-1.209225 7.188566,-1.722283 10.831328,-2.329273 9.225962,-1.537319 18.442605,-3.263583 27.758222,-4.100892 28.83951,-2.592158 58.01616,-0.884141 86.89226,-0.03718"
style="fill:none;fill-opacity:1;stroke:currentColor;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 60.935223,51.335517 c 1.131478,-0.82227 2.072846,-2.008817 3.394446,-2.466804 3.161691,-1.09566 6.513449,-1.560534 9.814099,-2.110518 8.359503,-1.392941 16.710561,-2.957082 25.151299,-3.715755 26.131033,-2.348715 52.567553,-0.801107 78.731743,-0.03369"
id="path8" />
<path
style="fill:none;fill-opacity:1;stroke:currentColor;stroke-width:20;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 87.045007,122.0222 c -1.118643,1.0562 -2.453734,1.92242 -3.355924,3.1686 -5.781083,7.98538 -13.117144,21.43086 -4.884465,30.77813 4.323739,4.90911 10.049889,8.7611 16.126165,11.18451 7.326277,2.92194 15.374477,3.78432 23.228367,4.51127 11.20859,1.03744 22.50545,0.60682 33.76085,0.76354 26.66878,0.37137 14.44172,-1.00144 26.91889,0.59627"
style="fill:none;fill-opacity:1;stroke:currentColor;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 83.806281,119.13377 c -1.013585,0.95701 -2.22329,1.74188 -3.040751,2.87102 -5.23815,7.23543 -11.885243,19.41817 -4.425739,27.88759 3.917674,4.44807 9.10605,7.9383 14.611671,10.13411 6.638227,2.64753 13.930578,3.42892 21.046868,4.0876 10.15593,0.94 20.39184,0.54983 30.59019,0.69183 24.16417,0.33649 13.08542,-0.90739 24.39079,0.54027"
id="path9" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -6,7 +6,7 @@
height="200"
viewBox="0 0 200 200"
version="1.1"
id="hiragana-small-ya"
id="svg1"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
sodipodi:docname="hiragana-small-ya.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
@ -25,7 +25,7 @@
inkscape:document-units="mm"
inkscape:zoom="1.381533"
inkscape:cx="-121.24213"
inkscape:cy="98.441371"
inkscape:cy="98.441369"
inkscape:window-width="1536"
inkscape:window-height="902"
inkscape:window-x="0"
@ -39,16 +39,17 @@
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linejoin:round"
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linejoin:round;stroke-dasharray:none;stroke-linecap:round"
d="m 22.318281,66.024742 c 3.522764,-5.501248 1.310196,-3.074172 12.511103,-6.879934 18.486357,-6.281155 31.10176,-9.525165 51.481112,-11.33282 17.781294,-1.577204 56.822334,-3.535437 75.702734,3.133648 12.25208,4.327774 13.15313,16.159869 5.86791,25.022203 -9.89215,12.033627 -30.4193,21.729881 -44.13131,27.517921 -1.60362,0.6769 -3.45533,0.42408 -5.18299,0.63612"
id="path1" />
<path
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linejoin:round"
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linejoin:round;stroke-dasharray:none;stroke-linecap:round"
d="m 39.84223,19.392328 c 2.395717,4.499876 5.306115,8.761481 7.187149,13.499629 2.029237,5.111447 3.134124,10.546481 4.476386,15.879684 3.417985,13.580674 6.331658,27.285733 9.802138,40.853088 7.475495,29.224441 16.236122,57.535541 27.425749,85.593431"
id="path2" />
<path
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linejoin:round"
d="m 95.63708,19.155587 c 2.853869,14.957057 9.67911,28.437868 14.84236,42.573525 2.10119,5.752511 3.81797,11.638235 5.72695,17.457352"
id="path3" />
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 94.189413,24.222422 c 2.853869,14.957057 11.126777,23.371033 16.290027,37.50669 2.10119,5.752511 3.09414,6.5714 5.00312,12.390517"
id="path3"
sodipodi:nodetypes="csc" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -1,19 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>Dumb physics engine</title>
<title>Dumb Physics Engine</title>
<meta name="description" content="Converts SVGs into a set of circles and use those circles for dumb collision checking">
<link rel="stylesheet" href="style.css">
</head>
<body>
<!--
Draw 200x200 SVGs in Inkscape with the pencil tool and a stroke width of 20
Make sure the scale is set to 1 and that the id is set to a unique value
Also, change the stroke to currentColor so we can style the color with CSS
Draw SVGs in Inkscape with the scale set to 1
Use the pencil tool with a stroke width of 20 and round endcaps
Then change the stroke color to currentColor so we can style it with CSS (might have to do this in a text editor)
-->
<svg id="hiragana-ni"></svg>
<svg id="hiragana-small-ya"></svg>
<svg id="hiragana-a"></svg>
<svg id="d"></svg>
<svg id="u"></svg>
<svg id="m"></svg>
<svg id="b"></svg>
<script src="script.js"></script>
</body>
</html>

46
m.svg Normal file
View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="200"
height="200"
viewBox="0 0 200 200"
version="1.1"
id="svg1"
sodipodi:docname="u.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="2.183982"
inkscape:cx="136.21907"
inkscape:cy="128.20618"
inkscape:window-width="1536"
inkscape:window-height="902"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 25.820096,70.504458 c -0.279617,1.740895 -0.848527,3.459504 -0.838849,5.222685 0.255376,46.524227 2.633835,-8.937146 0.06976,45.446307 -0.38795,8.2283 -1.154661,16.43771 -1.445181,24.67003 -1.112944,31.53691 1.02998,17.34175 8.486863,-0.97836 9.231101,-22.67903 15.257165,-37.23546 30.12881,-57.828718 5.387068,-7.459651 16.655579,-25.382745 28.24006,-10.842437 4.127353,5.180466 4.496278,12.510895 5.805765,19.003777 6.355886,31.514668 0.750221,21.373238 3.124668,55.728908 0.33136,4.79442 1.432408,9.56987 3.078158,14.08515 0.22154,0.60781 1.59405,-0.21261 1.74924,-0.84063 0.88884,-3.59699 0.71191,-7.37743 1.18942,-11.05171 2.49506,-19.199 3.03872,-28.15433 10.14309,-46.5427 0.98625,-2.55271 9.91829,-31.035682 21.57041,-32.505852 3.19784,-0.403478 6.46382,2.288236 8.3241,4.920413 4.21712,5.966936 6.65388,13.046334 9.21124,19.890918 8.46856,22.665491 7.3761,24.100021 11.40406,45.446301 0.9279,4.91746 1.97788,9.81113 2.98515,14.71295 0.55477,2.69973 1.60942,5.33696 1.70095,8.09158 0.0538,1.61871 -1.05646,-3.06206 -1.58469,-4.5931"
id="path1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

116
script.js
View file

@ -6,27 +6,44 @@ document.querySelectorAll("svg").forEach(function(svg) {
svg.outerHTML = req.responseText
})
let rad = 10 // Stroke width
let size = 200 // SVG width and height
let rad = 10 // Stroke radius
let A = [] // Objects
let cnt = 0
let idcnt = 0
let ix = 0
let iy = 0
let ny = 0
document.querySelectorAll("svg").forEach(function(svg) {
// Move objects so they aren't overlapping
svg.style.left = 1.5 * size * cnt++ + "px"
svg.style.top = "50px"
// Position objects so they aren't overlapping
if (ix + svg.width.baseVal.value > window.innerWidth) {
ix = 0
iy += ny
ny = 0
}
svg.style.left = ix + "px"
svg.style.top = iy + "px"
ix += svg.width.baseVal.value
ny = Math.max(svg.height.baseVal.value, ny)
svg.id = idcnt++
const rect = svg.getBoundingClientRect()
let a = {
id: svg.id, // Unique ID
p: [], // Collision circles
cm: svg.createSVGPoint(), // Center of mass
cm: svg.createSVGPoint(), // Position of center of mass relative to top left corner
x: rect.x, // x position of center of mass
y: rect.y, // y position of center of mass
vx: Math.random(), // x velocity
vy: Math.random(), // y velocity
th: 0, // Angular position
w: Math.random() / 100 // Angular velocity
w: Math.random() / 100, // Angular velocity
m: 0, // Mass
mi: 0, // Moment of inertia
r: 0 // Distance to farthest point from center of mass
}
svg.querySelectorAll("path").forEach(function(path) {
// Get circles on path for collision checking
for (let i = 0; i < path.getTotalLength(); i += 5) {
const p = path.getPointAtLength(i)
let num = Math.floor(path.getTotalLength() * 2 / rad)
for (let i = 0; i <= num; i++) {
const p = path.getPointAtLength(i / num * path.getTotalLength())
a.cm.x += p.x
a.cm.y += p.y
a.p.push(p)
@ -34,7 +51,7 @@ document.querySelectorAll("svg").forEach(function(svg) {
/* let circle = document.createElementNS("http://www.w3.org/2000/svg", "circle")
circle.setAttribute("cx", p.x)
circle.setAttribute("cy", p.y)
circle.setAttribute("r", rad)
circle.setAttribute("r", 10)
circle.setAttribute("fill", "red")
svg.appendChild(circle) */
}
@ -42,17 +59,16 @@ document.querySelectorAll("svg").forEach(function(svg) {
a.cm.x /= a.p.length
a.cm.y /= a.p.length
// Change origin to center of mass
const rect = svg.getBoundingClientRect()
a.x = rect.x + a.cm.x // Position of center of mass
a.y = rect.y + a.cm.y // Position of center of mass
a.x += a.cm.x
a.y += a.cm.y
for (const p of a.p) {
p.x -= a.cm.x
p.y -= a.cm.y
}
svg.style.transformOrigin = a.cm.x + "px " + a.cm.y + "px"
a.m = a.p.length // Mass
a.mi = 0 // Moment of inertia
a.m = a.p.length
for (const p of a.p) a.mi += p.x ** 2 + p.y ** 2
for (const p of a.p) a.r = Math.max(Math.sqrt(p.x ** 2 + p.y ** 2), a.r)
A.push(a)
})
@ -92,15 +108,15 @@ function collide(a, b, c, n) {
b.vx += n.x * j / b.m
b.vy += n.y * j / b.m
b.w += -cr(cb, n) * j / b.mi
console.log('boop')
// console.log('boop')
}
// Collision of object a with wall at position k and direction d
function wallCollide(a, k, d) {
if ((d == 0 && Math.abs(a.x - k) < size) || (d == 1 && Math.abs(a.y - k) < size)) {
if ((!d && Math.abs(a.x - k) < a.r + rad) || (d && Math.abs(a.y - k) < a.r + rad)) {
let c = {x: 0, y: 0, cnt: 0}
for (const p of a.p.map(x => rot(a, x))) {
if ((d == 0 && Math.abs(p.x - k) < rad) || (d == 1 && Math.abs(p.y - k) < rad)) {
if ((!d && Math.abs(p.x - k) < rad) || (d && Math.abs(p.y - k) < rad)) {
c.x += p.x
c.y += p.y
c.cnt++
@ -119,24 +135,31 @@ function wallCollide(a, k, d) {
// Collision of object a with object b
function objectsCollide(a, b) {
if (ds(a, b) < size * size) {
if (ds(a, b) < (a.r + b.r + 2 * rad) ** 2) {
// Objects are close
let c = {x: 0, y: 0, cnt: 0}
let n = {x: 0, y: 0}
// Slight performance optimization?
// Only consider points close to other object
let aa = []
let bb = []
for (const p of a.p.map(x => rot(a, x))) {
// p is close to object b
if (ds(p, b) < size * size) {
for (const q of b.p.map(x => rot(b, x))) {
const d = ds(p, q)
if (d < 4 * rad * rad) {
// Collision!
// These calculations are a bit sketchy but I guess they work?
c.x += p.x + q.x
c.y += p.y + q.y
c.cnt++
n.x += (p.x - q.x) / d
n.y += (p.y - q.y) / d
}
if (ds(p, b) < (a.r + b.r + 2 * rad) ** 2) aa.push(p)
}
for (const p of b.p.map(x => rot(b, x))) {
if (ds(p, a) < (a.r + b.r + 2 * rad) ** 2) bb.push(p)
}
for (const p of aa) {
for (const q of bb) {
const d = ds(p, q)
if (d < (2 * rad) ** 2) {
// Collision!
// These calculations are a bit sketchy but I guess they work?
c.x += p.x + q.x
c.y += p.y + q.y
c.cnt++
n.x += (p.x - q.x) / d
n.y += (p.y - q.y) / d
}
}
}
@ -152,17 +175,29 @@ function objectsCollide(a, b) {
}
}
// Move stuff, check collisions, and render
function tick() {
// Move each object one step
for (let a of A) {
a.x += a.vx
a.y += a.vy
a.th += a.w
// Don't allow glitching into walls
/* const px = a.p.map(x => rot(a, x).x)
let k = Math.min(...px) - rad
if (k < 0) a.x -= k
k = window.innerWidth - Math.max(...px) - rad
if (k < 0) a.x += k
const py = a.p.map(x => rot(a, x).y)
k = Math.min(...py) - rad
if (k < 0) a.y -= k
k = window.innerHeight - Math.max(...py) - rad
if (k < 0) a.y += k */
// Friction
if (Math.abs(a.vx) > 0.001) a.vx -= 0.001 * Math.sign(a.vx)
if (Math.abs(a.vy) > 0.001) a.vy -= 0.001 * Math.sign(a.vy)
if (Math.abs(a.w) > 0.00001) a.w -= 0.00001 * Math.sign(a.w)
}
// Check wall collisions
for (let a of A) {
wallCollide(a, 0, 0)
@ -170,18 +205,16 @@ function tick() {
wallCollide(a, 0, 1)
wallCollide(a, window.innerHeight, 1)
}
// Check collisions between objects
for (let i = 0; i < A.length; i++) {
for (let j = i + 1; j < A.length; j++) {
objectsCollide(A[i], A[j])
}
}
// Render every 10ms
cnt++
if (cnt == 10) {
cnt = 0
tickcnt++
if (tickcnt == 10) {
tickcnt = 0
for (a of A) {
let e = document.getElementById(a.id)
e.style.left = a.x - a.cm.x + "px"
@ -194,11 +227,10 @@ function tick() {
// Use click to update velocities
function updatev(event) {
for (a of A) {
let d = ds(a, {x: event.clientX, y: event.clientY})
let d = Math.max(ds(a, {x: event.clientX, y: event.clientY}), 100)
a.vx += 100 * (a.x - event.clientX) / d
a.vy += 100 * (a.y - event.clientY) / d
}
// Display spreading out circles
let circle = document.createElement("div")
circle.style.width = circle.style.height = "10px"
@ -213,6 +245,6 @@ function updatev(event) {
}, 1000)
}
cnt = 0
let tickcnt = 0
setInterval(tick, 1)
document.addEventListener("click", updatev)

25
stress.html Normal file
View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>Dumb Physics Engine</title>
<meta name="description" content="Converts SVGs into a set of circles and use those circles for dumb collision checking">
<link rel="stylesheet" href="style.css">
</head>
<body>
<svg id="d"></svg>
<svg id="u"></svg>
<svg id="m"></svg>
<svg id="b"></svg>
<svg id="hiragana-ni"></svg>
<svg id="hiragana-small-ya"></svg>
<svg id="hiragana-a"></svg>
<svg id="d"></svg>
<svg id="u"></svg>
<svg id="m"></svg>
<svg id="b"></svg>
<svg id="hiragana-ni"></svg>
<svg id="hiragana-small-ya"></svg>
<svg id="hiragana-a"></svg>
<script src="script.js"></script>
</body>
</html>

View file

@ -1,12 +1,8 @@
body {
/* background-image: url("catgirl.png"); */
background-size: auto 100vh;
background-position: center;
background-repeat: no-repeat;
background-attachment: fixed;
overflow-y: hidden;
overflow-x: hidden;
touch-action: manipulation;
position: fixed;
margin: 0;
overflow: hidden;
touch-action: none;
}
@keyframes color {
@ -52,3 +48,10 @@ div {
background-color: #007bff;
transition: transform 1000ms ease-in-out, opacity 1000ms ease-in-out;
}
img {
position: absolute;
left: 50vw;
transform: translateX(-50%);
height: 100vh;
}

46
u.svg Normal file
View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="200"
height="200"
viewBox="0 0 200 200"
version="1.1"
id="svg1"
sodipodi:docname="u.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="2.183982"
inkscape:cx="136.21907"
inkscape:cy="128.20618"
inkscape:window-width="1536"
inkscape:window-height="902"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:currentColor;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 39.205909,75.448123 c -1.498412,21.24945 -1.980381,15.368861 0.162762,36.841387 1.664601,16.67795 1.855938,28.58373 11.379014,43.39479 7.014054,10.90883 14.345223,15.67333 26.607076,10.56342 14.155609,-5.8991 25.514139,-20.96366 32.740149,-33.27494 3.77953,-6.43935 6.03572,-13.68473 8.3724,-20.77627 2.74841,-8.3411 4.85188,-16.888539 6.85567,-25.439128 0.90679,-3.869478 1.23323,-7.852388 1.8655,-11.776081 0.19943,-1.237642 -0.55199,-4.126579 0.62958,-3.707749 1.6647,0.590086 1.91192,3.04222 2.33232,4.757652 1.34098,5.471824 1.81443,11.122727 2.91362,16.648202 2.98001,14.980134 5.50472,23.937134 9.18799,39.057454 1.76107,7.22944 3.37115,14.49585 5.20122,21.70813 0.96895,3.81861 2.29395,7.54367 3.19442,11.37901 1.46077,6.22176 1.75258,6.08352 -0.35056,4.17457"
id="path1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB