import { _decorator, Component, Node, Vec2, v2, Camera, Rect, CCFloat, EventTouch, EventMouse, UITransform, Vec3, Touch, Size, view, CCInteger, Sprite, tween } from "cc"; import { EDITOR, PREVIEW } from "cc/env"; import { IVec2Like } from "cc"; import { EBundleName } from "../const/GameEnum"; import MesMgr from "../MesEvent/MesMgr"; const { ccclass, property,executeInEditMode } = _decorator; @ccclass("CameraScale") export class CameraScale{ @property({ type: CCFloat, displayName: '最小值' }) min: number = 1; @property({ type: CCFloat, displayName: '最大值' }) max: number = 1; } @ccclass("CameraCon") @executeInEditMode() export class CameraCon extends Component { m_TounchDown: boolean = false; m_IsClickDown: boolean = false; m_MoveSpeed: number = 2; m_Lastdistance: number = 0; t_TempVec2: Vec2 = v2(); private _Camera:Camera; public get m_Camera(): Camera{ if(!this._Camera){ this._Camera = this.node.getComponent(Camera); } return this._Camera; }; @property(Sprite) mBg:Sprite; @property({type:Node,displayName:"摄像机矩形节点"}) mCameraRect: Node; @property({ type: CameraScale, displayName: '摄像机缩放约束' }) mCameraScale: CameraScale = new CameraScale(); Cmaer_Scale_Speed: number = 0.01; @property({ displayName: '摄像机移动返回约束' }) m_Rect: Rect = new Rect(); @property({ type: CCInteger, displayName: '基础' }) BaseoOrthoHeight:number = 667; _ZoomRatio: number = 1.0; @property({ type: CCFloat, displayName: '摄像机的Ratio' }) get mZoomRatio(){ return this._ZoomRatio; } set mZoomRatio(value:number){ if(this.isFreeze){return} this._ZoomRatio = value; this.setTounchRect(); } private isMove:boolean =false; private moveDir:Vec2 = new Vec2(); private time:number = 0.2; private readonly maxTime:number = 0.5; private tempPos: Vec3 = new Vec3(); /**默认的 宽高大小 */ initWidthAndHight: Vec2 = new Vec2(); private toRatio: number = 0; private baseRation: number = 0; private toTime: number = 0; private toMaxTime: number = 0; private isFreeze:boolean = false; public static Ins: CameraCon; protected onLoad(): void { this.initWidthAndHight.x = view.getVisibleSize().width; this.initWidthAndHight.y = view.getVisibleSize().height; CameraCon.Ins = this; this.addEvents(); this.setTounchRect(); if (EDITOR) { this.node.active = false; setTimeout(() => { this.node.active = true; }) } } setBgSpRite(url:string,Bundle:EBundleName){ CNodeUtils.SwitchTexture(url,this.mBg,Bundle); } private addEvents(): void { this.mCameraRect.on(Node.EventType.TOUCH_START, this.onMouseEnter, this); this.mCameraRect.on(Node.EventType.TOUCH_MOVE, this.onMouseMove, this); this.mCameraRect.on(Node.EventType.TOUCH_END, this.onMouseUp, this); this.mCameraRect.on(Node.EventType.TOUCH_CANCEL, this.onMouseLeave, this); if(PREVIEW){ this.mCameraRect.on(Node.EventType.MOUSE_WHEEL, this.onMouseWheel, this); } } get CamreaWordPos(){ return this.m_Camera.node.worldPosition; } TweenZoomRatio(ratio:number,time:number = 0.5){ this.toTime = 0; this.toMaxTime = time; this.baseRation = this._ZoomRatio; this.toRatio = ratio - this._ZoomRatio; let dt = this.toMaxTime / 60; this.schedule(this.updateZoomRatio, dt); } private updateZoomRatio(dt:number){ //let dt = this.toMaxTime / 60; this.toTime += dt; let bar = this.toTime / this.toMaxTime; if (bar >= 1) { bar = 1; } this.mZoomRatio = this.baseRation + this.toRatio * bar; if (bar >= 1) { this.unschedule(this.updateZoomRatio); } } getWordRect(){ return this.mCameraRect.getComponent(UITransform).getBoundingBoxToWorld(); } /**获取视野的最大范围半径 */ getWordRange(){ let rect = this.getWordRect(); return Math.max(rect.width,rect.height) / 2; } /**获取视野的最大范围半径 */ getWordRange2() { let rect = this.getWordRect(); //return Math.max(rect.width, rect.height) / 2; return { width: rect.width / 2, height: rect.height / 1.7 }; } SetCameraPos(pos:IVec2Like,isSet:boolean = true){ if (this.isFreeze) { return } pos.x = Math.max(this.m_Rect.xMin / this._ZoomRatio, pos.x); pos.x = Math.min(this.m_Rect.width / this._ZoomRatio, pos.x); pos.y = Math.max(this.m_Rect.yMin / this._ZoomRatio, pos.y); pos.y = Math.min(this.m_Rect.height / this._ZoomRatio, pos.y); this.m_Camera.node.setPosition(pos.x, pos.y, 1000) } SetCameraFixdPos(pos:IVec2Like,isSet:boolean = true){ this.m_Camera.node.setPosition(pos.x, pos.y, 1000) } /**获取UI坐标通过摄像机转世界坐标 */ getScreenToWorldPoint(event: EventTouch, out?: Vec3) { return this.m_Camera.screenToWorld(new Vec3(event.getLocation().x, event.getLocation().y), out); } getWordPosToUIPos(wordPos: Vec3,prent:Node, out?: Vec3) { return this.m_Camera.convertToUINode(wordPos,prent, out); } updateBg(){ //背景跟随 let sprite = this.mBg.getComponent(Sprite); if(sprite.spriteFrame){ let material = sprite.sharedMaterial; let uvOffset = new Vec2(this.node.position.x / 512, -this.node.position.y / 512); material.setProperty("tilingOffset", uvOffset); } //bg.position = position; } protected update(dt: number): void { this.isMove && this.moveByDir(dt); } private moveByDir(dt:number){ if (dt >= 0) { this.time = Math.max(0, this.time - dt); if (this.time <= 0) { this.isMove = false; } } const moveScale = dt < 0 ? 1 : this.time / this.maxTime; this.tempPos.x = this.node.position.x; this.tempPos.y = this.node.position.y; this.tempPos.x -= this.moveDir.x * this.m_MoveSpeed / this.mZoomRatio * moveScale; this.tempPos.y -= this.moveDir.y * this.m_MoveSpeed / this.mZoomRatio * moveScale; this.SetCameraPos(this.tempPos); } setFreeze(Ration:number,pos:IVec2Like){ this.isFreeze = true; this._ZoomRatio = Ration; this.setTounchRect(false); this.m_Camera.node.setPosition(pos.x, pos.y, 1000) } RestoreFreeze(){ this.isFreeze = false; } private setTounchRect(isCheck:boolean = true) { if(isCheck){ this._ZoomRatio = Math.min(this._ZoomRatio, this.mCameraScale.max); this._ZoomRatio = Math.max(this._ZoomRatio, this.mCameraScale.min); } this.m_Camera.orthoHeight = this.BaseoOrthoHeight * this._ZoomRatio; ConsoleEx.Log("当前缩放",this._ZoomRatio); this.mCameraRect.getComponent(UITransform).setContentSize(new Size(this.initWidthAndHight.x * this._ZoomRatio, this.initWidthAndHight.y * this._ZoomRatio )); // this.mBg.node.setScale(this._ZoomRatio,this._ZoomRatio,this._ZoomRatio) let tX = this.initWidthAndHight.x * this._ZoomRatio; let tY = this.initWidthAndHight.y * this._ZoomRatio; tX = Math.ceil((tX / 512) + 1) * 512; tY = Math.ceil((tY / 512) + 1) * 512; this.mBg.node.getComponent(UITransform).setContentSize(new Size(tX,tY)) //ConsoleEx.Log("当前",this._ZoomRatio) } //#region 摄像机触摸事件 /**手指按下 */ public onMouseEnter(event: EventTouch) { this.m_TounchDown = true; this.m_Lastdistance = -1; this.m_IsClickDown = true; this.isMove = false; } movebottom(time:number = 0){ if(time<=0){ this.tempPos.x = this.node.position.x; this.tempPos.y = -Number.MAX_VALUE; this.SetCameraPos(this.tempPos); }else{ this.tempPos.x = this.node.position.x; this.tempPos.y = -Number.MAX_VALUE; this.tempPos.x = Math.max(this.m_Rect.xMin / this._ZoomRatio, this.tempPos.x); this.tempPos.x = Math.min(this.m_Rect.width / this._ZoomRatio, this.tempPos.x); this.tempPos.y = Math.max(this.m_Rect.yMin / this._ZoomRatio, this.tempPos.y); this.tempPos.y = Math.min(this.m_Rect.height / this._ZoomRatio, this.tempPos.y); let target = this.tempPos.clone(); target.z = 1000; tween(this.m_Camera.node).to(time, { position: target }).start(); } } moveTop(time:number = 0){ if(time<=0){ this.tempPos.x = this.node.position.x; this.tempPos.y = Number.MAX_VALUE; this.SetCameraPos(this.tempPos); }else{ this.tempPos.x = this.node.position.x; this.tempPos.y = Number.MAX_VALUE; this.tempPos.x = Math.max(this.m_Rect.xMin / this._ZoomRatio, this.tempPos.x); this.tempPos.x = Math.min(this.m_Rect.width / this._ZoomRatio, this.tempPos.x); this.tempPos.y = Math.max(this.m_Rect.yMin / this._ZoomRatio, this.tempPos.y); this.tempPos.y = Math.min(this.m_Rect.height / this._ZoomRatio, this.tempPos.y); let target = this.tempPos.clone(); target.z = 1000; tween(this.m_Camera.node).to(time, { position: target }).start(); } } /**手指移动 */ public onMouseMove(event: EventTouch) { this.m_IsClickDown = false; if (!this.m_TounchDown) return; let Touches: Touch[] = event.getTouches(); if (Touches.length == 1) { this.time = this.maxTime; this.moveDir.x = event.getDeltaX(); this.moveDir.y = event.getDeltaY(); this.moveByDir(-1); } else if (Touches.length == 2) { Vec2.subtract(this.t_TempVec2, Touches[0].getLocation(), Touches[1].getLocation()); // 双指当前间距 let distance = this.t_TempVec2.length(); if (this.m_Lastdistance <= 0) { this.m_Lastdistance = distance; } let offdis = distance - this.m_Lastdistance if (offdis < 0) { this.mZoomRatio -= (distance - this.m_Lastdistance) * this.Cmaer_Scale_Speed; } else if (offdis > 0) { this.mZoomRatio -= (distance - this.m_Lastdistance) * this.Cmaer_Scale_Speed; }else{ this.setTounchRect(); } this.m_Lastdistance = distance; } } /**手指抬起 */ public onMouseUp(event: EventTouch) { this.m_TounchDown = false; this.m_Lastdistance = -1; if (!this.m_IsClickDown) { this.isMove = true;return;} this.m_IsClickDown = false; MesMgr.event("MoveToPoint", this.getScreenToWorldPoint(event)) } /**手指在目标区域内抬起 作用同onMouseUp 一样 */ public onMouseLeave(event: EventTouch) { this.onMouseUp(event); } /**滑轮滚动 */ public onMouseWheel(event: EventMouse) { let scrollY = event.getScrollY(); this.mZoomRatio += scrollY / 100 * this.Cmaer_Scale_Speed; //this.setTounchRect(); } private onMouseWheel_document(e) { let dir = 0; if (e.wheelDelta) { dir = e.wheelDelta; } else if (e.detail) { dir = e.detail; } if (dir < 0) { this.mZoomRatio += dir / 100 * this.Cmaer_Scale_Speed; } else if (dir > 0) { this.mZoomRatio += dir / 100 * this.Cmaer_Scale_Speed; }else{ this.setTounchRect(); } } //#endregion }