微信小游戏 彩色试管 倒水游戏 逻辑

 最近开始研究微信小游戏,有兴趣的 可以关注一下 公众号, 记录一些心路历程和源代码。

定义一个 Cup类:
主要功能
  1. 初始化水杯:根据传入的颜色信息初始化水杯中的水层。
  2. 倒水:模拟水杯倾斜并倒出水的过程。
  3. 加水:模拟向水杯中加水的过程。
  4. 颜色管理:管理水杯中不同颜色的水层。
  5. 交互:处理水杯的点击事件,触发倒水或加水的操作。
    import { Component, _decorator,Node, UITransform, Color, Tween, Vec2, tween, v3, v2, Vec3, Widget, Layers } from "cc";
    import { AudioEnum, AudioUtil } from "../utils/audio_util";
    import Water, { WaterInfo } from "./water";
    import { WaterFlow } from "./waterFlow";
    import { EDITOR } from "cc/env";
    
    const { ccclass, property } = _decorator;
    
    export let WaterColors = [
        "#155DEF",
        "#F2C90F",
        "#004616",
        "#E4584F",
        "#00B38A",
        "#DD2E44",
        "#E5C69A",
        "#65DC8E",
        "#B068F0",
        "#F010BF",
        "#538849",
    ]
    
    //*高度乘数因子,满杯水只显示80% */
    const HEIGHT_FACTOR = 0.8;
    
    //一杯水,分成四组四个颜色,0表示没有水 */
    export interface _CupInfo{
        colorIds:Array<number>;//长度为4
    }
    
    const SPLIT_COUNT = 4;
    
    @ccclass
    export default class Cup extends Component {
        @property(Water)
        private water:Water = null;
    
        private _flow:WaterFlow = null;
        public getFlow():WaterFlow{
            if(this._flow){
                return this._flow;
            }
            let _node = new Node("water_flow");
            _node.layer = Layers.Enum.UI_2D
            _node.addComponent(UITransform)
            this._flow = _node.addComponent(WaterFlow);
            return this._flow;
        }
    
        private onClick:(c:Cup)=>void = null;
    
        onBtn_click(){
            if(this.isPouring()){
                return;
            }
            if(this.onClick){
                this.onClick(this);
            }
        }
    
        public isPouring(){
            return Math.abs(this.node.angle)>1.0;
        }
    
        //每个试管 初始化 4层颜色
        initWater(){
            const info = this.info;
            let arr = [];
            
            for(let i=SPLIT_COUNT-1;i>=0;i--){
                let colorId = info.colorIds[i];
                if(colorId==0){
                    continue;
                }
                let lastObj = arr[arr.length-1];
                if(!lastObj||lastObj!=colorId){
                    arr.push({
                        height:1/SPLIT_COUNT,
                        colorId:colorId
                    });
                }else{
                    lastObj.height += 1/SPLIT_COUNT;
                }
            }
            arr.forEach(function (obj) {
                let hex = WaterColors[obj.colorId]||"#538849"
                // log("obj.colorId",obj.colorId,"color",hex)
                obj.color = new Color().fromHEX(hex);
                obj.height*=HEIGHT_FACTOR;
            })
            
            this.water.initInfos(arr);
        }
    
        private info:_CupInfo = null;
        setCupInfo(info:_CupInfo,onClick:(c:Cup)=>void){
            this.info = info;
            this.onClick = onClick;
            
            this.initWater();
            
            this.reset();
        }
    
        update(){
            if(EDITOR){
                return;
            }
            if(this.water.skewAngle==this.node.angle){
                return;
            }
            this.water.skewAngle = this.node.angle;
        }
    
        private setPourOutCallback(pourStart,pourEnd){
            //水开始从瓶口流出来
            const _onStart = function(){
                if(pourStart){
                    pourStart(this)
                }
                
            }
            //水倒完了
            const _onFinish = function(){
                if(this.tween){
                    this.tween.stop();
                    this.tween = null;
                }
                if(pourEnd){
                    pourEnd(this)
                }
            }
            this.water.setPourOutCallback(_onStart.bind(this),_onFinish.bind(this));
        }
    
        private setPourInCallback(onFinish){
            //水倒完了
            const _onFinish = function(){
                let isFinished = this.checkIsFinshed();
                // log("-----------isFinished",isFinished)
                if(onFinish){
                    onFinish(this,isFinished)
                }
                if(isFinished){
                    AudioUtil.playEffect(AudioEnum.finishOne,0.4)
                }
            }
            this.water.setPourInCallback(_onFinish.bind(this));
        }
    
        /**是否完成了(同颜色填满整个杯子) */
        checkIsFinshed(){
            let isFinished = true;
            let colorIds = this.info.colorIds;
            let tmpId = null;
            let empTyNum = 0;
            for(let i=0;i<SPLIT_COUNT;i++){
                if(tmpId==null){
                    tmpId = colorIds[i]
                }
                if(tmpId!=colorIds[i]){
                    isFinished = false;
                    break;
                }else if(colorIds[i]==0){
                    empTyNum++;
                }
            }
            if(empTyNum==SPLIT_COUNT){
                isFinished = true;
            }
            return isFinished;
        }
    
        private tween:Tween<Node> = null;
    
        moveToPour(dstPt:Vec3,isRight:boolean,onPourStart:(c:Cup)=>void,onPourEnd:(c:Cup)=>void){
            this.setPourOutCallback(onPourStart,onPourEnd);
    
            let startAngle = this.water.getPourStartAngle()
            let endAngle = this.water.getPourEndAngle()
    
            this.water.onStartPour();
            if(isRight){
                startAngle*=-1;
                endAngle*=-1;
            }
    
            let moveDur = 0.5;
            let pourDur = 0.8;
    
            this.tween = tween(this.node)
                .set({angle:0})
                .to(moveDur,{position:v3(dstPt.x,dstPt.y),angle:startAngle})
                .to(pourDur,{angle:endAngle})
                .call(()=>{
                    this.tween = null;
                }).start();
    
            let top = this.getTop();
            let colorIds = this.info.colorIds;
            for(let i=0;i<SPLIT_COUNT;i++){
                let _id = colorIds[i]
                if(_id==0){
                    continue;
                }else if(top.topColorId==_id){//顶部相同颜色的水都倒掉了
                    colorIds[i] = 0;
                }else{
                    break;
                }
            }
        }
    
        startAddWater(colorId:number,num:number,onComplete:(cup:Cup,isFInish:boolean)=>void){
            this.setPourInCallback(onComplete);
            let acc = 0;
            for(let i=SPLIT_COUNT-1;i>=0;i--){
                if(this.info.colorIds[i]!=0){
                    continue;
                }
                this.info.colorIds[i] = colorId;
                if(++acc==num){
                    break;
                }
            }
            let hex = WaterColors[colorId]||"#538849"
            this.water.addInfo({
                colorId:colorId,
                height:num/SPLIT_COUNT *HEIGHT_FACTOR,
                color:new Color().fromHEX(hex)
            });
    
            AudioUtil.playPourWaterEffect(num/SPLIT_COUNT);
        }
    
        /**加水立刻 */
        addWaterImmediately(colorId:number,num:number){
            let acc = 0;
            for(let i=SPLIT_COUNT-1;i>=0;i--){
                if(this.info.colorIds[i]!=0){
                    continue;
                }
                this.info.colorIds[i] = colorId;
                if(++acc==num){
                    break;
                }
            }
            this.initWater();
        }
    
        /**将顶部的颜色删除num个 */
        removeTopWaterImmediately(num:number){
            let acc = 0;
            let top = this.getTop();
            let colorIds = this.info.colorIds;
            for(let i=0;i<SPLIT_COUNT;i++){
                let _id = colorIds[i]
                if(_id==0){
                    continue;
                }else if(top.topColorId==_id){//顶部相同颜色的水都倒掉了
                    colorIds[i] = 0;
                    if(++acc>=num){
                        break
                    }
                }else{
                    break;
                }
            }
            this.initWater();
            return top;
        }
    
        getTop(){
            let colorIds = this.info.colorIds;
            let emptyNum = 0;//杯顶的空位有几格
            let topColorId = 0;//杯顶颜色id
            let topColorNum = 0;//杯顶的颜色共有几格
            for(let i=0;i<SPLIT_COUNT;i++){
                if(colorIds[i]==0){
                    emptyNum++;
                    continue;
                }
                if(topColorId==0||topColorId==colorIds[i]){
                    topColorId = colorIds[i];
                    topColorNum++;
                }else{
                    break;
                }
            }
            return {
                emptyNum:emptyNum,
                topColorId:topColorId,
                topColorNum:topColorNum,
                colorHex:WaterColors[topColorId]||"#538849"
            }
        }
    
        reset(){
            this.node.angle = 0;
            this.water.skewAngle = 0
        }
    
        public setPourAnchor(isRight:boolean){
            let pt = v2(3,2);
            pt.x = isRight?(this.node.getComponent(UITransform).width-pt.x):pt.x;
            pt.y = this.node.getComponent(UITransform).height-pt.y;
            
            pt.x = pt.x/this.node.getComponent(UITransform).width;
            pt.y = pt.y/this.node.getComponent(UITransform).height;
    
            this.setAnchor(pt) 
        }
    
        public setNormalAnchor(){
            this.setAnchor(v2(0.5,0.5))
        }
    
        private setAnchor(anchor:Vec2){
            let trans = this.node.getComponent(UITransform)
    
            let oldAnchor = trans.anchorPoint.clone()
            let selfPt = this.node.getPosition();//当前锚点世界坐标
            
            trans.setAnchorPoint(anchor);
    
            let offsetAnchor = v2(anchor.x-oldAnchor.x,anchor.y-oldAnchor.y)
            let offsetPt = v2(offsetAnchor.x*trans.width,offsetAnchor.y*trans.height)
            offsetPt = rotatePt(offsetPt,this.node.angle)
            selfPt.x += offsetPt.x;
            selfPt.y += offsetPt.y;
            this.node.setPosition(selfPt);
    
            this.water.getComponent(Widget).updateAlignment()
        }
    
        /**获取当前水面的global y坐标 */
        getWaterSurfacePosY(needAdjust=false){
            let top = this.getTop();
            let y = (SPLIT_COUNT-top.emptyNum)/SPLIT_COUNT;
            if(y<0.02){
                y = 0.02
            }else if(needAdjust){
                y-=1.0/SPLIT_COUNT*HEIGHT_FACTOR;
            }
            y*=HEIGHT_FACTOR;
            y-=0.5;
            let pt = v3(0,this.water.node.getComponent(UITransform).height*y);
            pt = this.water.node.getComponent(UITransform).convertToWorldSpaceAR(pt)
            return pt.y
        }
    }
    
    //水杯旋转角度控制
    function rotatePt(pt:Vec2,angle:number){
        let radian = angle2radian(angle);
        let ret = v2();
        ret.x = pt.x*Math.cos(radian)-pt.y*Math.sin(radian);
        ret.y = pt.x*Math.sin(radian)+pt.y*Math.cos(radian);
    
        return ret;
    }
    
    function angle2radian(angle:number){
        while(angle>360){
            angle-=360;
        }
        while(angle<-360){
            angle+=360;
        }
        return (angle%360) * Math.PI / 180.0;
    }

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-14 21:30:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-14 21:30:02       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-14 21:30:02       58 阅读
  4. Python语言-面向对象

    2024-07-14 21:30:02       69 阅读

热门阅读

  1. SVN 分支管理深入解析

    2024-07-14 21:30:02       16 阅读
  2. 栈与队列---滑动窗口最大值

    2024-07-14 21:30:02       19 阅读
  3. 查询(q_proj)、键(k_proj)和值(v_proj)投影具体含义

    2024-07-14 21:30:02       17 阅读
  4. Django核心面试题

    2024-07-14 21:30:02       19 阅读
  5. B树与B+树的区别

    2024-07-14 21:30:02       17 阅读
  6. 第三方登录、任意用户登录漏洞总结

    2024-07-14 21:30:02       19 阅读
  7. 关于RiboSeq分析流程的总结

    2024-07-14 21:30:02       20 阅读
  8. T113-i 高清倒车支持解串器MAX96708驱动

    2024-07-14 21:30:02       22 阅读
  9. 【MySQL】9.表的内外连接

    2024-07-14 21:30:02       21 阅读