水也有排序规则,太牛了!(干货收藏)
Water Sort Puzzle!
效果
这次咱们来实现杯子倾斜中的水面效果。
效果预览:
视频预览:
实现
首先,简化模型,杯子当作长方形处理,仅考虑杯子旋转范围-90 ~ 90
度。
水面渲染可采用graphics
绘图组件处理(把原点移动至杯子左下角作为原点),再添加一层mask
图片遮罩,裁剪出杯子效果。
确认已知条件:
杯子的宽高。 杯子旋转角度。 水面初始高度(杯子未旋转时)。
需求出:
水面与水杯的交点位置。
先考虑杯子节点顺时针旋转(angle
为正)。
水面会出现两种情况,我们只需把握一个原则,水的体积(面积)不变。
梯形形状计算过程如下图所示:
三角形形状计算过程如下图所示:
计算一个临界角度,通过这个角度判断水的形状是属于哪一种。
对于杯子节点逆时针旋转(angle
为负),推算过程类似,参考以下计算过程。
private drawOneWater(height: number, color: Color) {
const radiansA = this.bottleAngle / 180 * Math.PI;
//计算临界角度
const radiansM = Math.atan(2 * height / this.bottleWidth);
const tempWTan = this.bottleWidth * Math.tan(radiansA);
this.drawGraphics.fillColor = color;
if (radiansA <= radiansM) {
if (radiansA < -radiansM) {
// 三角形 逆时针
let hL = Math.sqrt(2 * height * -tempWTan);
// 超出高度处理
hL = hL > this.bottleHeight ? this.bottleHeight : hL;
const bW = hL / Math.tan(-radiansA);
this.drawGraphics.moveTo(this.bottleWidth, 0);
this.drawGraphics.lineTo(this.bottleWidth, hL);
this.drawGraphics.lineTo(this.bottleWidth - bW, 0);
this.drawGraphics.lineTo(this.bottleWidth, 0);
} else {
// 梯形,包含顺逆时针
this.drawGraphics.moveTo(0, 0);
let hL = height + tempWTan / 2;
// 超出高度处理
let cutOffset = 0;
if (hL > this.bottleHeight) {
cutOffset += hL - this.bottleHeight
}
let hR = height - tempWTan / 2;
if (hR > this.bottleHeight) {
cutOffset += hR - this.bottleHeight
}
this.drawGraphics.lineTo(this.bottleWidth, 0);
this.drawGraphics.lineTo(this.bottleWidth, hR - cutOffset);
this.drawGraphics.lineTo(0, hL - cutOffset);
this.drawGraphics.lineTo(0, 0);
}
} else {
// 三角形 顺时针
let hL = Math.sqrt(2 * height * tempWTan);
// 超出高度处理
hL = hL > this.bottleHeight ? this.bottleHeight : hL;
const bW = hL / Math.tan(radiansA);
this.drawGraphics.moveTo(0, 0);
this.drawGraphics.lineTo(bW, 0);
this.drawGraphics.lineTo(0, hL);
this.drawGraphics.lineTo(0, 0);
}
this.drawGraphics.fill();
}
对于多层水,按照从高到低的顺序画图,低处的水覆盖高层。如下图所示,按照0,1,2
的顺序画对应的水层。
private drawWater() {
if (!this.drawGraphics) return
this.drawGraphics.clear();
// 水的高度从高到低画
for (let index = 0; index < this.waterHeights.length; index++) {
const height = this.waterHeights[index];
this.drawOneWater(height, this.waterClolors[index] || Color.WHITE);
}
}
对于每一层什么时候倒完,正好是水的下一层到达瓶口时,大家可以算出对应的角度,这里就留给大家继续实现这个功能吧!
小结
抓住不变量,临界值实现对应效果!
以上为白玉无冰使用 Cocos Creator 3.1.0
实现 "水排序之水杯效果!"
的技术分享。
如果你也办法实现这个效果,一起留言讨论吧!
“点赞“ ”在看” 鼓励一下▼
评论