Skip to content

Instantly share code, notes, and snippets.

@SS1031
Last active December 29, 2015 19:39
Show Gist options
  • Save SS1031/7718812 to your computer and use it in GitHub Desktop.
Save SS1031/7718812 to your computer and use it in GitHub Desktop.
D3jsでBoids ターゲット機能をつけてみた。 群れ感に欠ける
<!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