01
效果演示
Cocos Creator 版本:3.4.1
该 demo 演示了双指缩放时通过更改节点的 scale 属性或者更改摄像机的 position 属性实现场景的缩放效果
02
实现方法
两种方式都各有利弊,可以根据使用场景选择合适的方案
1开启多点触控
在项目设置中开启多点触控
2缩放节点
节点的缩放属性随着双指间距的放大缩小进行等比的变化
基本概念:
双指初始间距:双指刚触碰屏幕时的间距
双指当前间距:双指移动时的间距
节点初始缩放:双指刚触碰屏幕时节点的缩放
节点当前缩放:双指移动时节点的缩放
等比关系:
双指当前间距 / 双指初始间距 = 节点当前缩放 / 节点初始缩放
公式变换:
节点当前缩放 = 节点初始缩放 * (双指当前间距 / 双指初始间距)
完整代码:
onTouchMove(event: EventTouch) {
let touches = event.getTouches();
if (touches.length >= 2) {
let temp = v2();
Vec2.subtract(temp, touches[0].getLocation(), touches[1].getLocation());
// 双指当前间距
let distance = temp.length();
if (this.originalTouchDistance == -1) {
// 双指初始间距
this.originalTouchDistance = distance;
// 节点初始缩放
this.originalNodeScale = this.nodeTarget.scale.clone();
}
let targetScale = v3();
// 双指当前间距 / 双指初始间距
let scale = distance / this.originalTouchDistance;
// 节点初始缩放 * (双指当前间距 / 双指初始间距)
Vec3.multiplyScalar(targetScale, this.originalNodeScale, scale);
scale = targetScale.x;
// 属于节点缩放比
scale = clamp(scale, this.minScale, this.maxScale);
this.nodeTarget.setScale(scale, scale, scale);
}
}
3移动摄像机
当双指进行缩放操作时,通过移动摄像机的位置,同样可以实现场景缩放的视觉效果
摄像机到原点的距离随着双指间距的放大缩小进行等比的变化
方法和节点缩放一样,只不过是将节点的缩放变为摄像机到原点的距离的缩放
基本概念:
双指初始间距:双指刚触碰屏幕时的间距
双指当前间距:双指移动时的间距
摄像机初始距离:双指刚触碰屏幕时摄像机到原点的距离
摄像机当前距离:双指移动时摄像机到原点的距离
等比关系:
双指当前间距 / 双指初始间距 = 摄像机当前距离 / 摄像机初始距离
公式变换:
摄像机当前距离 = 摄像机初始距离 * (双指当前间距 / 双指初始间距)
求出摄像机当前的距离后,还需要根据距离计算出摄像机的坐标
将场景放大缩小,实际只是将摄像机拉近拉远,并不会改变摄像机的角度
所以可以根据 ∠A,利用三角函数求出摄像机的坐标
利用反正切函数计算 ∠A,即摄像机与水平轴的夹角:
getAngle(a: Vec2, b: Vec2) {
let delta = v2();
Vec2.subtract(delta, a, b);
// http://c.biancheng.net/ref/atan2.html
// 反正切函数 atan2() 和正切函数 tan() 的功能恰好相反:
// tan() 是已知一个角的弧度值,求该角的正切值;而 atan2() 是已知一个角的正切值(也就是 y/x),求该角的弧度值
let degree = misc.radiansToDegrees(Math.atan2(delta.y, delta.x));
return degree;
}
利用正弦函数计算对边 a,即摄像机的 y 坐标:
let y = Math.sin(rad) * curCameraDistance;
利用余弦函数计算临边 b,即摄像机的 z 坐标:
let z = Math.cos(rad) * curCameraDistance;
完整代码:
onTouchMove(event: EventTouch) {
let touches = event.getTouches();
if (touches.length >= 2) {
let temp = v2();
Vec2.subtract(temp, touches[0].getLocation(), touches[1].getLocation());
// 双指当前间距
let distance = temp.length();
if (this.originalTouchDistance == -1) {
// 双指初始间距
this.originalTouchDistance = distance;
// 摄像机初始位置
this.originalCameraPosition = this.nodeCamera.position.clone();
// 摄像机初始距离
this.originalCameraDistance = this.originalCameraPosition.length();
}
let scale = this.originalTouchDistance / distance;
// 摄像机机当前距离
let curCameraDistance = this.originalCameraDistance * scale;
// 约束摄像机距离
curCameraDistance = clamp(curCameraDistance, this.minLength, this.maxLength);
// 降维 可以将 z 视作二维平面中的 x
temp = v2(this.originalCameraPosition.z, this.originalCameraPosition.y);
// 计算两点间的角度
let angle = this.getAngle(temp, Vec2.ZERO);
// 根据角度计算弧度
let rad = misc.degreesToRadians(angle);
// http://c.biancheng.net/ref/sin.html
// sinA = 对边 / 斜边 可得 对边 = sinA * 斜边
let y = Math.sin(rad) * curCameraDistance;
// http://c.biancheng.net/ref/cos.html
// cosA = 临边 / 斜边 可得 临边 = cosA * 对边
let z = Math.cos(rad) * curCameraDistance;
this.nodeCamera.position = v3(this.nodeCamera.position.x, y, z);
}
}
爱意随风起,风止意难平。
落日归山海,山海藏深意。
更多教程
请扫码关注