水排序中的这个效果怎么实现?

白玉无冰

共 6167字,需浏览 13分钟

 · 2021-06-08

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 实现 "水排序之水杯效果!" 的技术分享。

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

keep hungry! keep foolish!

更多

转向行为AI  折纸效果 竖直布局的文本弹性跟随相机!  标志板!2D 素材 3D 效果!  2020 原创精选!

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


浏览 29
点赞
评论
收藏
分享

手机扫一扫分享

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

手机扫一扫分享

举报