Creator双指缩放和拖动无黑边

Creator双指缩放和拖动无黑边

源码在文末
效果
请添加图片描述
因为PC端不可以双指操作,所以这是现在手机上录屏再到电脑录GIF的结果

节点结构
在这里插入图片描述
遮挡节点
在这里插入图片描述
目标节点,也就是需要缩放和拖动的奥利给图片
在这里插入图片描述
创建一个脚本挂在canvas上

需要在组件里面定义的属性

	@property(UITransformComponent)
    canvas: UITransformComponent = null!;

    @property({displayName: "相机", tooltip: "相机", type: CameraComponent})
    camera: CameraComponent = null!;

    @property({displayName: "目标节点", tooltip: "目标节点", type: Node})
    target: Node = null!;

    @property({displayName: "文字数组", tooltip: "文字数组", type: [LabelComponent]})
    label: LabelComponent[] = [];

    @property({displayName: "遮挡的节点", tooltip: "遮挡的节点,目标节点的父节点", type: UITransformComponent})
    mask: UITransformComponent = null!;

    @property({displayName: "最小缩放倍数", tooltip: "最小缩放倍数", type: CCFloat})
    min_scale: number = 1.00;

    
    // 缩放灵敏度
    SPL: number = 0.5;

    // 上次缩放缩放时两个手指触点连线的长度
    length: number = null!;
    // 上次缩放的时候目标节点的位置,这个除以了缩放倍数,再次用这个值需要重新乘缩放倍数
    pos: Vec2 = null!;

拖动和双指缩放的实现

	onLoad () {
        let self = this;

        // 给遮挡节点绑定移动事件   负责移动目标节点
        this.mask.node.on(SystemEventType.TOUCH_MOVE, function (event: EventTouch) {
            // 获取触点在上一次事件时的位置对象,对象包含 x 和 y 属性
            let last_pos = event.getPreviousLocation();
            // 获取触点位置
            let pos = event.getLocation();
            // 做向量减法
            let dir = last_pos.subtract(pos);
            // 获取目标节点坐标
            let node_pos = self.target.getPosition();
            // 设置目标节点坐标
            self.target.setPosition(new Vec3(node_pos.x - dir.x, node_pos.y - dir.y));

            console.log("移动了目标节点");
        }, this);

        // 给canvas绑定移动事件   负责两个手指缩放
        this.canvas.node.on(Node.EventType.TOUCH_MOVE, function (event: EventTouch) {

            // 获取触点
            let touches = event.getTouches();
            
            // 如果有两个以上触点
            if (touches.length >= 2) {
                // 获取第一个和第二个触点
                let touch1 = touches[0];
                let touch2 = touches[1];

                // 把通过触摸得到的点转到节点坐标,先用camera转为世界坐标再转到canvas节点空间坐标系
                let point1 = self.camera.screenToWorld(new Vec3(touch1.getLocation().x, touch1.getLocation().y));
                let point2 = self.camera.screenToWorld(new Vec3(touch2.getLocation().x, touch2.getLocation().y));
                let touchPoint1 = self.canvas.convertToNodeSpaceAR(point1);
                let touchPoint2 = self.canvas.convertToNodeSpaceAR(point2);
                // 最后转换成vec2
                let tp1 = new Vec2(touchPoint1.x, touchPoint1.y);
                let tp2 = new Vec2(touchPoint2.x, touchPoint2.y);
                // 两触点之差
                let tp_dis = tp1.subtract(tp2);
                // 两触点连线的长度
                let length = tp_dis.length();


                // 如果手指第一次触碰到屏幕
                if (self.length == null) {
                    // 设置两手指触点连线距离
                    self.length = length;
                    console.log("初始化");
                } else {

                    self.label[0].string = "两触点连线长度" + length;

                    // 算出灵敏度
                    let SPL = self.SPL * 1000;

                    // 放大了   本次两触点连线长度大于上次,也就是手指正在做放大动作
                    if (length > self.length) {
                        console.log("放大了");
                        
                        // 算出本次长度和上次长度差
                        let dis = length - self.length;
                        let scale = self.target.getScale();
                        self.target.setScale(scale.x + dis / SPL, scale.y + dis / SPL);
                    }
                    // 缩小了   本次两触点连线长度小于上次,也就是手指正在做缩小动作
                    else if (length < self.length) {
                        console.log("缩小了");

                        // 算出上次长度和本次长度差
                        let dis = self.length - length;
                        let scale = self.target.getScale();
                        self.target.setScale(scale.x - dis / SPL, scale.y - dis / SPL);
                    }
                }


                // 获取目标节点的缩放
                let scale = self.target.getScale();
                // 限制目标节点的缩放,目标节点缩到多小就不能缩了
                if (scale.x <= self.min_scale || scale.y <= self.min_scale) {
                    self.target.setScale(self.min_scale, self.min_scale, 1.0);
                }

                
                
                // 更新label
                self.label[1].string = "目标节点当前缩放:" + self.target.getScale();
                let sc_n = Math.floor(self.target.scale.x / 1.0 * 100) + "%";
                self.label[2].string = "当前缩放:" + sc_n;


                // 更新上次触摸时两触点连线长度
                self.length = length;


                // 获取目标节点缩放
                let sc = self.target.scale.x;
                
                // 如果第一次缩放
                if (self.pos == null!) {
                    // 设置上次目标节点位置   结果为目标节点的位置除以缩放倍数
                    self.pos = new Vec2(self.target.position.x / sc, self.target.position.y / sc);
                } else {
                    // 获取上次目标节点的位置并且乘缩放倍数
                    let pos = new Vec3(self.pos.x * sc, self.pos.y * sc);
                    // 设置目标节点的位置
                    self.target.setPosition(pos);

                    // 设置上次目标节点的位置   结果为目标节点的位置除以缩放倍数
                    self.pos = new Vec2(self.target.position.x / sc, self.target.position.y / sc);
                }
            }
        }, this.node);


        // 给canvas绑定结束触摸事件
        this.canvas.node.on(Node.EventType.TOUCH_END, function () {
            // 设置触点连线长为null,下次手指缩放时再次初始化,如果不写这句代码下一次手指缩放时会因为手指位置与上次距离过大而出现突然放大或缩小的问题
            self.length = null!;
            // 设置目标节点位置为null,下次手指缩放时再次初始化,如果不写这句代码会导致下一次手指缩放时图片位置锁定
            self.pos = null!;
        }, this);
    }

限制目标节点上下左右拖动范围的代码

刚开始做的时候在遮挡节点下创建了一个和目标节点一样大小的纯黑精灵当背景,辅助写限制拖动范围的代码,如果没有限制拖动范围的代码拖动时就会出现纯黑色的黑边,做完之后因为不需要再用就把纯黑精灵节点删掉了,注释和标题写的黑边就是这个意思

	update () {
        // 获取目标节点
        let target = this.target.getComponent(UITransformComponent)!;

        // 获取缩放倍数
        let sc = this.target.scale.x;

        // 获取目标节点和mask的上下左右
        let left_tg = target.node.position.x - (target.width * sc / 2);
        let right_tg = target.node.position.x + (target.width * sc / 2);
        let top_tg = target.node.position.y + (target.height * sc / 2);
        let up_tg = target.node.position.y - (target.height * sc / 2);

        let left = -this.mask.width / 2;
        let right = this.mask.width / 2;
        let top = this.mask.height / 2;
        let up = -this.mask.height / 2;


        // 获取目标节点位置,因为位置会发生变化,下面每个if语句后面都要再获取一次位置
        let pos = this.target.getPosition();
        

        // 检测目标节点不超出规定范围,防止出现黑边
        if (left_tg >= left) {
            this.target.setPosition(new Vec3(left + target.width * sc / 2, pos.y, pos.z));
            // console.log("左边缘");
        }

        pos = this.target.getPosition();

        if (right_tg <= right) {
            this.target.setPosition(new Vec3(right - target.width * sc / 2, pos.y, pos.z));
            // console.log("右边缘");
        }

        pos = this.target.getPosition();

        if (top_tg <= top) {
            this.target.setPosition(new Vec3(pos.x, top - target.height * sc / 2, pos.z));
            // console.log("上边缘");
        }

        pos = this.target.getPosition();

        if (up_tg >= up) {
            this.target.setPosition(new Vec3(pos.x, up + target.height * sc / 2, pos.z));
            // console.log("下边缘");
        }
    }

节点的绑定
文字数组随便新建三个label绑定上就可以,主要为了更方便直观地看目标节点的具体变化
在这里插入图片描述

双指缩放实现思路

如何判断手指是在做缩小动作还是放大动作?

只需要知道每次两指接触屏幕时,两指触点连线的长度即可。就是图中红线画的部分长度
只要知道第一次接触屏幕的长度,就可以了,用第二次接触时长度和上一次也就是第一次进行大小比较,第二次比第一次大就是在做放大动作,反之就是缩小。

举个例子理解,两手指刚接触屏幕时红线长度是10,手指移动一段距离后长度变成了20,因为20大于10,所以判断两手指正在向外扩张,在做放大动作。手指又移动了一段距离长度变成了15,判断为缩小,15大于10为什么还判断为缩小呢,第一次是10,第二次是20,第三次是15,第三次需要和上一次的长度20比较,而不是和第一次比较,因为15小于20,所以手指在向内收缩,做缩小的动作
在这里插入图片描述
length属性就是上一次缩放时两指触点连线的长度
在这里插入图片描述
来看看代码里面是怎么实现的,先获取动态触点列表,判断触点数量,如果有两个以上触点就计算出两触点连线长度,再判断是不是第一次触碰屏幕,如果是第一次就把连线长度赋值给length属性
在这里插入图片描述
如果不是第一次触碰屏幕就判断手指的动作,用本次长度和上次长度比大小,最后用本次长度减去上次长度求出手指移动的距离,处理后对目标节点进行缩放

还要限制目标节点缩放的范围,缩到多小就不能缩放了
在这里插入图片描述
判断完手指动作一定要更新上次触碰时两触点连线长度,不然下一次缩放时的判断就不对了
在这里插入图片描述
触摸结束把length设为null,下一次触碰时重新初始化
在这里插入图片描述
还需要注意一个问题,双指放大的时候目标节点的大小不断的在变化,放大之后显示的部分就不是之前看的部分中心所放大后的样子了,就像下面这样
请添加图片描述
我通过一个很巧妙的办法解决了这个问题,下图就是解决后的效果
请添加图片描述
需要用到pos属性,pos属性是上次缩放时目标节点的位置,这个位置是目标节点的位置除以了倍数得到的结果
在这里插入图片描述
手指缩放时进行判断,和length的处理办法有点像
如果是第一次缩放就初始化设置pos
如果不是第一次缩放就把目标节点的位置设为上次目标节点的位置乘现在的缩放倍数
在这里插入图片描述
同样在结束触摸的时候设为null,下次双指缩放再初始化
在这里插入图片描述

源码:https://gitee.com/propertygame/cocos-creator3.x-demos/tree/master/HandsScaling
技术交流Q群:1130122408
更多内容请关注微信公众号

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值