衝突を考慮

8 6月

先に,JavaScript の学習環境を書いてみたのですが,講義で利用するために,プログラムのサンプルを書いてみています。以前に,重力場の中での運動を書いたので,それに衝突を入れてみました。

衝突 : 画像にリンクが張ってあります。

ソースを下記にあげます。少し説明を書きます。

(19行あたり) mx, my はクリックしたマウスの座標です。
(22行あたり) 運動するボールの座標などを記録するオブジェクトが並んでいます。
(26行あたり) 運動するボールを配列に格納。
(48行あたり) ボールをドキュメントに追加。
(52行あたり) 30 msec ごとに,ボールの座標値を計算する関数(updata)を起動。
(60行あたり) set_r_v は,座標と速度を計算する関数。重力の効果も取り入れいている。
(62行あたり) if_collision は,衝突の判断をする関数。衝突時の速度の計算など。50px 以内なら衝突と判断する。物体の質量はすべて同じとして計算している。衝突はもっとも近くにあるボールのみ考慮する。
(64行あたり) in_box は箱の壁で反射させる関数。
(66行あたり) move は最終的にボールを移動させる関数。
(153行あたり) mouseDown クリックしたマウスの位置を取得する関数。これがIEでしか動かない部分。
(170行あたり) set_v0 は,ボールの速度を再設定する関数。

<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

   <title>first</title>

<style type="text/css">


body {
    margin: 0px;
    padding: 0px;
    background-color: #ffffff;
}

</style>


<script type="text/javascript">


var mx = 0;
var my = 0;


var gray = {id:'maru',src:'maru.gif', x:150,y:150,vx:-1,vy:0};
var red = {id:'red', src:'red.gif', x:210,y:160,vx:1,vy:0};
var blue = {id:'blue', src:'blue.gif', x:30,y:100,vx:-3,vy:0};

var obj_ary = new Array (gray,red,blue);

var obj_ary_length = obj_ary.length;







function startup() {


for (var i in obj_ary) {

var tmpleft = Number(obj_ary[i].x) - 25;

var element = document.createElement('img');

element.setAttribute('id',obj_ary[i].id);
element.setAttribute('src',obj_ary[i].src);

element.style.position = 'absolute';
element.style.left = tmpleft;
element.style.top = '125px';
element.style.height = '50px';

var tmpid = document.getElementById("box")

tmpid.appendChild(element);

}



var step = setInterval(updata,30);


}




function updata() {


for (var i in obj_ary) {

set_r_v(obj_ary[i]);



if_collision(i,obj_ary[i]);


in_box(obj_ary[i]);

move(obj_ary[i]);

}

}


function set_r_v(tmpobj) {

tmpobj.vy  = tmpobj.vy + 0.05;

tmpobj.x = tmpobj.x + tmpobj.vx;
tmpobj.y = tmpobj.y + tmpobj.vy;

return;
}



function if_collision(i,tmpobj) {

var i = Number(i);



min_distance = 1000;
min_j = 10001;

var x1 = tmpobj.x;
var y1 = tmpobj.y;

for (var j = i + 1; j < obj_ary_length; j = j + 1) {

var x2 = obj_ary[j].x;
var y2 = obj_ary[j].y;

var distance = Math.sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));

if (distance < min_distance) {

min_distance = distance;

min_j = j;

}

} // loop for j



if (min_distance*min_distance < 1) {

min_distance = 1;

}

if (min_distance < 50) {

//alert('collision');


var x2 = obj_ary[min_j].x;
var y2 = obj_ary[min_j].y;

var overlap = (50 - min_distance)/1;

var e1 = {x: (x1 - x2)/min_distance,y:(y1 - y2)/min_distance};
var e2 = {x:-(y1 - y2)/min_distance,y:(x1 - x2)/min_distance};

var v1 = {x:obj_ary[i].vx,y:obj_ary[i].vy};
var v2 = {x:obj_ary[min_j].vx,y:obj_ary[min_j].vy};

obj_ary[i].vx = inner_product(v2,e1) * e1.x + inner_product(v1,e2) * e2.x;

obj_ary[i].vy = inner_product(v2,e1) * e1.y + inner_product(v1,e2) * e2.y;

obj_ary[min_j].vx = inner_product(v1,e1) * e1.x + inner_product(v2,e2) * e2.x;

obj_ary[min_j].vy = inner_product(v1,e1) * e1.y + inner_product(v2,e2) * e2.y;



obj_ary[i].x = obj_ary[i].x + overlap * e1.x;
obj_ary[min_j].x = obj_ary[min_j].x - overlap * e1.x;
obj_ary[i].y = obj_ary[i].y + overlap * e1.y;
obj_ary[min_j].y = obj_ary[min_j].y - overlap * e1.y;

}

}




function inner_product(v1,v2) {

return v1.x * v2.x + v1.y * v2.y;

}



function mouseDown() {

var theEvent = window.event;

mx = theEvent.clientX - 10;
my = theEvent.clientY - 10;

//alert("mx = " + mx + " my = " + my);


for (var i in obj_ary) {

set_v0(obj_ary[i]);

}


}


function set_v0(tmpobj) {


var kyori = Math.sqrt((mx - tmpobj.x)*(mx - tmpobj.x) + (my - tmpobj.y)*(my - tmpobj.y));

if (kyori < 1) {

return;

} else {

tmpobj.vx = 3*(mx - tmpobj.x) / kyori;
tmpobj.vy = 3*(my - tmpobj.y) / kyori;

}

}



function move(tmpobj) {

var tmpid = document.getElementById(tmpobj.id);

tmpid.style.left = tmpobj.x - 25;

tmpid.style.top = tmpobj.y - 25;

}


function in_box(tmpobj) {

if ((tmpobj.x < 25) || (275 < tmpobj.x)) {

tmpobj.vx = - tmpobj.vx;

if (tmpobj.x < 25) {

tmpobj.x = 25 + (25 - tmpobj.x);

} else {

tmpobj.x = 275 - (tmpobj.x - 275);

}

}

if ((tmpobj.y < 25) || (275 < tmpobj.y)) {

tmpobj.vy = - tmpobj.vy;

if (tmpobj.y < 25) {

tmpobj.y = 25 + (25 - tmpobj.y);

} else {

tmpobj.y = 275 - (tmpobj.y - 275);

}

}

return;
}


</script>


</head>

<!--<body>-->

<body  onload="startup();">

<div id="box" style="position: absolute; left: 10px; top: 10px; width: 300px; height: 300px; border-width: 1px;  border-color: black; border-style: solid; " onclick='mouseDown();'>


</div>


<div style="position: absolute; left: 30px; top: 500px; width: 300px; height: 100px; border-width: 0px;  border-color: black; border-style: solid; ">
<strong>(参考2) 衝突を取り入れました</strong><br />

ときどき計算間違いをしています。<br />


</div>

</body>
</html>