当然雪落地其实并不难,我们来点好玩的,如果地上有个障碍物怎么办,这个场景其实就像我们的 app
页面中底下有一排按钮,比较明显的是 floating button
, 我们想把雪下到他们头上,该怎么办呢?
1. 怎样的雪花会撞在障碍物上呢
这其实很简单,假设雪花都是球,啊不,都是圆的, 只要:
雪花中心到障碍物中心的距离 <= 障碍物半径,
就认为他撞墙了:
假设障碍物属性:
Offset circlePosition = Offset(screenSize.width/2, screenSize.height);
double circleRadius = 50;
那么我们搞个方法来判断:
bool _checkDangerous(SnowBasicInfo snow) {
// 我们通过snow的x,y距离底下障碍物的中心距离来判断snow会不会撞到障碍物
double xToBarrier = (circlePosition.dx - (snow.x)).abs();
double yToBarrier = (circlePosition.dy - (snow.y)).abs();
// 勾股定理求雪球中心到障碍物中心距离
double distance = pow((xToBarrier * xToBarrier + yToBarrier* yToBarrier), 0.5);
return distance < circleRadius;
}
通过上面方法来判断雪花是不是危险,但是如果你说雪花比障碍物大怎么办?那你说我怎么办~当然随便他怎么办,我反正不办。
2. 那撞墙了要怎么办呢
雪花撞墙后,我们假设和它落地一个下场,会变成一根条条,嗯,只是他是一段弧,而不是线段,那么问题来了,弧要怎么算出来呢
来,捡起你的数学课本看下面这个图吧:
图中蓝色部分其实就是我们想要的弧,小圆即为雪花,大圆是障碍物,小圆在障碍物左侧和右侧分开计算。
在左图中,我们只需要求 S 点的位置所对应的 角θ
,就可以知道圆弧的起始角度,弧度对应 2倍的角1,半径即障碍物半径。
- 小 r 为雪花半径,由之前定的雪花变化系数
snow.r
和雪花图宽共同决定:snow.r * snowImage.width.toDouble() / 2
- 大 R 为障碍物半径:
circleRadius
centerX, centerY
即为障碍物坐标x, y
. 即为当时雪花中心坐标:(snow.x, snow.y)
而右边的图就只要求角1就行,相对简单,
公式我都写图里了接下来只要变成代码就行了鸭:
和雪落地一样,我们给雪添加属性:
class SnowBasicInfo {
...
Rect touchRect;
// 起始角度
double startAngle;
// 滑过的角度
double swipeAngle;
//弧的粗细
double stroke;
// 是否撞墙
bool touchBarrier = false;
...
}
与之前的雪落地一样,我们希望随着时间变长,积雪厚度增加,然鹅我们只能用和之前一样的蠢方法,即通过一个增长系数:
var multip = pow((snows.where((element) => element.touchRect != null).length / 10 ), 0.5);
我们在雪融化前添加这段逻辑:
if(snow.r != 0 && (_checkDangerous(snow) || snow.touchBarrier)) {
snow.touchBarrier = true;
if(snow.touchRect == null) {
var multip = pow((snows.where((element) => element.touchRect != null).length / 10 ), 0.5);
var angleSnow = atan((snow.r * snowImage.width.toDouble() / 2) / circleRadius);
snow.touchRect = Rect.fromCircle(center: circlePosition, radius: circleRadius);
// 雪厚度就在这变化啦
snow.stroke = multip * snow.r * 10 ;
snow.startAngle = snow.x < circlePosition.dx ? pi + asin((circlePosition.dy - snow.y) / circleRadius) - angleSnow : 2* pi -(asin((circlePosition.dy - snow.y) / circleRadius));
snow.swipeAngle = snow.x < circlePosition.dx ? angleSnow * 2 * snow.r / 2: -angleSnow * 2 * snow.r / 2;
} else {
}
// canvas.drawArc 中的stroke用法和之前地上积雪一样哦
canvas.drawArc(snow.touchRect, snow.startAngle, snow.swipeAngle, false, snowBarrierPainter..strokeWidth = snow.stroke);
continue;
}
好了,其实这段就是把上面图里的草稿翻译出来而已,这样就能看到最顶上gif里的效果啦,是不是只要细心想,一切都会很简单?
3. 如果雪能从障碍上滑下来呢...
我们可以选择加一个特效,当雪落到障碍上时,障碍上的积雪会随着时间而慢慢贴着障碍物往地上滑,同时越来越薄
毕竟没怎么见过积雪,只能xjbyy...
其实效果并不好,所以在顶上也没这样做,效果很简单,只要在雪撞墙后,让雪的旋转初始角度往边上累加就行啦:
if(snow.touchRect == null) {
...
} else {
snow.startAngle = snow.x <= circlePosition.dx ? snow.startAngle - pi / 1000 : snow.startAngle + pi / 1000;
if(snow.startAngle < pi || snow.startAngle > 2 * pi) {
snow.invalid = true;
snow.melted = true;
continue;
}
snow.stroke = snow.stroke - 0.001;
}
至此,番外篇也结束了,如果你有更好玩的想法,快来一起摸鱼鸭~
摸更多鱼?
如果你对相关内容感兴趣呢,欢迎来一起摸鱼鸭: github.com/SpiciedCrab…