p5.js之有趣的时钟(码绘2)

一、开发环境:

 window10、火狐浏览器63.0.3、vs code1.28.2

二、应用框架:

p5.js

三、开发背景:

近期阅读《上帝掷骰子吗?》,对量子物理中的粒子深深着迷,并认识到现实世界中种种连续性事件在极微观角度中并不连续,称为普朗克现象,既然计算机是对现实世界的抽象,那么只要找到微观粒子的特征值即可还原微观下的粒子运动。基于此,趁着完成作业的机会,好好的研究一番粒子运动。在p5.js的框架下,事实证明,可以很好的展示粒子运动的效果。虽然仅仅只是一些简单的运动效果,还有很多需要完善的地方,但是此次仅仅作为一次研究粒子运动的尝试,会在之后慢慢完善。

四、内容综述:

主要实现了粒子的无规则运动、圆形粒子的墙壁碰撞检测、粒子的聚集、粒子的绕轴旋转等等粒子运动的效果以及创意时钟的实现过程。

五、实现过程(附代码、HTML与CSS代码省略):

①实现按照时间顺序,一步步“作画”

使用loop()函数noLoop()函数循环主体作画函数draw(),定义变量count记录循环次数,根据循环次数判断作画步骤;

function draw() {
    background(0);
    fill(228, 58, 41);
    count++;
    if (count < 200) {
        
    } else if (count < 300) {
                
    } else if (count < 500) {
        
    } else if (count < 1100) {

    } else {
        
    }
}

②随机生成“粒子”,并赋予粒子的特征值——位置、速度

宏观物理世界中的运动通常被视作连续的,抽象在二维平面直角坐标系已连续函数展现。以微观物理学的角度解读粒子,其运动可视为不连续,位置坐标值加上微分位移dx即可表现粒子的运动。

随机产生粒子的同时,随机赋予粒子速度。粒子以此速度运动,如果粒子运动到中心圆(圆心在屏幕中心,半径为100),则停止运动。粒子运动到边界发生碰撞,通过两个判断条件判断粒子是否碰撞到边界,若是,则改变微分位移。

function createParticle() {
    for (i = 0; i < 1000; i++) {
        //计算下一帧粒子的位置
        x[i] = x[i] + dx[i];
        y[i] = y[i] + dy[i];
        //画出粒子
        ellipse(x[i], y[i], 10, 10);
        //计算粒子距离中心圆的距离
        dist = Math.sqrt(Math.pow(x[i] - (width / 2), 2) + Math.pow((y[i] - height / 2), 2));
        //粒子在中心圆内,则停止运动
        if (dist < 100) {
            dx[i] = 0;
            dy[i] = 0;
        }
        //粒子与墙壁的碰撞过程
        if (x[i] > 1900 || x[i] < 0) {
            dx[i] = -dx[i];
        }
        if (y[i] > 900 || y[i] < 0) {
            dy[i] = -dy[i];
        }
    }
}

③聚集粒子,收束粒子到屏幕中心

三角函数的知识计算粒子的正确速度。

 for (i = 0; i < 1000; i++) {
            //计算粒子与屏幕中心的欧式距离
            dist = Math.sqrt(Math.pow(x[i] - (width / 2), 2) + Math.pow((y[i] - height / 2), 2));
            //计算粒子距屏幕中心横、纵距离
            var distX = x[i] - width / 2;
            var distY = y[i] - height / 2;
            //粒子速度方向为粒子与中心连线方向,根据三角函数计算
            dx[i] = -distY / dist;
            dy[i] = distX / dist;
            ellipse(x[i], y[i], 1, 1);
            x[i] += dx[i] * 20;
            y[i] += dy[i] * 20;
        }

④扩散粒子,由粒子组成时钟盘

代码与上述过程类似。注意,此时粒子的位置并不是屏幕中心,而是会无线接近屏幕中心,dx和dy无限小,表现在js中为一个极小但不为零的数字。所以,此时计算粒子距离屏幕中心横、纵距离是有意义的,并不为零。

for (i = 0; i < 1000; i++) {
            //计算粒子与屏幕中心的欧式距离
            dist = Math.sqrt(Math.pow(x[i] - (width / 2), 2) + Math.pow((y[i] - height / 2), 2));
            //计算粒子距屏幕中心横、纵距离
            var distX = x[i] - width / 2;
            var distY = y[i] - height / 2;
            //粒子x、y轴方向速度互换,并取其中一值为负,使粒子绕中心旋转,过程中旋转半径变大
            dx[i] = -distY / dist;
            dy[i] = distX / dist;
            ellipse(x[i], y[i], 1, 1);
            //乘以20使粒子运动速度更快
            x[i] += dx[i] * 20;
            y[i] += dy[i] * 20;
        }

⑤稳定粒子,以恒定半径旋转

代码同④,将后面两行代码中“*20”修改为“*0.2”。

⑥画时钟刻度

此次时钟刻度采用罗马数字,观察罗马数字字形,基础字符有三个——“X”、“V”和“I”。首先利用p5.js中quad()函数rect()函数画出基础字符,再通过函数调用基础字符,调整位置,画出罗马数字“I~XII”。

function drawI(positionX, positionY) {
    rect((width / 2) - 2 + positionX, (height / 2) - 14 + positionY, 4, 28);
    rect((width / 2) - 5 + positionX, (height / 2) - 18 + positionY, 10, 4);
    rect((width / 2) - 5 + positionX, (height / 2) + 14 + positionY, 10, 4);
}

function drawX(positionX, positionY) {
    quad((width / 2) - 11 + positionX, (height / 2) - 14 + positionY, (width / 2) - 5 + positionX, (height / 2) - 14 + positionY, (width / 2) + 5 + positionX, (height / 2) + 14 + positionY, (width / 2) + 11 + positionX, (height / 2) + 14 + positionY);
    quad((width / 2) + 5 + positionX, (height / 2) - 14 + positionY, (width / 2) + 11 + positionX, (height / 2) - 14 + positionY, (width / 2) - 10 + positionX, (height / 2) + 14 + positionY, (width / 2) - 4 + positionX, (height / 2) + 14 + positionY);
    rect((width / 2) - 13 + positionX, (height / 2) - 18 + positionY, 10, 4);
    rect((width / 2) - 13 + positionX, (height / 2) + 14 + positionY, 10, 4);
    rect((width / 2) + 3 + positionX, (height / 2) - 18 + positionY, 10, 4);
    rect((width / 2) + 3 + positionX, (height / 2) + 14 + positionY, 10, 4);
}
function drawV(positionX, positionY) {
    quad((width / 2) - 13 + positionX, (height / 2) - 16 + positionY, (width / 2) - 7 + positionX, (height / 2) - 16 + positionY, (width / 2) + positionX, (height / 2) + 12 + positionY, (width / 2) + positionX, (height / 2) + 18 + positionY);
    quad((width / 2) + 7 + positionX, (height / 2) - 16 + positionY, (width / 2) + 13 + positionX, (height / 2) - 16 + positionY, (width / 2) + positionX, (height / 2) + 18 + positionY, (width / 2) + positionX, (height / 2) + 12 + positionY);
    rect((width / 2) - 14 + positionX, (height / 2) - 18 + positionY, 8, 4);
    rect((width / 2) + 5 + positionX, (height / 2) - 18 + positionY, 8, 4);
}

⑦画秒针

秒针并不是指针形式,以大小圆的形式展现。

function drawSecond() {
    s = second();
    var secondX, secondY, scaleAngle;
    noFill();
    //以圆替代指针,落在数字上时,圆形变大
    if (s % 5 == 0) {
        secondX = scalePos.scaleX[(parseInt(s / 5) + 11) % 12];
        secondY = scalePos.scaleY[(parseInt(s / 5) + 11) % 12];
        ellipse(width / 2 + secondX, height / 2 + secondY, 60, 60);
    } else {
        scaleAngle = s * Math.PI / 30;
        secondX = (clockSize + 30) * Math.sin(scaleAngle);
        secondY = -(clockSize + 30) * Math.cos(scaleAngle);
        ellipse(width / 2 + secondX, height / 2 + secondY, 6, 6);
    }
}

⑧画时针、分针,并显示数字时间

时针和分针并不会有太大的变化,相对于秒针的变化,慢得多,基于这个逻辑,设计隐藏时针和分针。按住鼠标左键,将会显示时针分针和数字时间。通过mousePressed()函数mouseReleased()函数判断鼠标键的按下与抬起。

//bool变量mouseDown表示鼠标键按住
if (mouseDown) {
            drawHour();
            drawMinute();
            drawTextTime();
        }

至此,整个时钟的刻画已经结束。

六、结果/对比

结果:

码绘视频:https://v.qq.com/x/page/w0801lb8yp5.html

手绘截图:

对比:

①呈现效果:

码绘在表现“运动”这一主题上具有天然优势。一幅画始终是静态的,即使这幅画很灵动,很飘逸,看起来像动态,也始终是静态图像。利用计算机实现绘画则不同,计算机绘画可以看作画了不止一幅图像,将所有可能图像全部画出来,根据条件判断,将哪些图像播放出来,所以易于表现“运动”这一主题。映射到现实世界中,可以类比小人书定格动画等。

手绘图虽然无法绘出“动图”,但是手绘呈现的效果却是不同的,绝不能因为手绘无法绘出“动图”就认为在运动表现上码绘更有优势。手绘是另一种艺术形式,是触手可及的绘画,可以给人以情感性,相比“码绘”,更亲近人的情感。而以静态图像表现运动又是另一种感觉,似动非动,很奇妙的体验。(参考梵高的《星月夜》

②创作体验:

码绘在刻画规则图形时很快速,例如圆形、矩形、三角形等,在刻画不规则图形时很难,例如刻画狗的轮廓,需要复杂的数学函数精确地表达。在利用计算机进行创作时,大多数时候是在根据图像形态和大小寻找合适的函数,需要用到大量的数学知识和编程基础,创作过程就是计算过程,会有计算的“过程感”。

手绘创作工具是铅笔和画板,是可以触碰到的实物,有绘画的“过程感”,易于刻画不规则图像,例如刻画狗的轮廓。在掌握技法的基础上,心中所想即为所画。但是对于刻画规则且精细的图像,手绘就会有困难,例如,画出3cm的直线,这种精确规则图像是无法凭心中的感觉描述的,故而也无法精确表现精确值。

两种不同的创作体验都很棒,码绘是心中抽象→数学(据)抽象,手绘是心中抽象→直接描绘。

 

参考:

1.《用代码画画》:

0.1 用代码画画——搞艺术的学编程有啥用?

https://blog.csdn.net/magicbrushlv/article/details/77922119

1.1 开始第一幅“码绘”——以编程作画的基本方法

https://blog.csdn.net/magicbrushlv/article/details/77840565

 

2. 以编程的思想来理解绘画—— (一)用”一笔画“表现“过程美”

https://blog.csdn.net/magicbrushlv/article/details/82634189

 

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值