#过年不停更#HarmonyOS自定义JS组件—灵动的锦鲤 原创 精华
作者:包月东
简介
今天给大家带来如何用纯JS代码的Canvas绘制一条游动的锦鲤
先看下效果图
实现思路
拆分
先看设计图,我们的小鱼由头、鳍、身体、节肢、尾部五部分组成。
下面给出每个部位的实现api
-
头是一个实心圆,可以通过canvas.arc()
-
鱼鳍则由一条直线和曲线构成,会用到path,曲线可以使用贝塞尔曲线canvas.quadraticCurveTo()。
-
身体由两条直线和曲线构成,曲线也选用贝塞尔曲线,通过控制点可以控制小鱼胖瘦
-
节肢1由两个实心圆和一个梯形构成。梯形可以看出四条封闭的线段构成。
-
节肢2由一个梯形和一个圆,方案同上
-
尾由两个三角形,也是封闭线段
参数
基准尺寸参数
首先我们定一个基准尺寸参数来控制小鱼的大小,这里我们选取鱼头的半径R
其他参数如下:
小鱼的整体尺寸如下:
值得注意的是,画布的长度并不等于小鱼的长度,因为小鱼的重心并不位于鱼长中心,而是小鱼身的中心点,但是小鱼的转身却要围绕它,因此我们画布的半径需要拓展成小鱼身中心到小鱼尾的长度,整个画布的大小=4.19R*4.19R,如下
基准旋转参数
为了使我们的小鱼能够左右掉头,这里就需要一个旋转角度,我们选取fishMainAngle作为主角度。
实现步骤
自定义一个Canvas的组件
持有绘图相关的上下文
这里我们延迟200ms,在js中获取hml定义的fishcanvas组件,再拿到context并持有。接着执行onDraw进行绘制
定义绘制方法
下面分步骤说明
清除画布
每次绘制前我们都需要将画布擦除,不然会污染后续绘制
绘制小鱼头
绘制小鱼头,需要小鱼头中心坐标,小鱼头半径。小鱼头中心坐标可由重心坐标middlePoint、距离、当前角度推算出来。
注意画布坐标轴是原则在左上角,x轴向右,y轴向下
绘制小鱼眼,小鱼眼由两个椭圆实现,使用canvas.ellipse()绘制
绘制小鱼鳍
利用startPoint,controlPoint,endPoint绘制贝塞尔的封闭path
绘制节肢
节肢由圆、梯形构成,先绘制圆再讲梯形绘制上
绘制小鱼尾大小三角形
绘制小鱼身
首先得到小鱼身的四个顶点,在得到左右两边的两个控制点,根据这六个点绘制一个封闭的path
小鱼的摆动
摆动
我们通过不断改变小鱼的旋转角度fishAngle来模拟小鱼的摆动,这里可以使用定时器,更为方便的可以使用Animator
这里startAnimation方法中我们创建了一个Animator,并指定option,option中的参数说明如下
创建完动画我们通过指定onframe回调,currentValue是动画变化因子,currentValue影响小鱼角度。改完currentValue,我们调用onDraw()进行重绘制
效果如下:
⚠️这里虽然实现了小鱼的摆动,但是感觉怪怪的。日常小鱼摆动时,小鱼尾,节肢的幅度和频率要高于小鱼身体,这样才能不能显得呆板。幅度我们在小鱼尾和节肢那里增加一个currentValue相关乘积来扩大振幅。
那如何实现动画更新时,小鱼各部位的频率不同呢,这里就涉及小鱼的变频
变频
方案一:对于不同频率的部位分别创建一个Animator,每个Animator分别管理相同部位的频率并绘制。交互比较复杂
方案二:使用正弦函数的周期性。sin(nx)的频率是sin(x)的n倍,如果小鱼的角度公式与sin(nx)相关,那么我们对不同部位设置不同的n值来实现频率不一致,比如头的角度=sin(2x),尾的角度=sin(3x),那么尾的频率就是头的1.5倍。
如上fishAngle的频率扩大了1.2倍,节肢的频率扩大了1.5倍。sin,cos的角度变化范围,也就是currentValue的end-begin,必须是360度的整数倍,这样才能保证sin,cos的周期性。
我们这里设置begin=0,如下求currentValue的end值
下面是变频的option
调用
总结
通过本项目的演练,我们对自定义Canvas,JS动画,三角函数等有了更深的认识
这里只是实现了小鱼摆动和变频,后续有时间会接着增加点击屏幕实现小鱼的游动、游动时的转向、转向变频
源码地址
更多原创内容请关注:深开鸿技术团队
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
这锦鲤也太生动了,赶快转发该文章!
6666
不错的创意,很详细的介绍,我也试试
好厉害啊,这个是不是可以参加比赛?作者太厉害了
厉害了哥
真 666
吾愿称之为本周最强!
6b 666