Last active
December 29, 2015 19:39
-
-
Save SS1031/7718812 to your computer and use it in GitHub Desktop.
D3jsでBoids ターゲット機能をつけてみた。 群れ感に欠ける
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="ja"> | |
<head> | |
<meta charset="utf-8"> | |
<title>D3 Boids</title> | |
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script> | |
</head> | |
<style> | |
</style> | |
<body> | |
<script type="text/javascript"> | |
d3.select("body").style("background-color", "black"); | |
var w = window.innerWidth; | |
var h = window.innerHeight; | |
var NUM_OF_BOIDS = 1000; | |
var BOID_RADIUS = 2; | |
// 初期 ランダム配置 | |
var dataset = new Array(NUM_OF_BOIDS); | |
for(var i=0; i<dataset.length; i++) { | |
dataset[i] = [Math.floor(Math.random() * w), Math.floor(Math.random() * h)]; | |
} | |
var svg = d3.select("body").append("svg") | |
.attr("width", w) | |
.attr("height", h); | |
// ボイドの中心 | |
var center_x = 0; | |
var center_y = 0; | |
// ターゲットの位置 | |
var target_x = w/2; | |
var target_y = h/2; | |
// circle要素の作成 | |
svg.selectAll("circle") | |
.data(dataset) | |
.enter() | |
.append("circle") | |
.attr("cx", function(d) { | |
center_x += d[0]; | |
return d[0]; | |
}) | |
.attr("cy", function(d) { | |
center_y += d[0]; | |
return d[1]; | |
}) | |
.style("fill", "rgb(102,153,255)") | |
.attr("r", BOID_RADIUS); | |
function update() { | |
// ルール1 : 全てのボイドは群の中心に向かおうとする | |
center_x = 0; | |
center_y = 0; | |
// 中心 | |
dataset.forEach(function(d) { | |
center_x += d[0]; | |
center_y += d[1]; | |
}); | |
// 中心 | |
center_x = center_x / NUM_OF_BOIDS - 1; | |
center_y = center_y / NUM_OF_BOIDS - 1; | |
// 中心に向かう速度の計算 | |
var velo = [NUM_OF_BOIDS]; | |
for(var i=0; i<dataset.length; i++) { | |
velo[i] = [(center_x - dataset[i][0]) / 100, (center_y - dataset[i][1]) / 100]; | |
} | |
// ルール2 : 他の個体と距離を取ろうとする | |
for(var i=0; i<dataset.length; i++) { | |
var vx = 0; | |
var vy = 0; | |
for(var j=i; j<dataset.length; j++) { | |
var dx = dataset[j][0] - dataset[i][0]; | |
var dy = dataset[j][1] - dataset[i][1]; | |
var dist = Math.sqrt(dx * dx + dy * dy); | |
if(dist < 15) { | |
dist += 0.00001; | |
vx -= dx / dist; | |
vy -= dy / dist; | |
} | |
} | |
velo[i][0] += vx; | |
velo[i][1] += vy; | |
} | |
// ルール3 : 他の個体と向きと速度を合わせようとする | |
for(var i=0; i<dataset.length; i++) { | |
var pvx = 0; | |
var pvy = 0; | |
for(var j=0; j<dataset.length; j++) { | |
if(i != j) { | |
pvx += dataset[j][0]; | |
pvy += dataset[j][1]; | |
} | |
} | |
pvx /= dataset.length - 1; | |
pvy /= dataset.length - 1; | |
// TODO : ここで割る数字を小さくすると右下に行く 謎 | |
velo[i][0] += (pvx - velo[i][0]) / 500; | |
velo[i][1] += (pvx - velo[i][1]) / 500; | |
} | |
// ルール4 : ターゲットに向かう速度 | |
for(var i=0; i<dataset.length; i++) { | |
// 絶妙なパラメータ調整が必要 | |
velo[i][0] += (target_x - dataset[i][0]) / 50; | |
if((target_x - dataset[i][0]) < 0) { | |
dataset[i][0] += (target_x - dataset[i][0]) / 500; | |
} | |
velo[i][1] += (target_y - dataset[i][1]) / 50; | |
if((target_y - dataset[i][1]) < 0) { | |
dataset[i][1] += (target_y - dataset[i][1]) / 500; | |
} | |
} | |
var indexx = 0; | |
var indexy = 0; | |
// 移動 | |
d3.selectAll("circle").transition() | |
.duration(1) | |
//.delay(function(d, i) { return i * 1; }) | |
.attr("cx", function(d) { | |
d[0] = d[0] + velo[indexx][0]; | |
indexx += 1; | |
return d[0]; | |
}) | |
.attr("cy", function(d) { | |
d[1] = d[1] + velo[indexy][1]; | |
indexy += 1; | |
return d[1]; | |
}); | |
setTimeout(function () { update() }, 1); | |
} | |
// クリック処理 | |
$('svg').click( function(event){ | |
target_x = event.pageX; | |
target_y = event.pageY; | |
}); | |
update(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment