如何优化Phaser 3中可旋转地球的点击拖拽交互使其更直观?
解决Phaser 3 3D模型拖拽旋转的直觉交互问题
问题的核心在于直接修改欧拉角时,X轴旋转基于全局坐标系而非模型当前的局部坐标系。当模型绕全局Y轴旋转后,继续用全局X轴旋转会出现不符合直觉的拖拽表现——正确逻辑应该是:鼠标左右拖拽时绕全局Y轴旋转(保持世界上下方向固定),鼠标上下拖拽时绕模型当前的局部X轴旋转(让模型正面区域随鼠标方向移动)。
解决方案:用四元数实现局部坐标系旋转
Phaser的Math.Quaternion可方便处理局部旋转,避开欧拉角的旋转顺序和万向锁问题。具体步骤如下:
- 初始化时用四元数维护模型旋转状态(替代直接修改
modelRotation) - 在
pointermove事件中,将垂直拖拽转换为模型局部X轴旋转,水平拖拽保持为全局Y轴旋转 - 将四元数转回匹配Phaser要求的欧拉角,赋值给
mesh.modelRotation
代码实现:
首先在场景初始化时定义四元数变量:
// 场景类内部定义 this.modelQuat = new Phaser.Math.Quaternion();
然后替换pointermove中的旋转逻辑:
// pointermove事件回调内 const rotateRate = 0.01; // 按需调整旋转速率 // 水平拖拽:绕全局Y轴执行外在旋转 const yRot = pointer.velocity.x * rotateRate / 800; const globalYQuat = new Phaser.Math.Quaternion().setFromAxisAngle(new Phaser.Math.Vector3(0,1,0), yRot); // 垂直拖拽:绕模型当前局部X轴执行内在旋转 const xRot = pointer.velocity.y * rotateRate / 600; const localXQuat = new Phaser.Math.Quaternion().setFromAxisAngle(new Phaser.Math.Vector3(1,0,0), xRot); // 先应用局部X旋转,再叠加全局Y旋转(顺序不可颠倒) Phaser.Math.Quaternion.multiply(this.modelQuat, localXQuat, this.modelQuat); Phaser.Math.Quaternion.multiply(globalYQuat, this.modelQuat, this.modelQuat); // 将四元数转换为Phaser要求的ZXY顺序外在欧拉角 const euler = new Phaser.Math.Euler().setFromQuaternion(this.modelQuat, 'ZXY'); mesh.modelRotation.x = euler.x; mesh.modelRotation.y = euler.y; mesh.modelRotation.z = euler.z;
逻辑说明
- 局部X轴旋转:通过四元数乘法顺序,先基于模型当前姿态(局部坐标系)绕X轴旋转,确保鼠标上下拖拽时,模型正面区域始终跟随鼠标方向移动
- 全局Y轴旋转:绕世界空间Y轴旋转,保持左右拖拽时世界上下方向固定,符合用户对“左右旋转”的直觉
- 适配Phaser旋转规则:转换欧拉角时指定
ZXY顺序,完美匹配modelRotation的外在旋转逻辑
可选优化:限制翻转范围
如果需要避免模型过度翻转(类似Google Earth的限制),可在转换欧拉角后对X轴旋转值做约束:
euler.x = Phaser.Math.Clamp(euler.x, -Math.PI/2, Math.PI/2);
内容的提问来源于stack exchange,提问作者Kylok
相关产品推荐
相关产品推荐

