水也有排序规则,太牛了!(干货收藏)

共 6145字,需浏览 13分钟

 ·

2021-06-24 22:42

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(00);
            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(00);
        }
    } else {
        // 三角形 顺时针
        let hL = Math.sqrt(2 * height * tempWTan);
        // 超出高度处理
        hL = hL > this.bottleHeight ? this.bottleHeight : hL;
        const bW = hL / Math.tan(radiansA);
        this.drawGraphics.moveTo(00);
        this.drawGraphics.lineTo(bW, 0);
        this.drawGraphics.lineTo(0, hL);
        this.drawGraphics.lineTo(00);
    }
    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 实现 "水排序之水杯效果!" 的技术分享。

如果你也办法实现这个效果,一起留言讨论吧!

“点赞“ ”在看” 鼓励一下





浏览 189
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报