最近开始研究微信小游戏,有兴趣的 可以关注一下 公众号, 记录一些心路历程和源代码。
定义一个 Cup类:
主要功能
-
初始化水杯:根据传入的颜色信息初始化水杯中的水层。
-
倒水:模拟水杯倾斜并倒出水的过程。
-
加水:模拟向水杯中加水的过程。
-
颜色管理:管理水杯中不同颜色的水层。
-
交互:处理水杯的点击事件,触发倒水或加水的操作。
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;//杯顶颜色idlet 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; }