游戏开发第13课-cocoscreator 实现倒水

首先,简化模型,杯子当作长方形处理,仅考虑杯子旋转范围-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);
    }
}
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值