您实现这一目标的方法是将这个项目拆分为任务:
- 加载和解析数据
- 更新时间和渲染数据
为了确保第 1 部分顺利进行,最好先确保您的数据易于解析。示例数据看起来像一个表格/电子表格,但它没有使用标准分隔符(例如逗号或制表符)格式化。您可以在解析时摆弄一些东西,但我建议首先使用干净的数据,例如,如果您打算space
用作分隔符:
TIME X Y
0.1333 0.0 0
0.2666 0.1 0.0999983333
0.3999 0.2 0.1999866669
0.5332 0.3 0.299955002
0.6665 0.4 0.3998933419
0.7998 0.5 0.4997916927
0.9331 0.6 0.5996400648
1.0664 0.7 0.6994284734
完成后,您可以使用loadStrings()加载数据并使用split()将一行分成 3 个元素,这些元素可以从字符串转换为浮点数。
一旦你有了使用价值,你就可以存储它们。您可以创建三个数组,每个数组保存一个来自加载数据的字段(一个用于所有 X 值,一个用于所有 Y 值,一个用于所有时间值),或者您可以作弊并使用单个PVector对象数组。虽然 PVector 用于 3D 数学/线性代数,但您有 2D 坐标,因此您可以将时间存储为第 3 个“维度”/分量。
第二部分主要围绕基于时间的更新展开,这就是millis()派上用场的地方。您可以检查更新之间经过的时间量,如果它大于某个(延迟)值,则该进行另一次更新(帧/数据行索引)。
您需要担心的最后一部分是在屏幕上呈现数据。幸运的是,在您的示例数据中,坐标已标准化(介于 0.0 和 1.0 之间),这使得映射到草图尺寸变得容易(通过使用简单的乘法)。否则map()函数会派上用场。
这是说明上述内容的草图,data.csv 是一个文本文件,其中包含上面的格式化示例数据:
PVector[] frames;//keep track of the frame data(position(x,y) and time(store in PVector's z property))
int currentFrame = 0,totalFrames;//keep track of the current frame and total frames from the csv
int now, delay = 1000;//keep track of time and a delay to update frames
void setup(){
//handle data
String[] rows = loadStrings("data.csv");//load data
totalFrames = rows.length-1;//get total number of lines (-1 = sans the header)
frames = new PVector[totalFrames];//initialize/allocate frame data array
for(int i = 1 ; i <= totalFrames; i++){//start parsing data(from 1, skip header)
String[] frame = rows[i].split(" ");//chop each row into 3 strings(time,x,y)
frames[i-1] = new PVector(float(frame[1]),float(frame[2]),float(frame[0]));//parse each row(not i-1 to get back to 0 index) and how the PVector's initialized 1,2,0 (x,y,time)
}
now = millis();//initialize this to keep track of time
//render setup, up to you
size(400,400);smooth();fill(0);strokeWeight(15);
}
void draw(){
//update
if(millis() - now >= delay){//if the amount of time between the current millis() and the last time we updated is greater than the delay (i.e. every 'delay' ms)
currentFrame++;//update the frame index
if(currentFrame >= totalFrames) currentFrame = 0;//reset to 0 if we reached the end
now = millis();//finally update our timer/stop-watch variable
}
PVector frame = frames[currentFrame];//get the data for the current frame
//render
background(255);
point(frame.x * width,frame.y * height);//draw
text("frame index: " + currentFrame + " data: " + frame,mouseX,mouseY);
}
还需要一些额外的注意事项:
- 您提到在 1 秒后移动到下一个坐标。从我在您的示例数据中可以看到,每秒有 8 次更新,因此 1000/8 可能会更好。不过,这取决于您如何处理时间。
- 我假设你的全套包括正弦波运动的数据。我已经映射到完整坐标,但是在
draw()
循环的渲染部分,您可以随意映射(例如,包括高度/2 偏移等)。此外,如果您不熟悉正弦波,请查看以下处理资源:Daniel Shiffman 的 SineWave 示例、Ira Greenberg 的三角教程。