p5js/vehicle.js
2022-12-11 03:30:43 +08:00

207 lines
6.1 KiB
JavaScript

let vehicle1;
let vehicle2;
function setup() {
cursor(CROSS);
createCanvas(600, 600);
vehicle1 = new Vehicle(300, 300, "#CCCCCC");
vehicle2 = new Vehicle(300, 300, "#CC3333");
vehicle2.velocity = randomVector(5);
}
function draw() {
// 追逐鼠标();
// 逃避鼠标();
// 小车追逐();
小车巡游();
}
function 追逐鼠标() {
background(64);
vehicle1.seek({ position: createVector(mouseX, mouseY) });
vehicle1.move();
vehicle1.turn();
vehicle1.drawPath();
vehicle1.show();
}
function 逃避鼠标() {
background(64);
vehicle1.flee({ position: createVector(mouseX, mouseY) });
vehicle1.move();
vehicle1.turn();
vehicle1.drawPath();
vehicle1.show();
}
function 小车追逐() {
background(64);
vehicle1.seek(vehicle2, 20);
vehicle2.move();
vehicle1.move();
if (vehicle2.turn()) vehicle2.velocity = randomVector(random(2, 5));
vehicle1.turn();
vehicle1.drawPath();
vehicle2.show("point");
vehicle1.show();
}
function 小车巡游() {
background(64);
vehicle1.wander();
vehicle1.move();
vehicle1.turn();
vehicle1.drawPath();
vehicle1.show();
}
/**
* 返回可指定大小的随机二维向量
* @param {number} magnitude 向量大小
* @return {p5.Vector} vector 随机二维向量
*/
function randomVector(magnitude) {
let vector = p5.Vector.random2D();
return magnitude ? vector.mult(magnitude) : vector;
}
class Vehicle {
constructor(x, y, color) {
this.path = [];
this.color = color;
this.position = createVector(x, y);
this.velocity = createVector(0, 0);
this.heading = this.velocity.heading();
this.acceleration = createVector(0, 0);
this.maxVelocity = 5;
this.maxAcceleration = 0.25;
}
seek(target, slowdownDistance = 100) {
const desired = p5.Vector.sub(target.position, this.position);
const distance = desired.mag();
const magnitude =
slowdownDistance > 0 && distance <= slowdownDistance
? map(distance, 0, slowdownDistance, 0, this.maxVelocity)
: this.maxVelocity;
desired.setMag(magnitude);
const steering = p5.Vector.sub(desired, this.velocity);
this.acceleration.add(steering);
}
flee(target, fleeDistance = 100) {
const desired = p5.Vector.sub(this.position, target.position);
const distance = desired.mag();
const magnitude =
!fleeDistance || fleeDistance <= 0
? this.maxVelocity
: distance <= fleeDistance
? map(distance, 0, fleeDistance, this.maxVelocity, 0)
: 0;
desired.setMag(magnitude);
const steering = p5.Vector.sub(desired, this.velocity);
this.acceleration.add(steering);
}
wander() {
const target = this.velocity.copy();
target.setMag(50).add(this.position);
// stroke(128);
// const x1 = target.x + -25 * cos(PI / 2 + this.heading);
// const y1 = target.y + -25 * sin(PI / 2 + this.heading);
// const x2 = target.x + 25 * cos(PI / 2 + this.heading);
// const y2 = target.y + 25 * sin(PI / 2 + this.heading);
// line(x1, y1, x2, y2);
const offset = map(noise(Date.now() / 1000), 0, 1, -50, 50);
const x = offset * cos(PI / 2 + this.heading);
const y = offset * sin(PI / 2 + this.heading);
target.add(x, y);
noStroke();
fill("#F063A4");
circle(target.x, target.y, 5);
const steering = target.sub(this.position);
this.acceleration.add(steering);
}
move() {
this.acceleration.limit(this.maxAcceleration);
this.velocity.add(this.acceleration);
if (this.velocity.mag() > 0) this.heading = this.velocity.heading();
this.velocity.limit(this.maxVelocity);
this.position.add(this.velocity);
this.acceleration.set(0, 0);
this.path.push(this.position.copy());
}
turn() {
let x = this.position.x;
let y = this.position.y;
while (x < 0 || x >= width) x = (x + width) % width;
while (y < 0 || y >= height) y = (y + height) % height;
const edgeCrossed = x != this.position.x || y != this.position.y;
this.position.x = x;
this.position.y = y;
if (edgeCrossed) {
this.path.pop();
this.path.push(null);
}
return edgeCrossed;
}
// bounce() {
// if (this.position.x <= this.size / 2) {
// this.position.x = this.size / 2;
// this.velocity.x *= -1;
// return true;
// } else if (this.position.x > canvasWidth - this.size / 2) {
// this.position.x = canvasWidth - this.size / 2;
// this.velocity.x *= -1;
// return true;
// }
// if (this.position.y <= this.size / 2) {
// this.position.y = this.size / 2;
// this.velocity.y *= -1;
// return true;
// } else if (this.position.y >= canvasHeight - this.size / 2) {
// this.position.y = canvasHeight - this.size / 2;
// this.velocity.y *= -1;
// return true;
// }
// return false;
// }
drawPath(color = 128) {
push();
noFill();
stroke(color);
strokeWeight(1);
if (this.path.length >= 10240) this.path.shift();
beginShape();
this.path.forEach((v) => {
if (!v) {
endShape();
beginShape();
} else {
vertex(v.x, v.y);
}
});
endShape();
pop();
}
show(mode = "triangle") {
push();
translate(this.position.x, this.position.y);
rotate(this.heading);
stroke(this.color);
fill(this.color);
if (mode == "point") circle(0, 0, 5);
else triangle(0, 0, -10, 2.5, -10, -2.5);
pop();
}
}