[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた
以前『JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた』 というエントリーを書いたのですが, tmlib.js の仕様が色々と変わってしまい動かない状態だったので, 修正しました.
よかったら参考にしてください.
自作ライブラリ tmlib.js を使って, 円同士の衝突プログラムを作ってみました.
やっているのは,
- 円同士の衝突判定
- めり込みの補正
- 衝突後の反発
です.
ちゃんと計算するなら, 衝突時間を調べてその分ベクトルの長さを調整して… ってやんないといけないのですが, 速度的に問題があるってのと難易度が上がってしまう(ホントはめんどくさい)のでちょっと省略しています.
サンプルは jsdo.it の方に移植してあるので, 実際に 動かしたり, fork してイジったりして頂けると嬉しいです.
Table of contents
Code
JavaScript 部分のコードです
/* * phi */ /* * グローバル */ var app = null; var visibleTrace = true; var circleList = []; var target = null; /* * 定数 */ var SCREEN_WIDTH = 640; var SCREEN_HEIGHT = 640; var BOUNCINESS = 0.8; var FRICTION = 0.99; var GRAVITY = tm.geom.Vector2(0, 0.8); var CIRCLE_RADIUS = 30; var CIRCLE_MAX_NUM = 15; var CIRCLE_PURSUIT_RATE = 0.25; // 収束率 /* * プレロード */ tm.preload(function() { }); /* * メイン処理 */ tm.main(function() { app = tm.app.CanvasApp("#world"); app.resize(SCREEN_WIDTH, SCREEN_HEIGHT); app.fitWindow(); app.background = "rgba(0, 0, 0, 0.25)"; for (var i=0; i<CIRCLE_MAX_NUM; ++i) { var circle = Circle(); app.currentScene.addChild(circle); circleList.push(circle); } for (var i=0; i<circleList.length-1; ++i) { var target = circleList[i]; for (var j=i+1; j<circleList.length; ++j) { var other = circleList[j]; target.collision.add(other); } } /* // Stats app.enableStats(); // dat.GUI var gui = app.enableDatGUI(); if (gui) { gui.add(window, "explode"); gui.add(window, "visibleTrace").setValue(true).onChange(function(){ app.background = (visibleTrace) ? "rgba(0, 0, 0, 0.25)" : "rgba(0, 0, 0, 1)"; }); gui.add(window, "BOUNCINESS", 0, 1, 0.1); gui.add(window, "FRICTION", 0, 1, 0.01); // gravity フォルダ var gravityFolder = gui.addFolder("gravity"); gravityFolder.add(GRAVITY, "x", -2, 2, 0.1); gravityFolder.add(GRAVITY, "y", -2, 2, 0.1); gravityFolder.open(); } */ app.update = function() { var scene = this.currentScene; var key = this.keyboard; // ポーズ if (key.getKeyDown("space") == true) { (scene.isUpdate == true) ? scene.sleep() : scene.wakeUp(); } } // mdlclick でキャプチャ tm.dom.Element(app.getElement()).event.mdlclick(function() { app.canvas.saveAsImage(); }); app.run(); }); window.explode = function() { for (var i=0; i<circleList.length; ++i) { var circle = circleList[i]; circle.explode(); } }; /* * サークルクラス */ var Circle = tm.createClass({ superClass: tm.app.CanvasElement, init: function() { this.superInit(40, 40); // 位置をセット this.x = Math.rand(0, app.width); this.y = Math.rand(0, app.height); // パラメータセット this.radius = Math.rand(25, 50); this.m = Math.PI*this.radius*this.radius; // 面積 = 重さにする // 表示色設定 this.colorAngle = Math.rand(0, 360); var canvas = document.createElement("canvas"); var context= canvas.getContext("2d"); var grad = context.createRadialGradient(0, 0, 0, 0, 0, this.radius); grad.addColorStop(0.0, "hsla({color}, 65%, 50%, 0.0)".format({color: this.colorAngle})); grad.addColorStop(0.95, "hsla({color}, 65%, 50%, 1.0)".format({color: this.colorAngle})); grad.addColorStop(1.0, "hsla({color}, 65%, 50%, 0.0)".format({color: this.colorAngle})); this.fillStyle = grad; this.strokeStyle= "white"; this.blendMode = "lighter"; // マウスやタッチ反応を有効化 this.interaction; // this.explode(); }, update: function(app) { // 掴んでいるサークルが自分だった場合 if (this === target) { var p = app.pointing; this.position.set(this.x+this.pointing.x, this.y+this.pointing.y); this.velocity.set(p.dx, p.dy); return ; } this.velocity.mul(FRICTION); this.velocity.add(GRAVITY); this.position.add(this.velocity); // var left = this.radius; var right = app.width-this.radius; var top = this.radius; var bottom = app.height-this.radius; if (this.x < left) { this.x = left; this.velocity.x*=-1; } if (this.x > right) { this.x = right; this.velocity.x*=-1; } if (this.y < top) { this.y = top; this.velocity.y*=-1; } if (this.y > bottom){ this.y = bottom; this.velocity.y*=-1; } }, draw: function(canvas) { canvas.fillCircle(0, 0, this.radius); }, explode: function() { // 向きをセット this.velocity = tm.geom.Vector2.random(0, 360, 32); }, oncollisionstay: function(e) { var other = e.other; var abVec = tm.geom.Vector2.sub(other.position, this.position); // 自分から相手へのベクトル var len = abVec.length(); if (len == 0) return ; abVec.normalize(); var distance = (this.radius + other.radius)-len; // 自分と相手の距離 var sinkVec = tm.geom.Vector2.mul(abVec, distance/2); this.position.sub(sinkVec); other.position.add(sinkVec); // 向きベクトルを調整する var V = tm.geom.Vector2; var m0 = this.m; var m1 = other.m; var e = BOUNCINESS; var ma = ( (m1 / (m0+m1))*(1+e) ) * V.dot(V.sub(other.velocity, this.velocity), abVec); var mb = ( (m0 / (m0+m1))*(1+e) ) * V.dot(V.sub( this.velocity, other.velocity), abVec); this.velocity.add( V.mul(abVec, ma) ); other.velocity.add( V.mul(abVec, mb) ); }, onmousedown: function() { console.log("a"); target = this; this.velocity.set(0, 0); }, onmouseup: function() { target = null; }, });
Tips
衝突判定の流れ
tm.app.CanvasElement の collision に衝突判定させたい 要素を登録すると自動的に衝突判定するようになります.
for (var i=0; i<circleList.length-1; ++i) { var target = circleList[i]; for (var j=i+1; j<circleList.length; ++j) { var other = circleList[j]; target.collision.add(other); } }
そして, 衝突時に collisionstay
イベントを発行します.
oncollisionstay: function(e) { ... }
めり込みの補正
めり込んだ距離の半分の長さだけそれぞれの円を移動させることでめり込んだ分を補正しています.
ベクトルの計算には自作の Vector3 クラスを使用しています. 使い方は C++ ゲームライブラリや C# の XNA にあるような Vector3 と基本同じです.
var other = e.other; var abVec = tm.geom.Vector2.sub(other.position, this.position); // 自分から相手へのベクトル var len = abVec.length(); if (len == 0) return ; abVec.normalize(); var distance = (this.radius + other.radius)-len; // 自分と相手の距離 var sinkVec = tm.geom.Vector2.mul(abVec, distance/2); this.position.sub(sinkVec); other.position.add(sinkVec);
衝突後の反発
互いの向きベクトル, 質量を考慮して衝突後の向きベクトルを計算しています.
// 向きベクトルを調整する var V = tm.geom.Vector2; var m0 = this.m; var m1 = other.m; var e = BOUNCINESS; var ma = ( (m1 / (m0+m1))*(1+e) ) * V.dot(V.sub(other.velocity, this.velocity), abVec); var mb = ( (m0 / (m0+m1))*(1+e) ) * V.dot(V.sub( this.velocity, other.velocity), abVec); this.velocity.add( V.mul(abVec, ma) ); other.velocity.add( V.mul(abVec, mb) );
[…] [New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた […]
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/HWVzPJtR
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life 以前『JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた』 というエ… http://t.co/dq1m3PkZ
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/M6MzF4EG
javascript: [New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/zNQSLkJj
javascript: [New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/zNQSLkJj
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life: 以前『JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた』… http://t.co/R44TooAL
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/EkgV6pXy
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/EGkxHgIN
【はてブ新着IT】 [New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/zBXXip4I
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/m0k2OaDO
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/R7s7nVqX
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/euOhXJPH
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた http://t.co/d7LiTtI0 @phi_jpから
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life
http://t.co/hxOcYzfM
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/TLpvMmHJ #javascript
javascript: [New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/dViMs5rY
JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/8LzcpGzy
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life
以前『JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた』 というエントリーを書いたのですが,
tmlib.js の仕様が色々と変わってしまい動かない状態だったので, 修正しました. よかったら参考にしてください. 自作ライブラリ
tmlib.js を使って, 円同士の衝突プログラムを作ってみました. やっているのは, 円同士の衝突判定 めり込みの補正 衝突後…
はてなブックマーク – [New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life
はてなブックマークに追加
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/aOaOj6uw
Reading… [New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Lif… http://t.co/ZnFuG4AH by http://t.co/8zLaOsv7
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life:以前『JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた』 というエントリ.. http://t.co/QoW8FRu1
“[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life” http://t.co/x3zkVMuy
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/3Hs6aNw0
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life [コンピュータ・IT] [blog-tech].. http://t.co/QoW8FRu1
[hatena antenna] [New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/Hcv9XaHt
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/TLpvMmHJ #javascript
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/TLpvMmHJ #javascript
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた http://t.co/qaqjeBe4 @phi_jpさんから
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた | TM Life http://t.co/KA4yeqmH
[New] JavaScript ライブラリ tmlib.js で円同士の衝突プログラムを作ってみた http://t.co/d7LiTtI0 @phi_jpから