一, 场景设计
二,整体场景效果
三,QuatView.ts代码
import {_decorator, Component, EventTouch, Input, input, Node, Quat, v3, Vec3, Vec2} from "cc";
const {ccclass, property} = _decorator;
@ccclass("QuatView")
export class QuatView extends Component {
@property({type: Node, tooltip: "目标cube"})
private cube: Node = null;
@property({type: Node, tooltip: "玩家"})
private player: Node = null;
private isSlerp: boolean;
private rotationQuat: Quat;
private tempQuat: Quat;
private timerMs: number;
private durationMs: number;
private tempV3: Vec3;
protected onLoad(): void {
this.isSlerp = false;
this.rotationQuat = new Quat();
this.tempQuat = new Quat();
this.tempV3 = new Vec3();
}
protected onEnable(): void {
this.listener(true);
}
protected onDisable(): void {
this.listener(false);
}
private listener(isAdd: boolean): void {
if (isAdd) {
input.on(Input.EventType.TOUCH_END, this.onTouchHandler, this);
input.on(Input.EventType.TOUCH_MOVE, this.onTouchHandler, this);
} else {
input.off(Input.EventType.TOUCH_END, this.onTouchHandler, this);
input.off(Input.EventType.TOUCH_MOVE, this.onTouchHandler, this);
}
}
private onTouchHandler(e: EventTouch): void {
switch (e.type) {
case Input.EventType.TOUCH_END:
// this.turningToTarget(true);
break;
case Input.EventType.TOUCH_MOVE:
// this.touchRotation(e);
this.touchAroundRotation(e);
break;
}
}
/**
* 转向目标
*/
private turningToTarget(isSlerp: boolean): void {
let targetPosition: Vec3 = this.cube.worldPosition
.subtract(this.player.worldPosition)
.normalize();//看向的方向 player -> cube
Quat.fromViewUp(this.rotationQuat, targetPosition, Vec3.UP);//获取转向rotationQuat
if (Quat.equals(this.rotationQuat, this.player.worldRotation)) {
this.isSlerp = false;
console.log(`%c 已经旋转到目标值,不需要再次旋转了`, "color:#F00");
} else {
if (!isSlerp) {
this.player.setWorldRotation(this.rotationQuat);
} else {
this.durationMs = 2000;
this.timerMs = 0;
}
this.isSlerp = isSlerp;
}
}
/**
* 触摸自旋转
*/
private touchRotation(e: EventTouch): void {
const delta: Vec2 = e.getDelta();
const axis: Vec3 = v3(-delta.y, delta.x, 0); //旋转轴,根据相似三角形求出
const rad: number = delta.length() * 1e-2; //旋转角度
this.tempQuat = this.player.getRotation(); //当前的四元数
Quat.rotateAround(this.rotationQuat, this.tempQuat, axis.normalize(), rad); //当面的四元数绕旋转轴旋转
this.player.setRotation(this.rotationQuat);
}
private touchAroundRotation(e: EventTouch): void {
const delta: Vec2 = e.getDelta();
// 绕轴转
// 这里选取轴朝上
const axis2: Vec3 = Vec3.UP;//旋转轴: Y
const rad2: number = 1e-2 * delta.x; //旋转角度
// 计算坐标
const point: Vec3 = this.cube.worldPosition; //旋转点
const pointNow: Vec3 = this.player.worldPosition; // 当前点的位置
// 算出坐标点的旋转四元数
Quat.fromAxisAngle(this.tempQuat, axis2, rad2);//在zx轴上的旋转量
// 计算旋转点和现有点的向量
Vec3.subtract(this.tempV3, pointNow, point);//pointNow - point , cube -> player
// 计算旋转后的向量
Vec3.transformQuat(this.tempV3, this.tempV3, this.tempQuat);
// 计算旋转后的点
Vec3.add(this.tempV3, point, this.tempV3);//point + this.tempV3
this.player.setWorldPosition(this.tempV3);
// 计算朝向
// 这么旋转会按原始的朝向一起旋转
const quatNow: Quat = this.player.worldRotation;
Quat.rotateAround(this.tempQuat, quatNow, axis2, rad2);
Quat.normalize(this.tempQuat, this.tempQuat);
this.player.setWorldRotation(this.tempQuat);
}
//做一个动画的缓动
protected update(dt: number): void {
if (!this.isSlerp) return;
this.timerMs += dt * 1000;
const ratio: number = this.timerMs / this.durationMs;
if (ratio < 1) {
//先快后慢, 使用球面插值,不然在旋转的时候会出现变形
this.tempQuat.set(this.player.worldRotation).slerp(this.rotationQuat, ratio);
} else {
this.tempQuat = this.rotationQuat;
this.isSlerp = false;
}
this.player.setWorldRotation(this.tempQuat);
}
}
脚本字段赋值: