我制作了经典的随机移动圆圈,如图所示:

这就是我想要实现的:
当 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)。高温高压