2016-09-24 8 views
0

私は粒子の爆発システムを作っています。ここでは各粒子 が中心点から直接離れて爆発します。しかし、私は本当にファンキーな振る舞いをしています。粒子の爆発の方向を計算するのに問題がある

私はMath.atan2(y2 - y1, x2 - x1) * 180/Math.PI;を使用して中心点の方向を計算し、次に角度から180度を差し引いて方向を逆にします。

Image of what's happening

for (var i = 0; i < le.length; i ++) { 
    // Create new particle element and append it to document. 
    lObj[i] = new Particle(0, 0, 9, 0, 0, document.createElement('span')); 
    lObj[i].spanEl.innerHTML = le[i]; 
    lObj[i].spanEl.style.position = 'relative'; 
    p.appendChild(lObj[i].spanEl); 
    // Find location of this particle. 
    loc[i] = lObj[i].spanEl.getBoundingClientRect(); 
    // Calculate direction toward center point and reverse away from it. 
    lObj[i].direction = directionToPoint(loc[i].left, loc[i].top, centX, centY) - 180; 
} 

var x = 0, 
    y = 0, 
    vel, 
    dir; 

function loop() { 
    for (var i = 0; i < le.length; i ++) { 
     // Update location of each particle 
     x = lObj[i].relX; 
     y = lObj[i].relY; 
     vel = lObj[i].velocity; 
     dir = lObj[i].direction; 
     dir = lObj[i].direction; 
     x += vel * Math.cos(dir * Math.PI/180); 
     y += vel * Math.sin(dir * Math.PI/180); 
     vel = (vel > 0) * (vel - 0.2); 
     lObj[i].relX = x; 
     lObj[i].relY = y; 
     lObj[i].velocity = vel; 
     lObj[i].spanEl.style.left = x + 'px'; 
     lObj[i].spanEl.style.top = y + 'px'; 
    } 
} 
は真剣にこれを把握することはできません。

は、ここで粒子を扱う私のコードの残りの部分です。あなたからの助けが大いに感謝されるでしょう!

編集:上記のコードのコメントにさらに



    var p = document.getElementsByTagName('p')[0], 
     le = p.innerHTML.split(''); 

    p.innerHTML = ''; 

    var lObj = []; 

    function Particle (relX, relY, velocity, direction, keyframe, spanEl) { 
     this.relX = relX; 
     this.relY = relY; 
     this.velocity = velocity; 
     this.direction = direction; 
     this.friction = 0.1; 
     this.keyframe = keyframe; 
     this.spanEl = spanEl; 
    } 

    var loc = []; 

    var centX = 800, centY = 250; 

    var marker = document.getElementsByClassName('marker')[0]; 

    marker.style.left = centX + 'px'; 
    marker.style.top = centY + 'px'; 
+0

ではなくスカラー(1D)方向の見出しとの組み合わせでの速度の値を使用してを使用する必要がありますが、2Dベクトルを維持するならば、それははるかに簡単です。もし完了すれば、あなたは角度が原点に戻っているかどうか気にしないので、少しの三角法を保存します。それは言った - なぜ方向を逆に180°を追加しようとしているのですか? Point-Origin =原点から点へのベクトル。原点=点から原点へのベクトルです。 2Dベクトルを使用すると、基本的なパーティクルシステムが簡単になります。 – enhzflep

+0

'粒子 'のコードと' le'と 'loc'のサンプルデータも提供してください。 – trincot

+0

ねえ、ありがとう!残りのコードを追加しました。私が理解しやすくするためにちょっと言ったことを言い換えることができますか? –

答えて

0

の残りの部分は、ここでは2次元ベクトルを利用不十分実装パーティクルシステムです。私はforループを使って 'アニメーション'を一緒にハッキングしました - 明らかに、私はwindow.requestAnimationFramehttps://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame)を使うべきですが、それはこの例の範囲を超えています。

各パーティクルの位置と方向を初期化するには、次の操作を行います。初期のように1で得られた数値を使用し

  • [0.5 .. -0.5]

    1. が各々から0と1
    2. 減算0.5の間で2個の乱数を取得するので、私は、範囲内の2つの数値を持っていますポジション。
    3. 粒子は ランダムな方向を有し、の範囲の速度を有するであろう0と10の間の数を掛け、それ
    4. (ベクトルとして 位置を表示して)原点からこの位置へのベクトルを正規化[0..10]
    5. 乱数[0..25]を取得し、それに25を加えます - これは最大 年になります。いくつかの楽しみだった

    function byId(id){return document.getElementById(id)} 
     
    window.addEventListener('load', onDocLoaded, false); 
     
    
     
    var partArray = [], maxParticles=500; 
     
    
     
    
     
    function onDocLoaded(evt) 
     
    { 
     
    \t for (var i=0; i<maxParticles; i++) 
     
    \t { 
     
    \t \t var pos = new vec2_t(Math.random()-0.5, Math.random()-0.5); \t \t // give them a poition of [-0.5..0.5] 
     
    \t \t var vel = pos.normalize(); 
     
    \t \t vel.scalarMult(Math.random() * 10); \t \t \t \t \t \t \t \t // give them a velocity of [0..10] 
     
    \t \t var maxAge = (Math.random() * 25) + 25; \t \t \t \t \t \t \t \t // age is in range [25..50] 
     
    \t \t var newParticle = new part_t(pos, vel, maxAge); \t \t \t \t \t \t // create the particle 
     
    \t \t partArray.push(newParticle); \t \t \t \t \t \t \t \t \t \t // and put it in our array 
     
    \t } 
     
    \t 
     
    \t for (var y=0; y<5; y++) 
     
    \t { 
     
    \t \t drawParticles(); 
     
    \t \t moveParticles(); 
     
    \t } 
     
    } 
     
    
     
    function vec2_t(x,y) 
     
    { 
     
    \t this.x = x; 
     
    \t this.y = y; 
     
    \t 
     
    \t this.normalize = function() 
     
    \t { 
     
    \t \t var result = new vec2_t(0,0); 
     
    \t \t var lenSq = (this.x*this.x) + (this.y*this.y); 
     
    \t \t var len = Math.sqrt(lenSq); 
     
    \t \t result.x = this.x/len; 
     
    \t \t result.y = this.y/len; 
     
    \t \t return result; 
     
    \t } 
     
    \t this.scalarMult = function(scalar) 
     
    \t { 
     
    \t \t this.x *= scalar; 
     
    \t \t this.y *= scalar; 
     
    \t } 
     
    \t 
     
    \t return this; 
     
    } 
     
    
     
    function part_t(position, velocity, maxAge) 
     
    { 
     
    \t this.position = position; 
     
    \t this.velocity = velocity; 
     
    \t this.maxAge = maxAge; 
     
    \t this.age = 0; 
     
    \t return this; 
     
    } 
     
    
     
    function setPixel(x,y,ctx) 
     
    { 
     
    \t var imgData = ctx.getImageData(x,y,1,1); 
     
    \t imgData.data[ 0 ] = 255; 
     
    \t imgData.data[ 1 ] = 0; 
     
    \t imgData.data[ 2 ] = 0; 
     
    \t imgData.data[ 3 ] = 255; 
     
    \t ctx.putImageData(imgData,x,y); 
     
    // \t console.log(x+','+y); 
     
    } 
     
    
     
    function drawParticles() 
     
    { 
     
    \t var can = byId('partSysCanvas'); 
     
    \t var ctx = can.getContext('2d'); 
     
    \t var partNum; 
     
    \t for (partNum=0; partNum<maxParticles; partNum++) 
     
    \t { 
     
         // add 256,256 since this is canvas.width/2,canvas.height/2 
     
    \t \t setPixel(256+partArray[partNum].position.x, 256+partArray[partNum].position.y, ctx); 
     
    \t } 
     
    } 
     
    function moveParticles() 
     
    { 
     
    \t for (var i=0; i<maxParticles; i++) 
     
    \t { 
     
    \t \t if (partArray[i].age < partArray[i].maxAge) 
     
    \t \t { 
     
    \t \t \t partArray[i].age++; 
     
    \t \t \t partArray[i].position.x += partArray[i].velocity.x; 
     
    \t \t \t partArray[i].position.y += partArray[i].velocity.y; 
     
    \t \t } 
     
    \t } 
     
    }
    <canvas width=512 height=512 id='partSysCanvas'></canvas>

  • +0

    ありがとうございました:)私は実際には、爆発的なパーティクルシステムを作成しようとするのではなく、爆発的なテキストを作成しようとしています。私が望む効果は、すべての人が中心から爆発することであり、すべてのランダムな方向からではありません。 –

    0

    。繰り返しになりますが、私はベクトルの使用に優先して三角法を避けました。文字は中央から爆発せず、テキストが描かれ、文字は爆発の席から離れたこの点から爆発する。私はvel.scalarMult(10);ですべての粒子に対して均一な爆発速度を設定しましたが、その代わりにこれを上の行でランダム化することができます。

    私はまた、爆弾との距離に基づいて粒子の速度を調整するのに気にしませんでした。すべてが席から離れて爆発するだけで、距離が増すにつれて爆発によって感じられる力が減少することがわかります。

    ここでは演奏するデモがあります。

    私は本当に​​

    "use strict"; 
     
    function newEl(tag){return document.createElement(tag)} 
     
    function byId(id){return document.getElementById(id)} 
     
    // useful for HtmlCollection, NodeList, String types (array-like objects without the forEach method) 
     
    function forEach(array, callback, scope){for (var i=0,n=array.length; i<n; i++)callback.call(scope, array[i], i, array);} // passes back stuff we need 
     
    
     
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
     
    function vec2_t(x,y) 
     
    { 
     
    \t this.x=x; 
     
    \t this.y=y; 
     
    \t this.equals = function(vec2){this.x = vec2.x; this.y = vec2.y;} 
     
    \t this.addVec = function(vec2){this.x += vec2.x; this.y += vec2.y;} 
     
    \t this.scalarMult = function(scalar){this.x *= scalar; this.y *= scalar;} 
     
    \t this.vecLen = function(){return Math.sqrt(this.x*this.x + this.y*this.y);} 
     
    \t this.normalize = function(){ let k = 1.0/this.vecLen(); this.scalarMult(k); } 
     
    \t this.vecSub = function(vec2){this.x-=vec2.x;this.y-=vec2.y;} 
     
    \t this.toString = function(){return"<"+this.x+","+this.y+">"} 
     
    \t return this; 
     
    } 
     
    
     
    function part_t(vec2pos, vec2vel, domElem) 
     
    { 
     
    \t this.pos = vec2pos; 
     
    \t this.vel = vec2vel; 
     
    \t this.domElem = domElem; 
     
    \t return this; 
     
    } 
     
    
     
    
     
    
     
    var particleArray, timerId; 
     
    let explosionOrigin = new vec2_t(156,110); 
     
    
     
    window.addEventListener('load', onDocLoaded, false); 
     
    
     
    
     
    
     
    function onDocLoaded(evt) 
     
    { 
     
    \t particleArray = createPartSys('textInput', 'tgtContainer'); 
     
    \t byId('stepBtn').addEventListener('click', onStepBtnClick); 
     
    \t byId('resetBtn').addEventListener('click', onResetBtnClick); 
     
    \t byId('animateBtn').addEventListener('click', onAnimateBtnClick); 
     
    \t 
     
    \t byId('pauseBtn').addEventListener('click', onPauseBtnClick); 
     
    \t 
     
    \t byId('tgtContainer').addEventListener('click', onClick); 
     
    } 
     
    
     
    function onStepBtnClick(evt) 
     
    { 
     
    \t updatePartSys(particleArray); 
     
    } 
     
    
     
    function onAnimateBtnClick(evt) 
     
    { 
     
    \t timerId = setInterval(function(){updatePartSys(particleArray);}, 100); 
     
    \t this.setAttribute('disabled', 'true'); 
     
    \t byId('pauseBtn').removeAttribute('disabled'); 
     
    } 
     
    
     
    function onPauseBtnClick(evt) 
     
    { 
     
    \t clearInterval(timerId); 
     
    \t this.setAttribute('disabled', 'true'); 
     
    \t byId('animateBtn').removeAttribute('disabled'); 
     
    } 
     
    
     
    function onResetBtnClick(evt) 
     
    { 
     
    \t var bombImg = byId('bomb'); 
     
    \t byId('tgtContainer').innerHTML = ''; 
     
    \t byId('tgtContainer').appendChild(bombImg); 
     
    \t 
     
    \t particleArray = createPartSys('textInput', 'tgtContainer'); 
     
    \t 
     
    \t byId('animateBtn').removeAttribute('disabled'); 
     
    \t clearInterval(timerId); 
     
    } 
     
    
     
    function createPartSys(srcElemId, tgtElemId) 
     
    { 
     
    \t let \t elem = byId(srcElemId); 
     
    \t var str = elem.value, len=str.length; 
     
    
     
    \t let result = []; 
     
    \t let parent = elem; 
     
    \t let curX = elem.offsetLeft - parent.offsetLeft; 
     
    \t let curY = elem.offsetTop - parent.offsetTop; 
     
    
     
    \t let bombImg = byId('bomb'); 
     
    \t bombImg.style = 'position: absolute'; 
     
    \t bombImg.style.left = (explosionOrigin.x - (bombImg.clientWidth/2))+'px'; 
     
    \t bombImg.style.top = (explosionOrigin.y - (bombImg.clientHeight/2))+'px'; 
     
    \t byId(tgtElemId).appendChild(bombImg); 
     
    \t \t 
     
    \t curY = 50; 
     
    \t curX = 50; 
     
    \t forEach(str, 
     
    \t \t \t function(letter) 
     
    \t \t \t { 
     
    \t \t \t \t var span = newEl('span'); 
     
    \t \t \t \t span.className = 'particle'; 
     
    \t \t \t \t if (letter == ' ') letter = '&nbsp;' 
     
    \t \t \t \t let h1 = newEl('h1'); 
     
    \t \t \t \t h1.innerHTML = letter; 
     
    \t \t \t \t span.appendChild(h1); 
     
    \t \t \t \t span.style.left = curX + 'px'; 
     
    \t \t \t \t span.style.top = curY + 'px'; 
     
    \t \t \t \t byId(tgtElemId).appendChild(span); 
     
    \t \t \t \t 
     
    \t \t \t \t var pos = new vec2_t(curX,curY); 
     
    \t \t \t \t 
     
    \t \t \t \t curX += span.offsetWidth; 
     
    
     
    \t \t \t \t var vel = new vec2_t(0,0); 
     
    \t \t \t \t 
     
    \t \t \t \t let letterOrigin = getCenter(span); 
     
    \t \t \t \t 
     
    \t \t \t \t vel.equals(letterOrigin); 
     
    \t \t \t \t vel.vecSub(explosionOrigin); 
     
    \t \t \t \t vel.normalize(); 
     
    \t \t \t // \t vel.scalarMult((Math.random()*1) + 4); 
     
    \t \t \t \t vel.scalarMult(10); 
     
    \t \t \t \t 
     
    \t \t \t \t var newPart = new part_t(pos,vel,span); 
     
    \t \t \t \t result.push(newPart); 
     
    \t \t \t } 
     
    \t \t); 
     
    \t return result; 
     
    } 
     
    
     
    function updatePartSys(partSys) 
     
    { 
     
    \t forEach(
     
    \t \t \t partSys, 
     
    \t \t \t function(part, index, array) 
     
    \t \t \t { 
     
    \t \t \t \t part.pos.addVec(part.vel); \t \t \t \t \t \t // position += velocity 
     
    \t \t \t \t var gravity = new vec2_t(0,0.98/3); \t \t \t \t // arbitrary value chosen 
     
    \t \t \t \t part.vel.scalarMult(0.95); \t \t \t \t \t \t // velocity *= 0.95 \t - needs to be quite high. it simulates wind resistance 
     
    \t \t \t \t part.vel.addVec(gravity); \t \t \t \t \t \t // velocity += gravity 
     
    \t \t \t \t part.domElem.style.left = part.pos.x + "px"; 
     
    \t \t \t \t part.domElem.style.top = part.pos.y + "px"; 
     
    \t \t \t } 
     
    \t \t); 
     
    } 
     
    
     
    function onClick(evt) 
     
    { 
     
    \t let elemRect = byId('tgtContainer').getBoundingClientRect(); 
     
    \t let posX = evt.clientX - elemRect.left, posY = evt.clientY-elemRect.top; 
     
    \t explosionOrigin.x = posX; 
     
    \t explosionOrigin.y = posY; 
     
    \t onResetBtnClick(); 
     
    } 
     
    
     
    function getCenter(elem) 
     
    { 
     
    \t let x = elem.offsetLeft + (elem.offsetWidth/2); 
     
    \t let y = elem.offsetTop + (elem.offsetHeight/2); 
     
    \t let result = new vec2_t(x,y); 
     
    \t return result; 
     
    }
    #tgtContainer 
     
    { 
     
    \t position: relative; 
     
    \t height: 256px; 
     
    \t width: 512px; 
     
    \t border: solid 1px black; 
     
    \t overflow: hidden; 
     
    \t background-color: white; 
     
    } 
     
    .particle 
     
    { 
     
    \t display: inline-block; 
     
    \t position: absolute; 
     
    } 
     
    .panel 
     
    { 
     
    \t display: inline-block; 
     
    \t border: solid 1px #113; 
     
    \t border-radius: 8px; 
     
    \t margin: 8px; 
     
    \t padding: 8px; 
     
    \t background-image: url(https://www.gravatar.com/avatar/97c2d181ef6bbb9eee0c4033561c3891?s=48&d=identicon&r=PG); 
     
    \t background-size: 100% 100%; 
     
    } 
     
    
     
    #textContainer 
     
    { 
     
    \t display: block; 
     
    } 
     
    
     
    #textContainer textarea 
     
    { 
     
    \t width: 100%; 
     
    \t padding: 0; 
     
    \t margin: 1px 0px; 
     
    }
    <div class='panel'> 
     
    \t \t <div id='textContainer'><textarea id='textInput'>click to set bomb position</textarea></div> 
     
    \t \t <hr> 
     
    \t \t <button id='resetBtn'>Reset</button><button id='stepBtn'>Single Step</button> | <button id='animateBtn'>Animate</button><button id='pauseBtn' disabled>Pause</button> 
     
    \t \t <hr> 
     
    \t \t <div id='tgtContainer'> 
     
    \t \t </div> 
     
    \t </div> 
     
    \t <svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" id='bomb'> 
     
    \t \t <g transform="translate(0,-1020.3622)"> 
     
    \t \t \t <path d="m23.23,15.84a10.55,10.55,0,1,1,-21.11,0,10.55,10.55,0,1,1,21.11,0z" transform="matrix(1.1875635,0,0,1.1875635,0.68612298,1020.367)" fill="#26201e"/> 
     
    \t \t \t <path d="m23.23,15.84a10.55,10.55,0,1,1,-21.11,0,10.55,10.55,0,1,1,21.11,0z" transform="matrix(0.86603158,0,0,0.86603158,2.4299747,1024.1874)" fill="#333"/> 
     
    \t \t \t <path d="m-13.04,19.32a1.964,1.964,0,1,1,-3.929,0,1.964,1.964,0,1,1,3.929,0z" transform="matrix(1.924285,1.1058108,-1.1908732,2.0723069,62.314757,1012.6494)" fill="#CCC"/> 
     
    \t \t \t <path d="m15.69,1026c0.02518-5.037,7.647-7.396,8.907-2.969,0.7936,2.761,1.349,5.666,4.877,6.786" stroke="#888" stroke-width="1.5px" fill="none"/> 
     
    \t \t \t <rect height="2.399" width="4.798" y="1026" x="13.31" stroke-width="0" fill="#26201e"/> 
     
    \t \t \t <path fill="#F00" transform="translate(2.0203051,1022.13)" d="M29.8,10.53,27.1,9.62,24.82,11.32,24.86,8.477,22.54,6.833,25.25,5.989,26.1,3.271,27.74,5.595,30.59,5.558,28.89,7.839z"/> 
     
    \t \t </g> 
     
    \t </svg>

    関連する問題