我制作了经典的随机移动圆圈,如图所示:
这就是我想要实现的:
当 mouseClicked 时,圆圈排列如下:
我想我可以检查所有圆圈的位置。如果他们的 y 位置在 1/2 高度内,他们应该形成弧。如果大于 1/2 高度,则它们形成线。
但诀窍是:如何形成那些形状?
我的意思是,我知道如何形成一个圆形,只需将它们的圆心移向一个点。但是LINE(如何移动他们的x位置)???甚至弧形???真的不知道。
有人知道吗?非常感谢你。
我制作了经典的随机移动圆圈,如图所示:
这就是我想要实现的:
当 mouseClicked 时,圆圈排列如下:
我想我可以检查所有圆圈的位置。如果他们的 y 位置在 1/2 高度内,他们应该形成弧。如果大于 1/2 高度,则它们形成线。
但诀窍是:如何形成那些形状?
我的意思是,我知道如何形成一个圆形,只需将它们的圆心移向一个点。但是LINE(如何移动他们的x位置)???甚至弧形???真的不知道。
有人知道吗?非常感谢你。
如果我理解正确,您正在尝试计算两点之间的中间位置。这些点可以在一条线上或一条弧线上。
在一条线上获得中间位置相当简单,并且有多种方法可以解决这个问题。想到的一个想法是使用lerp()函数(进行线性插值)。这是一个非常基本的示例:
//draw stuff
smooth();strokeWeight(5);
//line stuff
PVector start = new PVector(10,10);
PVector end = new PVector(90,90);
int numPts = 5;
float increment = 1.0/numPts;
for(int i = 0; i < numPts; i++){//for each point that should be on the line
float t = increment * i ; //'traversal' on the line (0.0 is at start 1.0 is at end)
point(lerp(start.x,end.x,t),//interpolate and draw
lerp(start.y,end.y,t));
}
在新草图中运行它以了解我的意思。这也可以手动完成,使用 PVector 类和插值公式:
point(percentage) = point(start) + ((point(end)-point(start)) * percentage)
因此:
//draw stuff
smooth();strokeWeight(5);
//line stuff
PVector start = new PVector(10,10);
PVector end = new PVector(90,90);
int numPts = 5;
float increment = 1.0/numPts;
for(int i = 0; i < numPts; i++){//for each point that should be on the line
float t = increment * i ; //'traversal' on the line (0.0 is at start 1.0 is at end)
PVector current = PVector.add(start,PVector.mult(PVector.sub(end,start),t));
point( current.x, current.y );
}
但lerp()
似乎更失败,并且可以轻松融入您现有的设置。
对于弧线,事情有点复杂,因为您需要一些三角学:将笛卡尔坐标转换为极坐标。这听起来有点复杂,但一旦你在脑海中想象事物,它并不难。想象一下你正在看一个时钟。
您可以通过查看两根针的位置(一个代表小时,一个代表分钟)来准确判断现在是什么时间。使用时钟位置或“坐标”,您可以轻松判断是中午/午夜。同样,您可以从“时钟坐标”转换回来,并说出中午/午夜的指针位置。
查看时钟,您还可以想象笛卡尔系统重叠:0,0 位于中心,笛卡尔坐标中的中午/午夜将是 (0,1),如果 1 将用于针长度的单位。对于 15:15,您将获得 (1,0),对于 18:30,您将获得 (0,-1),对于 20:45,您将获得 (-1,0),等等。您正在从一个 2D 坐标系(笛卡尔与x和y )到另一个(带有小时和分钟的“时钟” )
以非常相似的方式,您可以从笛卡尔(使用x和y)转换为极坐标(使用角度和半径)并返回。例如,12:00 表示 (0,1),但也可以表示为 ( 90 度,针长)。
现在回到圆弧:您可能知道起点和终点角度,并且您知道半径(距圆心的距离),因此您已经获得了极坐标。您只需转换为笛卡尔(x,y)坐标,可以使用以下公式完成:
x = cos(angle) * radius;
y = sin(angle) * radius;
此时值得注意的是,所有三角函数(sin/cos/tan/atan/etc.)都使用弧度。幸运的是,Processing 已经提供了一个弧度(),它可以简化弧度到弧度的转换。
这是一个基本草图来说明这个想法:
//draw stuff
smooth();strokeWeight(5);
//arc stuff
float distance = 35;//100 pixels away from the centre
float startAngle = radians(30);
float endAngle = radians(120);
int numPts = 10;
float increment = 1.0/numPts;
for(int i = 0; i < numPts; i++){//for each point on the arc
float intermediaryAngle = lerp(startAngle,endAngle,increment*i);
float x = cos(intermediaryAngle) * distance;
float y = sin(intermediaryAngle) * distance;
point(x+50,y+50);//50 is offset to draw from the centre of the sketch
}
我假设您应该能够检查对象的 y 坐标是否小于 height/2 并计算线定位的开始/结束位置或弧定位的开始角度/结束角度、半径/距离和偏移量
更新 如果您想从当前位置动画/插值到计算位置(无论是在线还是弧上),您需要处理它,因为上面的代码只处理计算目的地。这是我的意思的一个基本示例,基于您的一些代码:
int maxCircle = 10;
Circle[] circles = new Circle[maxCircle];
float increment = (1.0/maxCircle);
float traversal = 0.0;
void setup(){
size(400,400);
smooth();strokeWeight(5);
for(int i=0;i<maxCircle;i++){
circles[i] = new Circle(random(width),random(height),random(2,20));
}
}
void draw(){
background(255);
for(int i=0;i<maxCircle;i++){
if(!mousePressed) circles[i].update(width,height);//default
else{//if some event happens
//compute destination
float x,y;
float offx = width/2;
float offy = height/2;
//move to line
float startX = 0;
float endX = width;
float t = increment * i;
x = lerp(startX,endX,t);
y = offy-10;
//interpolate/move to computed position
if(traversal < 1.0){//if circle hasn't reached destination yet
traversal += 0.0001;//move closer to the destination
circles[i].x = lerp(circles[i].x,x,traversal);
circles[i].y = lerp(circles[i].y,y,traversal);
}
}
circles[i].display();
}
}
void mouseReleased(){
traversal = 0;
}
class Circle{
float x,y,vx,vy,r,speed;
Circle(float tempx, float tempy, float tempr){
x=tempx;
y=tempy;
vx=random(-1,1);
vy=random(-1,1);
r=tempr;
}
void update(int w,int h){
x+=vx;
y+=vy;
if(x<r || x>w-r){
vx*=-1;};
if(y<r || y>h-r){
vy*=-1;};
}
void display(){
fill(0,50);
noStroke();
ellipse(x,y,r,r);
}
}
按下鼠标时,圆圈将朝线条位置移动。另一种与上述类似的方法是使用 的速度Circle
:
这是一个代码示例:
int maxCircle = 10;
Circle[] circles = new Circle[maxCircle];
void setup() {
size(400, 400);
smooth();
strokeWeight(5);
for (int i=0;i<maxCircle;i++) {
circles[i] = new Circle(random(width), random(height), random(2, 20));
}
}
void draw() {
background(255);
for (int i=0;i<maxCircle;i++) {
if (!mousePressed) circles[i].update(width, height);//default
else {//if some event happens
//compute destination
float x = map(i,0,maxCircle,0,width);
float y = (height * .5) - 10;
//update to destination
circles[i].update(x,y,2);
}
circles[i].display();
}
}
class Circle {
float x, y, vx, vy, r, speed;
Circle(float tempx, float tempy, float tempr) {
x=tempx;
y=tempy;
vx=random(-1, 1);
vy=random(-1, 1);
r=tempr;
}
void update(int w, int h) {
x+=vx;
y+=vy;
if (x<r || x>w-r) {
vx*=-1;
};
if (y<r || y>h-r) {
vy*=-1;
};
}
void update(float x,float y,float speed){
//compute direction vector
float dx = x - this.x;
float dy = y - this.y;
//find the current 'speed': vector's length or magnitude
float len = sqrt(dx*dx + dy*dy);//PVector's mag() does this for you
//normalize the vector
dx /= len;
dy /= len;
//scale the vector
dx *= speed;
dy *= speed;
//interpolate/move to computed position
if(dist(this.x,this.y,x,y) > 2){//if circle hasn't reached destination yet (isn't close enough)
this.x += dx;
this.y += dy;
}
}
void display() {
fill(0, 50);
noStroke();
ellipse(x, y, r, r);
}
}
您可以运行以下命令:
var maxCircle = 10;
var circles = new Array(maxCircle);
function setup() {
createCanvas(400, 400);
smooth();
fill(0,50);
noStroke();
for (var i=0;i<maxCircle;i++) {
circles[i] = new Circle(random(width), random(height), random(2, 20));
}
}
function draw() {
background(255);
for (var i=0;i<maxCircle;i++) {
if (!isMousePressed) circles[i].updateBounds(width, height);//default
else {//if some event happens
//compute destination
var x = map(i,0,maxCircle,0,width);
var y = (height * .5) - 10;
//update to destination
circles[i].update(x,y,2);
}
circles[i].display();
}
}
function Circle(tempx, tempy, tempr){
this.x=tempx;
this.y=tempy;
this.vx=random(-1, 1);
this.vy=random(-1, 1);
this.r=tempr;
this.updateBounds = function(w,h) {
this.x+=this.vx;
this.y+=this.vy;
if(this.x < this.r || this.x>this.w-this.r) {
this.vx*=-1;
}
if (this.y<this.r || this.y>this.h-this.r) {
this.vy*=-1;
}
}
this.update = function(ax,ay,speed){
//compute direction vector
var dx = ax - this.x;
var dy = ay - this.y;
//find the current 'speed': vector's length or magnitude
var len = sqrt(dx*dx + dy*dy);//PVector's mag() does this for you
//normalize the vector
dx /= len;
dy /= len;
//scale the vector
dx *= speed;
dy *= speed;
//varerpolate/move to computed position
if(dist(this.x,this.y,ax,ay) > 2){//if circle hasn't reached destination yet (isn't close enough)
this.x += dx;
this.y += dy;
}
}
this.display = function() {
ellipse(this.x, this.y, this.r, this.r);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.4/p5.min.js"></script>
一些快速说明:
void update(float x,float y,float speed)
也可能是void seek(float x,float y,float speed)
or void moveTo(float x,float y,float speed)
。高温高压