Math.random()*(y-x)+x 公式分析

Math.random()*(y-x)+x 公式分析

欢迎

  • 本文章主要使用 JavaScript 语言,但是思想是通用的

在一些编程语言中,Math.random()只能生成一个零到一之间[0,1)的数字

我们希望生成一个[0,1)的数字

正常的使用Math.random()这个方法即可

// 生成随机数
console.log(Math.random());

// 重复运行3次
// 输出结果 0.824860163382928
// 输出结果 0.2828677085558433
// 输出结果 0.7065201777863614

我们希望生成[0,10)的数字

我们只需要把这个随机数乘一个数即可

console.log(Math.random() * 10);

// 重复运行3次
// 输出结果 7.475350215085657
// 输出结果 9.37430923250589
// 输出结果 3.7502072379588847

我们想象一个不可能情况可以帮助我更快理解

假设:我们现在的随机数是1,这个1也是我们目前最大的随机数,我们目前的方法Math.random()我们目前的区间是[0,1),我们希望区间能够扩大10倍,于是我们左右区间都乘了10,0乘10还是0,但是1乘10等于10,所以我们Math.random() * 10的区间是[0,10)

所以==我们希望他的最大区间是多少我们就在这个公式后面乘多少==,例如我希望他生成0到97之间的数字,公式就会长成这个样子

Math.random() * 97

我们希望生成一个[x,y)的数字

假设我们现在需要生成一个3到7之间的数字,我们先写出他的区间[3,7),我们可以让左区间归零,我们把左右区间同时减去3(之后会加回来)
[ 3 − 3 ⏞ 左区间 , 7 − 3 ⏞ 右区间 ) → [ 0 , 4 ) [\overbrace{3-3}^{左区间} ,\overbrace{7-3}^{右区间}) \rightarrow [0,4) [33 左区间,73 右区间)[0,4)

现在我们的区间长成这个样子[0,4),我们就可以用上面的方法写出我们的公式

console.log(Math.random() * 4);

// 重复运行3次
// 输出结果1.2476033188729243
// 输出结果 1.330843857626764
// 输出结果 3.176887420042733

然后我们现在让他的值移动到[3,7),我们可以让最终结果再加3,就可以把一开始减去的给重新加回来

for(let i = 0;i<3;i++){
    console.log(Math.random() * 4 + 3);
}

// 输出结果
// 输出结果 3.693767070707926
// 输出结果 6.000697646107264
// 输出结果 5.153719945106879

我们现在就应该发现了,这个4代表的其实是我们左区间被移动回原点时我们右区间的值,这个值等同于左右区间的差,等同于右区间减去左区间
KaTeX parse error: Expected 'EOF', got '&' at position 2: &̲&左区间被移动回原点时我们右区…
既然这个值等于右区间减去左区间,我们期待的随机数是[x,y),那么这个值自然就是y-x,然后我们再加上我们移动的数字x,最终我们公式长成这样
M a t h . r a n d o m ( ) ⏞ 生成一个 0 到 1 之间的数 × ( y − x ) ⏞ 左右区间的差 + x ⏞ 将左区间从 0 增加到 x \overbrace{Math.random()}^{生成一个0到1之间的数}\times\overbrace{(y-x)}^{左右区间的差}+\overbrace{x}^{将左区间从0增加到x} Math.random() 生成一个01之间的数×(yx) 左右区间的差+x 将左区间从0增加到x

<canvas id="waveCanvas" width="800" height="600"></canvas> <script> const canvas = document.getElementById('waveCanvas'); const ctx = canvas.getContext('2d'); class WaveParticle { constructor(x, y) { this.x = x; this.y = y; this.radius = 3; // 初始随机扩散方向 const angle = Math.random() * Math.PI * 2; this.speed = 3; this.vx = Math.cos(angle) * this.speed; this.vy = Math.sin(angle) * this.speed; this.life = 5.0; // 生命周期 // 新增属性 (插入到constructor中) this.maxSplitTimes = 10; // 初始粒子可分裂次数 this.splitCount = 0; // 已分裂次数 this.splitCooldown = 0; // 分裂冷却时间(毫秒时间戳) } } // ===== 全局配置 ===== const particles = []; const DAMPING = 0.02; // 能量衰减 const REPULSE_RADIUS = 10; // 排斥作用半径 // ===== 点击生成波纹 ===== canvas.addEventListener('click', (e) => { const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; // 生成环形粒子群 for(let i=0; i<36; i++) { particles.push(new WaveParticle(x, y)); } }); // ===== 物理更新 ===== function updateParticles() { particles.forEach((p, index) => { // 生命周期衰减 p.life -= 0.002; if(p.life <= 0) { particles.splice(index, 1); return; } // 边界反弹 if(p.x < 0 || p.x > canvas.width) p.vx *= -1; if(p.y < 0 || p.y > canvas.height) p.vy *= -1; // 能量衰减 p.vx *= (1 - DAMPING); p.vy *= (1 - DAMPING); // 更新位置 p.x += p.vx; p.y += p.vy; // 粒子间碰撞检测 particles.forEach(other => { if(p === other) return; const dx = other.x - p.x; const dy = other.y - p.y; const dist = Math.sqrt(dx*dx + dy*dy); if(dist < REPULSE_RADIUS) { // 排斥力计算 const force = (REPULSE_RADIUS - dist) / REPULSE_RADIUS; const angle = Math.atan2(dy, dx); p.vx -= Math.cos(angle) * force * 0.5; p.vy -= Math.sin(angle) * force * 0.5; // ===== 插入碰撞分裂逻辑 ===== (在现有碰撞检测循环内) if(dist < p.radius * 2 && performance.now() > p.splitCooldown && p.splitCount < p.maxSplitTimes) { // 生成两个新粒子 for(let i=0; i<2; i++) { const angle = Math.random() * Math.PI * 2; const newParticle = new WaveParticle(p.x, p.y); // 继承属性修改 newParticle.maxSplitTimes = 3; // 子代最大分裂次数 newParticle.splitCooldown = performance.now() + 5000; // 5秒冷却 newParticle.vx = p.vx * 0.8 + Math.cos(angle) * 2; newParticle.vy = p.vy * 0.8 + Math.sin(angle) * 2; particles.push(newParticle); } // 更新母体状态 p.splitCount++; p.splitCooldown = performance.now() + 500; } } }); }); } // ===== 渲染绘制 ===== function draw() { ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; ctx.fillRect(0, 0, canvas.width, canvas.height); particles.forEach(p => { ctx.beginPath(); ctx.arc(p.x, p.y, p.radius, 0, Math.PI*2); ctx.fillStyle = `rgba(0, 150, 255, ${p.life})`; ctx.fill(); }); } // ===== 动画循环 ===== function animate() { updateParticles(); draw(); requestAnimationFrame(animate); } animate(); </script>用这段代码,尽量不改动原有代码和功能,添加粒子数量检测,并且超过500粒子删除最早的粒子,把完整的代码给我运行
最新发布
03-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值