1

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

在此处输入图像描述

这就是我想要实现的:

当 mouseClicked 时,圆圈排列如下: 在此处输入图像描述

我想我可以检查所有圆圈的位置。如果他们的 y 位置在 1/2 高度内,他们应该形成弧。如果大于 1/2 高度,则它们形成线。

但诀窍是:如何形成那些形状?

我的意思是,我知道如何形成一个圆形,只需将它们的圆心移向一个点。但是LINE(如何移动他们的x位置)???甚至弧形???真的不知道。

有人知道吗?非常感谢你。

4

1 回答 1

1

如果我理解正确,您正在尝试计算两点之间的中间位置。这些点可以在一条线上或一条弧线上。

在一条线上获得中间位置相当简单,并且有多种方法可以解决这个问题。想到的一个想法是使用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 坐标系(笛卡尔与xy )到另一个(带有小时分钟的“时钟” )

以非常相似的方式,您可以从笛卡尔(使用xy)转换为极坐标(使用角度半径)并返回。例如,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

  1. 计算方向向量(通过从当前位置向量中减去目标向量)
  2. 找到当前速度(或速度矢量的大小)
  3. 根据方向矢量及其速度缩放速度矢量。(如果您愿意,这将允许突然停止或减速)

这是一个代码示例:

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>

草图预览

一些快速说明:

  1. 请注意,我已经定义了另一种更新方法,我在其中进行矢量数学运算。在 Processing/Java 中,您可以拥有一个名称相同但参数不同的方法/函数,这有时会派上用场。在这种情况下,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)
  2. 矢量术语起初可能看起来很复杂,但一旦你进入它就会很有意义。此外,它在计算机图形学中非常有用(在处理或您决定将来使用的任何其他语言中)。我热烈推荐Daniel Shiffman 的 Nature of Code关于该主题的 Vector 章节。它通过易于理解的示例进行了很好的解释。Processing 有方便的PVector类供您使用。
  3. 将来,一旦您对向量感到满意,并且如果您想探索更高级的运动算法,请随时探索自主转向行为/Boids。(虽然这是一个高级主题,但很有趣/有趣)。

高温高压

于 2012-09-10T07:17:20.820 回答