马黑黑 发表于 2024-4-13 13:32

Collide

本帖最后由 马黑黑 于 2024-4-13 14:05 编辑 <br /><br /><style>
#mydiv { margin: 20px 0 20px calc(50% - 721px); width: 1280px; height: 720px; background: url('https://638183.freep.cn/638183/t24/1/collide.jpg') no-repeat center/cover; box-shadow: 3px 3px 6px #333; position: relative; z-index: 1; }
#play { position: absolute; width: 100px; top: 462px; cursor: pointer; left: 630px; animation: rot 5s linear infinite var(--state); }
@keyframes rot { to { transform: rotate(360deg); } }
</style>

<div id="mydiv">
        <audio id="aud" src="https://music.163.com/song/media/outer/url?id=1817349555" autoplay></audio>
        <img id="play" src="https://638183.freep.cn/638183/web/svg/3star-01.svg" alt="" />
</div>

<script>
var canv = document.createElement('canvas');
var ww = canv.width = mydiv.offsetWidth;
var hh = canv.height = mydiv.offsetHeight;
canv.style.cssText = `position: absolute'; left: 0; top: 0; cursor: crosshair`;
mydiv.prepend(canv);
var ctx = canv.getContext('2d');
var balls = [];
var raf = null;
var speed = () => (Math.random() < 0.5 ? -1 : 1) * (Math.random() * 0.5 + 0.5);
var mState = () => {
        aud.paused ?
                (mydiv.style.setProperty('--state', 'paused'), cancelAnimationFrame(raf)) :
                (mydiv.style.setProperty('--state', 'running'), render());
};
var innerCircle = (ex,ey,cx,cy,r) => Math.sqrt((ex - cx) ** 2 + (ey - cy) ** 2) <= r;
var drawBall = (x,y,r,color) => {
        ctx.save();
        ctx.beginPath();
        ctx.fillStyle = color;
        ctx.arc(x,y,r,0,2*Math.PI);
        ctx.fill();
        ctx.restore();
};
var move = (ball) => {
        var x = ball.x, y = ball.y, r = ball.r, color = ball.color, spdX = ball.speedX, spdY = ball.speedY;
        x += spdX;
        y += spdY;
        if(x - r < 0 || x + r > ww) spdX = - spdX;
        if(y - r < 0 || y + r > hh) spdY = - spdY;
        ball.x = x;
        ball.y = y;
        ball.speedX = spdX;
        ball.speedY = spdY;
        drawBall(x,y,r,color);
};
var render = () => {
        ctx.clearRect(0,0,ww,hh);
        for(var j = 0; j < balls.length; j ++) {
                for(var k = 0; k < balls.length; k ++) {
                        var dx = balls.x - balls.x, dy = balls.y - balls.y;
                        var distance = Math.sqrt(dx * dx + dy * dy);
                        if(distance < (balls.r + balls.r)) {
                                balls.speedX = -balls.speedX;
                            balls.speedY = -balls.speedY;
                            balls.speedX = -balls.speedX;
                            balls.speedY = -balls.speedY;
                        }
                }
                move(balls);
        }
        aud.paused ? cancelAnimationFrame(raf) : raf = requestAnimationFrame(render);
};
var initBalls = (total) => {
        for (var j = 0; j < total; j ++) {
                var x = Math.random() * (ww - 200) + 50, y = Math.random() * (hh - 100) + 30, r = Math.random() * 5 + 5, color = '#' + Math.random().toString(16).substr(-6), spdx = speed(), spdy = speed();
                balls.push({x: x, y: y, r: r, color: color, speedX: spdx, speedY: spdy});
                move(balls);
        }
};
aud.loop = false;
aud.onplaying = aud.onpause = () => mState();
aud.onseeked = () => cancelAnimationFrame(raf);
aud.onended = () => { cancelAnimationFrame(raf); aud.play(); };
play.onclick = () => aud.paused ? aud.play() : aud.pause();
canv.onclick = (e) => {
        var x = e.offsetX, y = e.offsetY;
        for(var j = 0; j < balls.length; j ++) {
                if(innerCircle(x, y, balls.x, balls.y, balls.r)) {
                        if(balls.r < 20) balls.r += 2;
                        balls.color = `#${Math.random().toString(16).substr(-6)}`;
                }
        }
};
initBalls(40);
</script>

马黑黑 发表于 2024-4-13 13:33

本帖最后由 马黑黑 于 2024-4-13 13:34 编辑 <br /><br /><style>
.mum { position: relative; margin: 0; padding: 10px; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: black; background: rgba(240, 240, 240,.95); box-shadow: 2px 2px 4px gray; border: thick groove lightblue; border-radius: 6px; }
.mum ::selection { background-color: rgba(0,100,100,.35); }
.mum div { margin: 0; padding: 0; }
.mum cl-cd { display: block; position: relative; margin: 0 0 0 50px; padding: 0 0 0 10px; white-space: pre-wrap; overflow-wrap: break-word; border-left: 1px solid silver; }
.mum cl-cd::before { position: absolute; content: attr(data-idx); width: 50px; color: gray; text-align: right; transform: translate(-70px); }
.tRed { color: red; }
.tBlue { color: blue; }
.tGreen { color: green; }
.tDarkRed { color: darkred; }
.tMagenta { color: magenta; }
</style>
<div class='mum'>
<cl-cd data-idx="1">&lt;<span class="tDarkRed">style</span>&gt;</cl-cd>
<cl-cd data-idx="2">#mydiv { <span class="tBlue">margin:</span> 20px 0 20px calc(50% - 721px); <span class="tBlue">width:</span> 1280px; <span class="tBlue">height:</span> 720px; <span class="tBlue">background:</span> url(<span class="tMagenta">'https://638183.freep.cn/638183/t24/1/collide.jpg'</span>) no-repeat center/cover; <span class="tBlue">box-shadow:</span> 3px 3px 6px #333; <span class="tBlue">position:</span> relative; }</cl-cd>
<cl-cd data-idx="3">#play { <span class="tBlue">position:</span> absolute; <span class="tBlue">width:</span> 100px; <span class="tBlue">top:</span> 462px; <span class="tBlue">cursor:</span> pointer; <span class="tBlue">left:</span> 630px; <span class="tBlue">animation:</span> rot 5s linear infinite <span class="tBlue">var</span>(--state); }</cl-cd>
<cl-cd data-idx="4">@keyframes rot { to { <span class="tBlue">transform:</span> rotate(360deg); } }</cl-cd>
<cl-cd data-idx="5">&lt;<span class="tDarkRed">/style</span>&gt;</cl-cd>
<cl-cd data-idx="6">&nbsp;</cl-cd>
<cl-cd data-idx="7">&lt;<span class="tDarkRed">div</span> <span class="tRed">id</span>=<span class="tMagenta">"mydiv"</span>&gt;</cl-cd>
<cl-cd data-idx="8">&nbsp; &nbsp; &lt;<span class="tDarkRed">audio</span> <span class="tRed">id</span>=<span class="tMagenta">"aud"</span> src=<span class="tMagenta">"https://music.163.com/song/media/outer/url?<span class="tRed">id</span>=1817349555"</span> autoply&gt;&lt;<span class="tDarkRed">/audio</span>&gt;</cl-cd>
<cl-cd data-idx="9">&nbsp; &nbsp; &lt;<span class="tDarkRed">img</span> <span class="tRed">id</span>=<span class="tMagenta">"play"</span> src=<span class="tMagenta">"https://638183.freep.cn/638183/web/svg/3star-01.svg"</span> alt=<span class="tMagenta">""</span> /&gt;</cl-cd>
<cl-cd data-idx="10">&lt;<span class="tDarkRed">/div</span>&gt;</cl-cd>
<cl-cd data-idx="11">&nbsp;</cl-cd>
<cl-cd data-idx="12">&lt;<span class="tDarkRed">script</span>&gt;</cl-cd>
<cl-cd data-idx="13"><span class="tBlue">var</span> canv = <span class="tRed">document</span>.createElement(<span class="tMagenta">'canvas'</span>);</cl-cd>
<cl-cd data-idx="14"><span class="tBlue">var</span> ww = canv.width = mydiv.offsetWidth;</cl-cd>
<cl-cd data-idx="15"><span class="tBlue">var</span> hh = canv.height = mydiv.offsetHeight;</cl-cd>
<cl-cd data-idx="16">canv.style.cssText = `<span class="tBlue">position:</span> absolute'; <span class="tBlue">left:</span> 0; <span class="tBlue">top:</span> 0; <span class="tBlue">cursor:</span> crosshair`;</cl-cd>
<cl-cd data-idx="17">mydiv.prepend(canv);</cl-cd>
<cl-cd data-idx="18"><span class="tBlue">var</span> ctx = canv.getContext(<span class="tMagenta">'2d'</span>);</cl-cd>
<cl-cd data-idx="19"><span class="tBlue">var</span> balls = [];</cl-cd>
<cl-cd data-idx="20"><span class="tBlue">var</span> raf = null;</cl-cd>
<cl-cd data-idx="21"><span class="tBlue">var</span> speed = () =&gt; (<span class="tRed">Math</span>.random() &lt; 0.5 ? -1&nbsp;: 1) * (<span class="tRed">Math</span>.random() * 0.5 + 0.5);</cl-cd>
<cl-cd data-idx="22"><span class="tBlue">var</span> mState = () =&gt; {</cl-cd>
<cl-cd data-idx="23">&nbsp; &nbsp; aud.paused ?</cl-cd>
<cl-cd data-idx="24">&nbsp; &nbsp; &nbsp; &nbsp; (mydiv.style.setProperty(<span class="tMagenta">'--state'</span>, <span class="tMagenta">'paused'</span>), cancelAnimationFrame(raf)) :</cl-cd>
<cl-cd data-idx="25">&nbsp; &nbsp; &nbsp; &nbsp; (mydiv.style.setProperty(<span class="tMagenta">'--state'</span>, <span class="tMagenta">'running'</span>), render());</cl-cd>
<cl-cd data-idx="26">};</cl-cd>
<cl-cd data-idx="27"><span class="tBlue">var</span> innerCircle = (ex,ey,cx,cy,r) =&gt; <span class="tRed">Math</span>.sqrt((ex - cx) ** 2 + (ey - cy) ** 2) &lt;= r;</cl-cd>
<cl-cd data-idx="28"><span class="tBlue">var</span> drawBall = (x,y,r,color) =&gt; {</cl-cd>
<cl-cd data-idx="29">&nbsp; &nbsp; ctx.save();</cl-cd>
<cl-cd data-idx="30">&nbsp; &nbsp; ctx.beginPath();</cl-cd>
<cl-cd data-idx="31">&nbsp; &nbsp; ctx.fillStyle = color;</cl-cd>
<cl-cd data-idx="32">&nbsp; &nbsp; ctx.arc(x,y,r,0,2*<span class="tRed">Math</span>.PI);</cl-cd>
<cl-cd data-idx="33">&nbsp; &nbsp; ctx.fill();</cl-cd>
<cl-cd data-idx="34">&nbsp; &nbsp; ctx.restore();</cl-cd>
<cl-cd data-idx="35">};</cl-cd>
<cl-cd data-idx="36"><span class="tBlue">var</span> move = (ball) =&gt; {</cl-cd>
<cl-cd data-idx="37">&nbsp; &nbsp; <span class="tBlue">var</span> x = ball.x, y = ball.y, r = ball.r, color = ball.color, spdX = ball.speedX, spdY = ball.speedY;</cl-cd>
<cl-cd data-idx="38">&nbsp; &nbsp; x += spdX;</cl-cd>
<cl-cd data-idx="39">&nbsp; &nbsp; y += spdY;</cl-cd>
<cl-cd data-idx="40">&nbsp; &nbsp; <span class="tBlue">if</span>(x - r &lt; 0 || x + r &gt; ww) spdX = - spdX;</cl-cd>
<cl-cd data-idx="41">&nbsp; &nbsp; <span class="tBlue">if</span>(y - r &lt; 0 || y + r &gt; hh) spdY = - spdY;</cl-cd>
<cl-cd data-idx="42">&nbsp; &nbsp; ball.x = x;</cl-cd>
<cl-cd data-idx="43">&nbsp; &nbsp; ball.y = y;</cl-cd>
<cl-cd data-idx="44">&nbsp; &nbsp; ball.speedX = spdX;</cl-cd>
<cl-cd data-idx="45">&nbsp; &nbsp; ball.speedY = spdY;</cl-cd>
<cl-cd data-idx="46">&nbsp; &nbsp; drawBall(x,y,r,color);</cl-cd>
<cl-cd data-idx="47">};</cl-cd>
<cl-cd data-idx="48"><span class="tBlue">var</span> render = () =&gt; {</cl-cd>
<cl-cd data-idx="49">&nbsp; &nbsp; ctx.clearRect(0,0,ww,hh);</cl-cd>
<cl-cd data-idx="50">&nbsp; &nbsp; <span class="tBlue">for</span>(<span class="tBlue">var</span> j = 0; j &lt; balls.length; j ++) {</cl-cd>
<cl-cd data-idx="51">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">for</span>(<span class="tBlue">var</span> k = 0; k &lt; balls.length; k ++) {</cl-cd>
<cl-cd data-idx="52">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">var</span> dx = balls.x - balls.x, dy = balls.y - balls.y;</cl-cd>
<cl-cd data-idx="53">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">var</span> distance = <span class="tRed">Math</span>.sqrt(dx * dx + dy * dy);</cl-cd>
<cl-cd data-idx="54">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">if</span>(distance &lt; (balls.r + balls.r)) {</cl-cd>
<cl-cd data-idx="55">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balls.speedX = -balls.speedX;</cl-cd>
<cl-cd data-idx="56">    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balls.speedY = -balls.speedY;</cl-cd>
<cl-cd data-idx="57">    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balls.speedX = -balls.speedX;</cl-cd>
<cl-cd data-idx="58">    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balls.speedY = -balls.speedY;</cl-cd>
<cl-cd data-idx="59">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="60">&nbsp; &nbsp; &nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="61">&nbsp; &nbsp; &nbsp; &nbsp; move(balls);</cl-cd>
<cl-cd data-idx="62">&nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="63">&nbsp; &nbsp; aud.paused ? cancelAnimationFrame(raf) : raf = requestAnimationFrame(render);</cl-cd>
<cl-cd data-idx="64">};</cl-cd>
<cl-cd data-idx="65"><span class="tBlue">var</span> initBalls = (total) =&gt; {</cl-cd>
<cl-cd data-idx="66">&nbsp; &nbsp; <span class="tBlue">for</span> (<span class="tBlue">var</span> j = 0; j &lt; total; j ++) {</cl-cd>
<cl-cd data-idx="67">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">var</span> x = <span class="tRed">Math</span>.random() * (ww - 200) + 50, y = <span class="tRed">Math</span>.random() * (hh - 100) + 30, r = <span class="tRed">Math</span>.random() * 5 + 5, color = <span class="tMagenta">'#'</span> + <span class="tRed">Math</span>.random().toString(16).substr(-6), spdx = speed(), spdy = speed();</cl-cd>
<cl-cd data-idx="68">&nbsp; &nbsp; &nbsp; &nbsp; balls.push({<span class="tBlue">x:</span> x, <span class="tBlue">y:</span> y, <span class="tBlue">r:</span> r, <span class="tBlue">color:</span> color, <span class="tBlue">speedX:</span> spdx, <span class="tBlue">speedY:</span> spdy});</cl-cd>
<cl-cd data-idx="69">&nbsp; &nbsp; &nbsp; &nbsp; move(balls);</cl-cd>
<cl-cd data-idx="70">&nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="71">};</cl-cd>
<cl-cd data-idx="72">aud.loop = false;</cl-cd>
<cl-cd data-idx="73">aud.onplaying = aud.onpause = () =&gt; mState();</cl-cd>
<cl-cd data-idx="74">aud.onseeked = () =&gt; cancelAnimationFrame(raf);</cl-cd>
<cl-cd data-idx="75">aud.onended = () =&gt; { cancelAnimationFrame(raf); aud.play(); };</cl-cd>
<cl-cd data-idx="76">play.onclick = () =&gt; aud.paused ? aud.play() : aud.pause();</cl-cd>
<cl-cd data-idx="77">canv.onclick = (e) =&gt; {</cl-cd>
<cl-cd data-idx="78">&nbsp; &nbsp; <span class="tBlue">var</span> x = e.offsetX, y = e.offsetY;</cl-cd>
<cl-cd data-idx="79">&nbsp; &nbsp; <span class="tBlue">for</span>(<span class="tBlue">var</span> j = 0; j &lt; balls.length; j ++) {</cl-cd>
<cl-cd data-idx="80">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">if</span>(innerCircle(x, y, balls.x, balls.y, balls.r)) {</cl-cd>
<cl-cd data-idx="81">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">if</span>(balls.r &lt; 20) balls.r += 2;</cl-cd>
<cl-cd data-idx="82">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balls.color = `#${<span class="tRed">Math</span>.random().toString(16).substr(-6)}`;</cl-cd>
<cl-cd data-idx="83">&nbsp; &nbsp; &nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="84">&nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="85">};</cl-cd>
<cl-cd data-idx="86">initBalls(40);</cl-cd>
<cl-cd data-idx="87">&lt;<span class="tDarkRed">/script</span>&gt;</cl-cd>
</div>

马黑黑 发表于 2024-4-13 13:37

小球接受点击操作,每一次成功点击,重新渲染是会大一点,一直打到半径为20像素,同时每一次成功点击它会变换颜色。

当小球较小时,点击会有点困难。

红影 发表于 2024-4-13 14:08

这个是前面小球撞击帖子的实例吧,好玩。
那些发生纠缠的小球,倒是正好配合了帖子节奏呢{:4_173:}

红影 发表于 2024-4-13 14:09

马黑黑 发表于 2024-4-13 13:37
小球接受点击操作,每一次成功点击,重新渲染是会大一点,一直打到半径为20像素,同时每一次成功点击它会变 ...

我暂停了,再点击,发现渲染和变色也会变化。运动中点击太难了{:4_189:}

红影 发表于 2024-4-13 14:13

奇怪,点击加精华按键的时候,小球忽然变成了横向拉伸了呢。

红影 发表于 2024-4-13 14:15

https://pic.imgdb.cn/item/661a22d868eb93571313394d.jpg

马黑黑 发表于 2024-4-13 14:16

红影 发表于 2024-4-13 14:13
奇怪,点击加精华按键的时候,小球忽然变成了横向拉伸了呢。

JS没有闭包,局部刷新可能受到影响

马黑黑 发表于 2024-4-13 14:16

红影 发表于 2024-4-13 14:09
我暂停了,再点击,发现渲染和变色也会变化。运动中点击太难了

聪明。不过,等运行起来才看到效果。

马黑黑 发表于 2024-4-13 14:16

红影 发表于 2024-4-13 14:08
这个是前面小球撞击帖子的实例吧,好玩。
那些发生纠缠的小球,倒是正好配合了帖子节奏呢

{:4_173:}

马黑黑 发表于 2024-4-13 14:17

红影 发表于 2024-4-13 14:15


这是小球高兴过头了

红影 发表于 2024-4-13 14:25

马黑黑 发表于 2024-4-13 14:16
JS没有闭包,局部刷新可能受到影响

哦哦,这样啊。好在评分没出问题。

红影 发表于 2024-4-13 14:25

马黑黑 发表于 2024-4-13 14:16
聪明。不过,等运行起来才看到效果。

是的,点击后也需要运行才看得到效果,否则是不变的。

红影 发表于 2024-4-13 14:26

马黑黑 发表于 2024-4-13 14:16


它们扭动的节奏正好是音乐节奏{:4_173:}

马黑黑 发表于 2024-4-13 14:26

红影 发表于 2024-4-13 14:26
它们扭动的节奏正好是音乐节奏

有点像

红影 发表于 2024-4-13 14:27

马黑黑 发表于 2024-4-13 14:17
这是小球高兴过头了

都忘乎所以了{:4_189:}

马黑黑 发表于 2024-4-13 14:27

红影 发表于 2024-4-13 14:25
是的,点击后也需要运行才看得到效果,否则是不变的。

整体渲染才出效果

马黑黑 发表于 2024-4-13 14:28

红影 发表于 2024-4-13 14:25
哦哦,这样啊。好在评分没出问题。

JS代码闭包的话,就不会在不同机制的刷新中丢三落四

马黑黑 发表于 2024-4-13 14:28

红影 发表于 2024-4-13 14:27
都忘乎所以了

正常,人家需要欣赏

红影 发表于 2024-4-13 14:29

马黑黑 发表于 2024-4-13 14:26
有点像

这个帖子里的小球纠缠随机发生,却是完美匹配帖子,真棒{:4_199:}
页: [1] 2 3 4 5 6 7 8
查看完整版本: Collide