メニュー 閉じる

007. p5.jsで自律エージェントのパーティクルを表示してみる

Processingのヒーロー、ダニエル・シフマンさんの例を参考に自律エージェントのパーティクルを表示。それぞれの小さな矢印は誰かに動きを命令されるわけではなく、周りの状況を判断し自分の動きを決めます。

このサンプルは画面が格子状になっていて、そこにnoiseで生成したランダムなベクトルが設定されています。小さな矢印は、自分がいる場所に設定されているベクトルを参照して次の動きを判断します。

http://www.velvet-number.com/p5_test/test006/

var debug;

var flowfield;

var vehicles;

function setup () {

	pixelDensity (displayDensity ());
	createCanvas (windowWidth, windowHeight);
	background (0);
	colorMode (HSB, 100);

	flowfield = new FlowField (20);
	flowfield.init ();
	vehicles = [];

	for (var i = 0; i < 1000; i++) {
		vehicles.push (new Vehicle (new p5.Vector (random (width), random (height)), random (2, 5), random (0.1, 0.5)));
	}

	debug = false;

}

function draw () {

	background (0);

	if (debug) {
		flowfield.render ();
	}

	for (var i = 0; i < vehicles.length; i++) {
		vehicles[i].follow (flowfield);
		vehicles[i].run ();
	}

	fill (100);
	noStroke ();
	text("Hit space bar to toggle debugging lines.\nClick the mouse to generate a new flow field.", 20, height - 30);

}

function keyPressed () {

	if (key == ' ') {
		debug = !debug;
	}

}

function mousePressed () {

	flowfield.init ();
	
}
function FlowField (r) {

	var field = [];

	var resolution = r;
	var cols = width / resolution;
	var rows = height / resolution;

	this.init = function () {

		noiseSeed (int (random (10000)));

		var xoff = 0;
		for (var i = 0; i < cols; i++) {
			var yoff = 0;
			field[i] = [];
			for (var j = 0; j < rows; j++) {
				var theta = map (noise (xoff, yoff), 0, 1, -TWO_PI, TWO_PI);
				field[i][j] = new p5.Vector (cos (theta), sin (theta));
				yoff += 0.1;
			}
			xoff += 0.1;
		}

	}

	this.render = function () {

		for (var i = 0; i < cols; i++) {
			for (var j = 0; j < rows; j++) {
				this.draw_vector (field[i][j], i * resolution, j * resolution, resolution);
			}
		}

	}

	this.draw_vector = function (v, x, y, sc) {

		stroke (100, 50);

		var len = v.mag () * sc;

		push ();
		translate (x, y);
		rotate (v.heading ());
		line (0, 0, len, 0);
		pop ();

	}

	this.lookup = function (look_v) {

		var col = int (constrain (look_v.x / resolution, 0, cols - 1));
		var row = int (constrain (look_v.y / resolution, 0, rows - 1));
		return (field[col][row].copy ());

	}

}
function Vehicle (l, ms, mf) {

	var location = l.copy ();
	var velocity = new p5.Vector (0, 0);
	var acceleration = new p5.Vector (0, 0);

	var r = 3.0;
	var maxforce = mf;
	var maxspeed = ms;
	var theta;

	this.run = function () {
		this.update ();
		this.border ();
		this.render ();
	}

	this.update = function () {

		velocity.add (acceleration);
		velocity.limit (maxspeed);
		location.add (velocity);
		acceleration.mult (0);

	}

	this.border = function () {

		if (location.x < -r) location.x = width + r;
		if (location.y < -r) location.y = height + r;
		if (location.x > width + r) location.x = -r;
		if (location.y > height + r) location.y = -r;

	}

	this.render = function () {

		theta = velocity.heading () + PI / 2;

		fill (map (theta, -1.0, 5.0, 0, 100), 100, 100);
		stroke (50);
		strokeWeight (1);
		push ();
		translate (location.x, location.y);
		rotate (theta);
		beginShape ();
		vertex (0, -r * 2);
		vertex (-r, r * 2);
		vertex (r, r * 2);
		endShape (CLOSE);
		pop ();

	}

	this.applyForce = function (force) {

		acceleration.add (force);

	}

	this.follow = function (flow) {

		var desired = flow.lookup (location);
		desired.mult (maxspeed);

		var steer = p5.Vector.sub (desired, velocity);
		steer.limit (maxforce);

		this.applyForce (steer);

	}

}

 

Posted in p5.js , processing