var 位置 = 新しい Vector2(10, 200);
var 速度 = 新しい Vector2(50, -50);
var 加速 = new Vector2(0, 10);
var dt = 0.1;
function step() {
position = Position.add(velocity.multiply(dt));
速度 = Velocity.add(acceleration.multiply(dt));
ctx.ストロークスタイル = "#000000";
ctx.fillStyle = "#FFFFFF";
ctx.beginPath();
ctx.arc(position.x,position.y, 5, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
ctx.ストローク();
}
start("kinematicsCancas", step);
実行 <ボタン onclick="stop();" type="button">停止
<ボタン onclick="clearCanvas();" type="button">クリア
修正代网试试看 開始位置を変更 開始速度を変更(方向を含む) 加速度を変更
このプログラムの中核は step() 関数の 2 つの実行コードです。パーティクル システムは、アニメーションやアニメーションで、雨点、火花、火花、爆発などのさまざまな効果をもたらすためによく使用されます。関連する機能は、たとえば、人が殴られた後にいくつかの光を発し、メインコーナーがそれらを吸収することができます。特性:
粒子は独立、粒子間相互不影響响(不碰撞、不徹底) 粒子有生命期間、生命结束後消滅 粒子は空間の 1 つの点として理解できますが、場合によっては、球体と環境の影響として半径を設定することもできます。 粒子帯には動作状態があり、その他の外部表示状態 (例:色、影など)もあります 粒子は回転運動を考慮せずに線性運動のみを行うことができます(例外もあります) 以下は本文例子里实现的粒子类:
复制代码
this.velocity = 速度;
this.acceleration = Vector2.zero; this.age = 0; this.life = 人生; this.color = カラー; this.size = サイズ; }; 游戏循環环 粒子系统は通常 3 つの周期に分けることができます: 送信粒子
模拟粒子(粒子老化、碰撞、运運動学模拟等等)
渲染パーティクル
は、ゲーム ループ内で各パーティクル システムに対して上記の 3 つのステップを実行する必要があります。パーティクルを生成します。パーティクルは、数値グループの末端に追加されるだけです。 🎜>//ParticleSystem.js
function ParticleSystem() {
// プライベート フィールド
var that = this;
var 粒子 = new Array();
// パブリックフィールド
this.gravity = new Vector2(0, 100);
this.Effects = new Array();
粒子は初期化時に、年 (年齢) はゼロに設定され、生命 (寿命) は固定されています。各シミュレーションが行われるたびに、都市は粒子を老化させます。つまり、年月が増加すると、年月が生命を超えて死に至ります。 🎜>
复制代码
代码如下:
function ParticleSystem() { // ... this.simulate = function(dt) { aging(dt); applyGravity(); applyEffectors(); kinematics(dt); }; // ... // プライベート メソッド function age(dt) { for (var i = 0; i <粒子.長さ; ) { var p = 粒子[i]; if (p.age >= p.life) kill(i); 🎜>else i ; } } function kill(index) { if (particles.length > 1) particles[index] =articles[particles.length - 1]; particles.pop(); } // ... } 関数 kill() でトリックが使用されます。配列内のパーティクルの順序は重要ではないため、中央のパーティクルを削除するには、最後のパーティクルをその要素にコピーし、pop() を使用して最後のパーティクルを削除します。これは通常、配列の途中から要素を直接削除するよりも高速です (C の配列または std::vector にも同じことが当てはまります)。
運動学シミュレーション
この記事の運動学シミュレーション コードの最も重要な 2 つの文をすべてのパーティクルに適用するだけです。さらに、各シミュレーションでは、まず重力加速度が粒子の加速度に書き込まれます。これは、将来的に毎回加速度を変更できるようにするために行われます (これについては、続編で説明します)。
// .. .
function applyGravity() { for (粒子内の変数 i) particles[i].acceleration = that.gravity; function kinematics(dt) { for (パーティクル内の var i) { var p = パーティクル[i] p.position = p.position.add(p.velocity.multiply(dt)); p.velocity = p.パーティクルのレンダリング }円、線分 (現在位置と前の位置)、画像、スプライトなどを使用するなど、さまざまな方法でレンダリングが行われます。この記事では円を使用し、寿命と年齢の比率に応じて円の透明度を制御します。コード スニペットは次のとおりです。 コードをコピーします 。
コードは次のとおりです。
function ParticleSystem() {
// ...
Math.floor(p.color.b * 255) ","
アルファ.toFixed(2) ")"; ctx.beginPath(); ctx.arc(p.position.x, p.position.y, p.size, 0, Math.PI * 2, true ); ctx.closePath(); ctx.fill(); // ... } 基本的なパーティクル システムが完成しました 以下の例では、各フレームがパーティクルを放出します。その位置はキャンバスの中央 (200,200)、放出方向は 360 度、速度は 100、ライフは 1 です。 2 番目の色は赤、半径は 5 ピクセルです。 コードをコピーします コードは次のとおりです。
var ps = new ParticleSystem(); 🎜>var dt = 0.01;
function sampleDirection() {
var theta = Math.random() * 2 * Math.PI;
実行 停止ボタン> コードを変更して試してください 起動位置を変更します< /li>上向きに発射、発射範囲は 90 度以内です
ライフを変更
半径を変更 フレームごとに 5 つのパーティクルを放出します ; 単純衝突 解析ソリューションよりも数値積分を使用する利点を説明するために、この記事では粒子システムに単純衝突を追加します。要件を追加したいと思います。パーティクルが長方形のチャンバー (キャンバス全体のサイズに設定可能) の内壁に衝突すると、衝突して反発します。衝突は完全に弾力的です。 プログラミングの観点からは、この関数を実行するためにコールバックを使用します。 ParticleSystem クラスにはエフェクタの配列があります。キネマティクス シミュレーションを実行する前に、各エフェクタ オブジェクトの apply() 関数が実行されます。 長方形のチャンバーは次のように実装されます。
// ChamberBox.js function ChamberBox(x1, y1, x2, y2) { this. apply = function(particle) { if (particle.position.x -article.size x2) particle.velocity.x = -particle.速度.x; if (粒子.位置.y - 粒子.サイズ y2) 粒子.速度.y = -粒子.速度.y ; }; }
これは実際には、粒子が内壁の範囲を超えたことを検出したときにその方向の速度成分を反転します。 さらに、この例のメイン ループは毎回キャンバス全体をクリアするのではなく、モーション ブラーの効果をシミュレートするためにフレームごとに半透明の黒い四角形を描画します。粒子の色も2色からランダムにサンプリングされます。
var ps = new ParticleSystem(); 🎜>ps .effects.push(new ChamberBox(0, 0, 400, 400)); // 最も重要なことは、このステートメントの追加です。 var dt = 0.01; function sampleDirection(angle1, angle2) ) { var t = Math.random(); var theta = angle1 * t angle2 * (1 - t); return new Vector2(Math.cos(theta), Math.sin(theta) )); } 関数 sampleColor(color1, color2) { var t = Math.random(); return color1.multiply(t).add(color2.multiply(1 - t) )); } 関数 step() { ps.emit(new Particle(new Vector2(200, 200)、sampleDirection(Math.PI * 1.75、Math.PI * 2).multiply( 250), 3, サンプルカラー (Color.blue, Color.purple), 5)); ctx.fillRect (0,0,canvas.width,canvas.height); ps.render(ctx); start("collisionChamberCanvas", step); 🎜><ボタン onclick ="eval(document.getElementById('collisionChamberCode').value)" type="button">実行 停止 インタラクティブな起動 最後に追加された例 インタラクティブ機能はマウスの位置でパーティクルを放出し、パーティクルの方向はマウスの移動速度に少しのノイズを加えたものに基づいています。粒子サイズと寿命にランダム性が追加されます。
コードをコピー コードは次のとおりです:
var ps = new ParticleSystem(); ps.effectors.push(new ChamberBox(0, 0, 400, 400)); var dt = 0.01; var oldMousePosition = Vector2.zero, newMousePosition = Vector2.zero; function sampleDirection(angle1, angle2) { var t = Math.random(); var theta = angle1 * t angle2 * (1 - t); return new Vector2(Math.cos(theta), Math.sin(theta)); } function sampleColor(color1, color2) { var t = Math.random(); return color1.multiply(t).add(color2.multiply(1 - t)); } function sampleNumber(value1, value2) { var t = Math.random(); return value1 * t value2 * (1 - t); } function step() { var velocity = newMousePosition.subtract(oldMousePosition).multiply(10); velocity = velocity.add(sampleDirection(0, Math.PI * 2).multiply(20)); var color = sampleColor(Color.red, Color.yellow); var life = sampleNumber(1, 2); var size = sampleNumber(2, 4); ps.emit(new Particle(newMousePosition, velocity, life, color, size)); oldMousePosition = newMousePosition; ps.simulate(dt); ctx.fillStyle="rgba(0, 0, 0, 0.1)"; ctx.fillRect(0,0,canvas.width,canvas.height); ps.render(ctx); } start("interactiveEmitCanvas", step); canvas.onmousemove = function(e) { if (e.layerX || e.layerX == 0) { // Firefox e.target.style.position='relative'; newMousePosition = new Vector2(e.layerX, e.layerY); } else newMousePosition = new Vector2(e.offsetX, e.offsetY); }; Run Stop
总结
本文介绍了最简单的运动学模拟,使用欧拉方法作数值积分,并以此法去实现一个有简单碰撞的粒子系统。本文的精华其实只有两条简单公式(只有两个加数和两个乘数),希望让读者明白,其实物理模拟可以很简单。虽然本文的例子是在二维空间,但这例子能扩展至三维空间,只须把Vector2换成Vector3。本文完整源代码可
下载 。
续篇会谈及在此基础上加入其他物理现象,有机会再加入其他物理模拟课题。希望各位支持,并给本人更多意见。
声明: この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。