p5.js动态GIF临摹:棍状体与螺旋体的匀速圆周运动实现

作者:异步漫步

时间:2026-10-23

浏览:629

本文基于互动媒体技术实验,使用p5.js库对动态GIF图像进行临摹重现。文章详细解析了棍状体与螺旋体两个核心部分的运动规律,重点阐述如何利用三角函数实现匀速圆周运动,并提供了完整的p5.js代码实现。此外,还总结了p5.js在函数参数声明与变量类型使用上的特性,并展示了一个结合鼠标交互的时钟扩展作品。

文章目录

前言与实验背景

前言

根据互动媒体技术课程实验要求,本文对一张GIF动态图进行了临摹,并采用p5.js库完成了图像的重现。文中将详细阐述实现逻辑与相关代码,并在末尾展示一个基于此原理的扩展作品。

原图

前言与实验背景

原图分析与运动规律

实现步骤

规律总结

通过观察原图,可以发现图像主要由两部分构成:棍状体和螺旋状体。

棍状体呈现从外到内逐渐变窄的特征,整体图形围绕固定的旋转圆心进行匀速圆周运动。

螺旋状体同样围绕该固定旋转圆心进行匀速圆周运动。

螺旋状体的旋转角速度大于棍状体的旋转角速度。

p5.js实现逻辑与代码

具体实现逻辑

为了便于分析,这里截取一个静态瞬间进行观察:

前言与实验背景

接下来探讨具体的实现方法。

我们可以分别编写两个函数来绘制棍状体和螺旋体,然后在draw()函数中调用这两个函数即可完成整体效果。

以下是棍状体的实现函数:


//圆周运动棍状体绘制函数
function drawBoll(r, g, b, interval)

以下是螺旋体的实现函数:


//圆周运动螺旋体的绘制函数
function drawBoll2( r, g, b, interval)

下面分两部分详细说明实现过程:

首先是棍状体部分。观察静止状态下的棍状体,它由14个小圆形组成,从外到内半径逐渐减小,颜色依次为红、橙、黄、绿、青、蓝、紫。每个小圆形都绕固定圆心做匀速圆周运动。实现思路是:先绘制一个做匀速圆周运动的小圆,其他小圆只需调整旋转半径、自身半径及颜色即可。关于匀速圆周运动的具体实现,将在后文详述。

其次是螺旋体部分。螺旋体同样由圆形重复变换生成,各圆形大小一致,区别在于颜色、旋转半径以及初始存在的弧度间隔。实现方法是:先绘制一个做匀速圆周运动的圆形,通过修改相关参数来生成其他部分。

最后一步是在draw()函数中通过for循环调用上述函数来实现整体动画。


for (var i =1;i < 15; i++) // for循环实现变化的重复
 {
  //其中前三个参数是颜色的RGB值,最后一个参数i实现各个圆形之间的变化
  drawBoll(139, 0, 255, i); 
  drawBoll2(139, 0, 255, i); 
  i++;
  drawBoll(0, 0, 255, i); 
  drawBoll2(0, 0, 255, i); 
  i++;
  drawBoll(0, 255, 255, i); 
  drawBoll2(0, 255, 255, i); 
  i++;
  drawBoll(0, 255, 0, i); 
  drawBoll2(0, 255, 0, i);
  i++;
  drawBoll(255, 255, 0, i); 
  drawBoll2(255, 255, 0, i); 
  i++;
  drawBoll(255, 165, 0, i); 
  drawBoll2(255, 165, 0, i); 
  i++;
  drawBoll(255, 0, 0, i); 
  drawBoll2(255, 0, 0, i); 
 }

代码实现

以下是该程序完整的p5.js代码:


//准备画板
function setup() {
 createCanvas(1000, 1000);
}

//开始作画
function draw() {
 background(50); //背景颜色
 for (var i =1;i < 15; i++) // for循环实现变化的重复
 {
  //其中前三个参数是颜色的RGB值,最后一个参数i实现各个圆形之间的变化
  drawBoll(139, 0, 255, i); 
  drawBoll2(139, 0, 255, i); 
  i++;
  drawBoll(0, 0, 255, i); 
  drawBoll2(0, 0, 255, i); 
  i++;
  drawBoll(0, 255, 255, i); 
  drawBoll2(0, 255, 255, i); 
  i++;
  drawBoll(0, 255, 0, i); 
  drawBoll2(0, 255, 0, i);
  i++;
  drawBoll(255, 255, 0, i); 
  drawBoll2(255, 255, 0, i); 
  i++;
  drawBoll(255, 165, 0, i); 
  drawBoll2(255, 165, 0, i); 
  i++;
  drawBoll(255, 0, 0, i); 
  drawBoll2(255, 0, 0, i); 
 }
}

//圆周运动棍状体绘制函数
function drawBoll(r, g, b, interval){
 fill(r, g, b);
 var x = 500; //圆周运动圆心的x坐标
 var y = 500; //圆周运动圆心的y坐标
 var t = millis() / 3; // 控制旋转速度的参数
 var xChange //圆周运动x坐标变化值
 var yChange; //圆周运动y坐标变化值
 var radius = interval * 15;//圆周运动的半径
 xChange = radius * Math.cos(t * Math.PI/180);
 yChange = radius * Math.sin(t * Math.PI/180); 
 x += xChange;
 y += yChange;
 ellipse(x, y, interval * 5, interval * 5);
}

//圆周运动螺旋体的绘制函数
function drawBoll2( r, g, b, interval){
 fill(r, g, b);
 var x = 500; //圆周运动圆心的x坐标
 var y = 500; //圆周运动圆心的y坐标
 var t = millis() / 1 + interval * 24; //24是两个小球之间间隔的角度
 var xChange //圆周运动x坐标变化值
 var yChange; //圆周运动y坐标变化值
 var radius = interval * 15;//圆周运动的半径
 xChange = radius * Math.cos(t * Math.PI/180);
 yChange = radius * Math.sin(t * Math.PI/180); 
 x += xChange;
 y += yChange;
 ellipse(x, y, 30, 30);
}

常见问题与p5.js特性

遇到的问题以及解决方案

1、如何实现匀速圆周运动?

承接上文,具体如何计算并实现匀速圆周运动?

实现匀速圆周运动需遵循以下步骤:首先确定旋转半径、旋转圆心坐标及旋转角速度;其次,利用三角函数计算运动点坐标与圆心坐标的差值;最后,将圆心坐标加上该差值得到圆周上各点的坐标,并以这些坐标为圆心绘制小圆,从而构成所需的图形。

匀速圆周运动的具体代码实现如下:


var x = 500; //圆周运动圆心的x坐标
 var y = 500; //圆周运动圆心的y坐标
 var t = millis() / 3; // 控制旋转速度的参数
 var xChange //圆周运动x坐标变化值
 var yChange; //圆周运动y坐标变化值
 var radius = interval * 15;//圆周运动的半径
 xChange = radius * Math.cos(t * Math.PI/180);
 yChange = radius * Math.sin(t * Math.PI/180); 
 x += xChange;
 y += yChange;
 ellipse(x, y, interval * 5, interval * 5);

2、p5.js与其他编程语言的区别

在p5.js中定义函数时,形参无需声明类型,例如:


function drawBoll(r, g, b, interval)

上述为正确写法,以下为错误写法:


function drawBoll(var r, var g, var b, var interval)

即在形参中不能使用var进行声明,否则会导致报错。

此外,在p5.js中声明变量使用var即可,无需使用int、char、string等类型声明。

结果图

前言与实验背景

扩展作品:鼠标交互时钟

扩展作品

前言与实验背景

扩展作品介绍

这是一个时钟扩展作品,增加了鼠标交互功能。

中间的时针、分针和秒针实现方式与前述GIF中的棍状体相同,仅调整了角速度和圆形大小参数,此处不再赘述。

重点介绍简单的鼠标交互事件。

交互效果由两部分组成:外围律动的粉色圆形和中间的爱心。

外围部分通过ellipse函数实现,圆心坐标跟随当前鼠标位置,宽高动态变化。设置一个变量size,使其不断增大,达到临界值后减小,再重新增大,代码如下:


size = size + 3;
if (size > 50)
  size = 20;
 ellipse(mouseX, mouseY, 20+size, 20+size);

中间部分由三个半圆组成:上方两个小半圆和下方一个大半圆,律动效果与外围部分一致。代码如下:


size = size + 3;
if (size > 50)
  size = 20;
 fill(255,0,0);//红色
 arc(mouseX+size/4, mouseY, size/2, size/2, PI, 0);//半圆
 arc(mouseX-size/4, mouseY, size/2, size/2, PI, 0);//半圆
 arc(mouseX, mouseY, size, size, 0*PI, 1*PI);//半圆

具体代码实现


//准备画板
function setup() {
 createCanvas(1000, 1000);
}

//开始作画
function draw() {
 background(50); //背景颜色
 for (var i =1;i < 15; i++) // for循环实现变化的重复
 {
  //其中前三个参数是颜色的RGB值,最后一个参数i实现各个圆形之间的变化
  drawBoll(139, 0, 255, i); 
  drawBoll2(139, 0, 255, i); 
  drawBoll3(139, 0, 255, i); 
  i++;
  drawBoll(0, 0, 255, i); 
  drawBoll2(0, 0, 255, i); 
  drawBoll3(0, 0, 255, i); 
  i++;
  drawBoll(0, 255, 255, i); 
  drawBoll2(0, 255, 255, i); 
  drawBoll3(0, 255, 255, i); 
  i++;
  drawBoll(0, 255, 0, i); 
  drawBoll2(0, 255, 0, i);
  drawBoll3(0, 255, 0, i);
  i++;
  drawBoll(255, 255, 0, i); 
  drawBoll2(255, 255, 0, i); 
  drawBoll3(255, 255, 0, i); 
  i++;
  drawBoll(255, 165, 0, i); 
  drawBoll2(255, 165, 0, i); 
  drawBoll3(255, 165, 0, i); 
  i++;
  drawBoll(255, 0, 0, i); 
  drawBoll2(255, 0, 0, i); 
  drawBoll3(255, 0, 0, i); 
 }
 mouse(255, 192, 203);
}

//时针绘制函数
function drawBoll(r, g, b, interval){
 fill(r, g, b);
 var x = 500; //圆周运动圆心的x坐标
 var y = 500; //圆周运动圆心的y坐标
 var t = 6 * millis() / 3600000; // 控制旋转速度的参数
 var xChange //圆周运动x坐标变化值
 var yChange; //圆周运动y坐标变化值
 var radius = interval * 15;//圆周运动的半径
 xChange = radius * Math.cos(t * Math.PI/180 - Math.PI / 2);
 yChange = radius * Math.sin(t * Math.PI/180 - Math.PI / 2); 
 x += xChange;
 y += yChange;
 ellipse(x, y, 30, 30);
}

//分针绘制函数
function drawBoll2( r, g, b, interval){
 fill(r, g, b);
 var x = 500; //圆周运动圆心的x坐标
 var y = 500; //圆周运动圆心的y坐标
 var t = 6 * millis() / 60000; // 控制旋转速度的参数
 var xChange //圆周运动x坐标变化值
 var yChange; //圆周运动y坐标变化值
 var radius = interval * 15;//圆周运动的半径
 xChange = radius * Math.cos(t * Math.PI/180 - Math.PI / 2);
 yChange = radius * Math.sin(t * Math.PI/180 - Math.PI / 2); 
 x += xChange;
 y += yChange;
 ellipse(x, y, 20, 20);
}

//秒针绘制函数
function drawBoll3( r, g, b, interval){
 fill(r, g, b);
 var x = 500; //圆周运动圆心的x坐标
 var y = 500; //圆周运动圆心的y坐标
 var t = 6 * millis() / 1000; // 控制旋转速度的参数
 var xChange //圆周运动x坐标变化值
 var yChange; //圆周运动y坐标变化值
 var radius = interval * 15;//圆周运动的半径
 xChange = radius * Math.cos(t * Math.PI/180 - Math.PI / 2);
 yChange = radius * Math.sin(t * Math.PI/180 - Math.PI / 2); 
 x += xChange;
 y += yChange;
 ellipse(x, y, 10, 10);
}

var size = 0;
// 实现鼠标交互的函数(律动的爱心)
function mouse(r, g, b){
 fill(r, g, b);
 size = size + 3;
 if (size > 50)
  size = 20;
 ellipse(mouseX, mouseY, 20+size, 20+size);
 fill(255,0,0);//红色
 arc(mouseX+size/4, mouseY, size/2, size/2, PI, 0);//半圆
 arc(mouseX-size/4, mouseY, size/2, size/2, PI, 0);//半圆
 arc(mouseX, mouseY, size, size, 0*PI, 1*PI);//半圆
}

以上为本次实验的全部内容。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章