127 lines
4.2 KiB
TypeScript
127 lines
4.2 KiB
TypeScript
// CameraOrbit.ts
|
|
import { _decorator, Component, Node, Vec3, EventTouch, input, Input, v3 } from 'cc';
|
|
const { ccclass, property } = _decorator;
|
|
|
|
@ccclass('CameraOrbit')
|
|
export class CameraOrbit extends Component {
|
|
@property(Node)
|
|
public targetNode: Node | null = null;
|
|
|
|
@property(Vec3)
|
|
private readonly FINISH_POINT = new Vec3(0, 0, -50); // 终点位置
|
|
|
|
private radius: number = 8; // 与角色的距离
|
|
private heightOffset: number = 3; // 高度偏移
|
|
private centerOffset = v3(0, 1.5, 0); // 瞄准点高度偏移
|
|
private isInitialized: boolean = false;
|
|
|
|
private lastTouchX: number = 0;
|
|
private readonly rotationSpeed: number = 0.3;
|
|
private readonly resetSpeed: number = 0.15; // 增加回正速度
|
|
private isTouching: boolean = false;
|
|
private currentRotation: number = 0;
|
|
private isResetting: boolean = false;
|
|
|
|
start() {
|
|
this.tryInitialize();
|
|
}
|
|
|
|
onEnable() {
|
|
input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
|
|
input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
|
|
input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
|
|
input.on(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
|
|
}
|
|
|
|
onDisable() {
|
|
input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
|
|
input.off(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
|
|
input.off(Input.EventType.TOUCH_END, this.onTouchEnd, this);
|
|
input.off(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
|
|
}
|
|
|
|
private onTouchStart(event: EventTouch) {
|
|
this.isTouching = true;
|
|
this.isResetting = false;
|
|
this.lastTouchX = event.getLocationX();
|
|
}
|
|
|
|
private onTouchMove(event: EventTouch) {
|
|
if (!this.isTouching || !this.targetNode) return;
|
|
|
|
const currentTouchX = event.getLocationX();
|
|
const deltaX = currentTouchX - this.lastTouchX;
|
|
|
|
// 更新摄像机的旋转
|
|
this.currentRotation += deltaX * this.rotationSpeed;
|
|
this.currentRotation = Math.max(-90, Math.min(90, this.currentRotation)); // 限制在±90度
|
|
|
|
// 更新摄像机位置和朝向
|
|
this.updateCameraPosition();
|
|
|
|
this.lastTouchX = currentTouchX;
|
|
}
|
|
|
|
private onTouchEnd() {
|
|
this.isTouching = false;
|
|
}
|
|
|
|
lateUpdate(deltaTime: number) {
|
|
if (!this.isInitialized || !this.targetNode) return;
|
|
|
|
if (!this.isTouching && !this.isResetting) {
|
|
this.resetRotation(deltaTime);
|
|
}
|
|
|
|
this.updateCameraPosition();
|
|
}
|
|
|
|
private updateCameraPosition() {
|
|
if (!this.targetNode) return;
|
|
|
|
const targetPos = this.targetNode.worldPosition.clone().add(this.centerOffset);
|
|
|
|
// 计算摄像机位置(始终在角色后方)
|
|
const cameraPos = new Vec3(
|
|
targetPos.x, // 与角色相同的X坐标
|
|
targetPos.y + this.heightOffset, // 高度偏移
|
|
targetPos.z + this.radius // 在角色后方
|
|
);
|
|
|
|
// 根据当前旋转角度调整摄像机位置
|
|
const angle = this.currentRotation * Math.PI / 180;
|
|
const offsetX = this.radius * Math.sin(angle);
|
|
const offsetZ = this.radius * Math.cos(angle);
|
|
|
|
cameraPos.x = targetPos.x + offsetX;
|
|
cameraPos.z = targetPos.z + offsetZ;
|
|
|
|
// 设置摄像机位置和朝向
|
|
this.node.worldPosition = cameraPos;
|
|
this.node.lookAt(targetPos);
|
|
|
|
// 添加固定的俯视角度
|
|
const currentEuler = this.node.eulerAngles.clone();
|
|
this.node.eulerAngles = new Vec3(-15, currentEuler.y, 0);
|
|
}
|
|
|
|
private resetRotation(deltaTime: number) {
|
|
const resetSpeed = 0.2; // 增加回正速度
|
|
this.currentRotation *= (1 - resetSpeed);
|
|
|
|
if (Math.abs(this.currentRotation) < 0.1) {
|
|
this.currentRotation = 0;
|
|
}
|
|
}
|
|
|
|
private tryInitialize() {
|
|
if (!this.targetNode || this.isInitialized) return;
|
|
this.isInitialized = true;
|
|
|
|
// 确保角色朝向-Z方向
|
|
this.targetNode.setRotationFromEuler(0, 180, 0);
|
|
|
|
this.updateCameraPosition();
|
|
}
|
|
}
|