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: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"><<span class="tDarkRed">style</span>></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"><<span class="tDarkRed">/style</span>></cl-cd>
<cl-cd data-idx="6"> </cl-cd>
<cl-cd data-idx="7"><<span class="tDarkRed">div</span> <span class="tRed">id</span>=<span class="tMagenta">"mydiv"</span>></cl-cd>
<cl-cd data-idx="8"> <<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><<span class="tDarkRed">/audio</span>></cl-cd>
<cl-cd data-idx="9"> <<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> /></cl-cd>
<cl-cd data-idx="10"><<span class="tDarkRed">/div</span>></cl-cd>
<cl-cd data-idx="11"> </cl-cd>
<cl-cd data-idx="12"><<span class="tDarkRed">script</span>></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 = () => (<span class="tRed">Math</span>.random() < 0.5 ? -1 : 1) * (<span class="tRed">Math</span>.random() * 0.5 + 0.5);</cl-cd>
<cl-cd data-idx="22"><span class="tBlue">var</span> mState = () => {</cl-cd>
<cl-cd data-idx="23"> aud.paused ?</cl-cd>
<cl-cd data-idx="24"> (mydiv.style.setProperty(<span class="tMagenta">'--state'</span>, <span class="tMagenta">'paused'</span>), cancelAnimationFrame(raf)) :</cl-cd>
<cl-cd data-idx="25"> (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) => <span class="tRed">Math</span>.sqrt((ex - cx) ** 2 + (ey - cy) ** 2) <= r;</cl-cd>
<cl-cd data-idx="28"><span class="tBlue">var</span> drawBall = (x,y,r,color) => {</cl-cd>
<cl-cd data-idx="29"> ctx.save();</cl-cd>
<cl-cd data-idx="30"> ctx.beginPath();</cl-cd>
<cl-cd data-idx="31"> ctx.fillStyle = color;</cl-cd>
<cl-cd data-idx="32"> ctx.arc(x,y,r,0,2*<span class="tRed">Math</span>.PI);</cl-cd>
<cl-cd data-idx="33"> ctx.fill();</cl-cd>
<cl-cd data-idx="34"> ctx.restore();</cl-cd>
<cl-cd data-idx="35">};</cl-cd>
<cl-cd data-idx="36"><span class="tBlue">var</span> move = (ball) => {</cl-cd>
<cl-cd data-idx="37"> <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"> x += spdX;</cl-cd>
<cl-cd data-idx="39"> y += spdY;</cl-cd>
<cl-cd data-idx="40"> <span class="tBlue">if</span>(x - r < 0 || x + r > ww) spdX = - spdX;</cl-cd>
<cl-cd data-idx="41"> <span class="tBlue">if</span>(y - r < 0 || y + r > hh) spdY = - spdY;</cl-cd>
<cl-cd data-idx="42"> ball.x = x;</cl-cd>
<cl-cd data-idx="43"> ball.y = y;</cl-cd>
<cl-cd data-idx="44"> ball.speedX = spdX;</cl-cd>
<cl-cd data-idx="45"> ball.speedY = spdY;</cl-cd>
<cl-cd data-idx="46"> 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 = () => {</cl-cd>
<cl-cd data-idx="49"> ctx.clearRect(0,0,ww,hh);</cl-cd>
<cl-cd data-idx="50"> <span class="tBlue">for</span>(<span class="tBlue">var</span> j = 0; j < balls.length; j ++) {</cl-cd>
<cl-cd data-idx="51"> <span class="tBlue">for</span>(<span class="tBlue">var</span> k = 0; k < balls.length; k ++) {</cl-cd>
<cl-cd data-idx="52"> <span class="tBlue">var</span> dx = balls.x - balls.x, dy = balls.y - balls.y;</cl-cd>
<cl-cd data-idx="53"> <span class="tBlue">var</span> distance = <span class="tRed">Math</span>.sqrt(dx * dx + dy * dy);</cl-cd>
<cl-cd data-idx="54"> <span class="tBlue">if</span>(distance < (balls.r + balls.r)) {</cl-cd>
<cl-cd data-idx="55"> balls.speedX = -balls.speedX;</cl-cd>
<cl-cd data-idx="56"> balls.speedY = -balls.speedY;</cl-cd>
<cl-cd data-idx="57"> balls.speedX = -balls.speedX;</cl-cd>
<cl-cd data-idx="58"> balls.speedY = -balls.speedY;</cl-cd>
<cl-cd data-idx="59"> }</cl-cd>
<cl-cd data-idx="60"> }</cl-cd>
<cl-cd data-idx="61"> move(balls);</cl-cd>
<cl-cd data-idx="62"> }</cl-cd>
<cl-cd data-idx="63"> 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) => {</cl-cd>
<cl-cd data-idx="66"> <span class="tBlue">for</span> (<span class="tBlue">var</span> j = 0; j < total; j ++) {</cl-cd>
<cl-cd data-idx="67"> <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"> 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"> move(balls);</cl-cd>
<cl-cd data-idx="70"> }</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 = () => mState();</cl-cd>
<cl-cd data-idx="74">aud.onseeked = () => cancelAnimationFrame(raf);</cl-cd>
<cl-cd data-idx="75">aud.onended = () => { cancelAnimationFrame(raf); aud.play(); };</cl-cd>
<cl-cd data-idx="76">play.onclick = () => aud.paused ? aud.play() : aud.pause();</cl-cd>
<cl-cd data-idx="77">canv.onclick = (e) => {</cl-cd>
<cl-cd data-idx="78"> <span class="tBlue">var</span> x = e.offsetX, y = e.offsetY;</cl-cd>
<cl-cd data-idx="79"> <span class="tBlue">for</span>(<span class="tBlue">var</span> j = 0; j < balls.length; j ++) {</cl-cd>
<cl-cd data-idx="80"> <span class="tBlue">if</span>(innerCircle(x, y, balls.x, balls.y, balls.r)) {</cl-cd>
<cl-cd data-idx="81"> <span class="tBlue">if</span>(balls.r < 20) balls.r += 2;</cl-cd>
<cl-cd data-idx="82"> balls.color = `#${<span class="tRed">Math</span>.random().toString(16).substr(-6)}`;</cl-cd>
<cl-cd data-idx="83"> }</cl-cd>
<cl-cd data-idx="84"> }</cl-cd>
<cl-cd data-idx="85">};</cl-cd>
<cl-cd data-idx="86">initBalls(40);</cl-cd>
<cl-cd data-idx="87"><<span class="tDarkRed">/script</span>></cl-cd>
</div> 小球接受点击操作,每一次成功点击,重新渲染是会大一点,一直打到半径为20像素,同时每一次成功点击它会变换颜色。
当小球较小时,点击会有点困难。 这个是前面小球撞击帖子的实例吧,好玩。
那些发生纠缠的小球,倒是正好配合了帖子节奏呢{:4_173:} 马黑黑 发表于 2024-4-13 13:37
小球接受点击操作,每一次成功点击,重新渲染是会大一点,一直打到半径为20像素,同时每一次成功点击它会变 ...
我暂停了,再点击,发现渲染和变色也会变化。运动中点击太难了{:4_189:} 奇怪,点击加精华按键的时候,小球忽然变成了横向拉伸了呢。 https://pic.imgdb.cn/item/661a22d868eb93571313394d.jpg 红影 发表于 2024-4-13 14:13
奇怪,点击加精华按键的时候,小球忽然变成了横向拉伸了呢。
JS没有闭包,局部刷新可能受到影响 红影 发表于 2024-4-13 14:09
我暂停了,再点击,发现渲染和变色也会变化。运动中点击太难了
聪明。不过,等运行起来才看到效果。 红影 发表于 2024-4-13 14:08
这个是前面小球撞击帖子的实例吧,好玩。
那些发生纠缠的小球,倒是正好配合了帖子节奏呢
{:4_173:} 红影 发表于 2024-4-13 14:15
这是小球高兴过头了 马黑黑 发表于 2024-4-13 14:16
JS没有闭包,局部刷新可能受到影响
哦哦,这样啊。好在评分没出问题。 马黑黑 发表于 2024-4-13 14:16
聪明。不过,等运行起来才看到效果。
是的,点击后也需要运行才看得到效果,否则是不变的。 马黑黑 发表于 2024-4-13 14:16
它们扭动的节奏正好是音乐节奏{:4_173:} 红影 发表于 2024-4-13 14:26
它们扭动的节奏正好是音乐节奏
有点像 马黑黑 发表于 2024-4-13 14:17
这是小球高兴过头了
都忘乎所以了{:4_189:} 红影 发表于 2024-4-13 14:25
是的,点击后也需要运行才看得到效果,否则是不变的。
整体渲染才出效果 红影 发表于 2024-4-13 14:25
哦哦,这样啊。好在评分没出问题。
JS代码闭包的话,就不会在不同机制的刷新中丢三落四 红影 发表于 2024-4-13 14:27
都忘乎所以了
正常,人家需要欣赏 马黑黑 发表于 2024-4-13 14:26
有点像
这个帖子里的小球纠缠随机发生,却是完美匹配帖子,真棒{:4_199:}