squidGame/tgx-games-client/assets/module_arean/scripts/common/CameraOrbitRole.ts

121 lines
3.9 KiB
TypeScript
Raw Normal View History

2025-02-21 10:45:46 +08:00
// 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; // 需通过脚本动态设置目标节点
private lastTouchX: number = 0;
private readonly rotationSpeed: number = 0.6;
private isTouching: boolean = false;
private currentAngle: number = 0;
// 动态计算参数
private radius: number = 5; // 初始默认值,会自动修正
private heightOffset: number = 2; // 初始默认值,会自动修正
private centerOffset = v3(0, 1, 0);// 中心点Y偏移角色腰部高度
// 初始化时自动校准参数
private isInitialized: boolean = false;
start() {
this.tryInitialize();
}
// 每帧更新摄像机位置
lateUpdate() {
if (!this.isInitialized) return;
this.updateCameraPosition(true); // true表示保持当前角度
}
// 动态设置目标节点
public setTarget(node: Node) {
this.targetNode = node;
this.tryInitialize();
}
private tryInitialize() {
if (!this.targetNode || this.isInitialized) return;
// 计算机型参数与目标的相对关系
const targetWorldPos = this.targetNode.worldPosition;
const cameraWorldPos = this.node.worldPosition;
// 计算水平距离(半径)
const dx = cameraWorldPos.x - targetWorldPos.x;
const dz = cameraWorldPos.z - targetWorldPos.z;
this.radius = Math.sqrt(dx * dx + dz * dz);
// 计算起始角度(世界坐标系)
this.currentAngle = Math.atan2(dx, dz) * 180 / Math.PI;
// 计算高度差
this.heightOffset = cameraWorldPos.y - targetWorldPos.y;
this.isInitialized = true;
}
private updateCameraPosition(keepAngle: boolean = false) {
if (!this.isInitialized) return;
const targetWorldPos = this.targetNode!.worldPosition.clone()
.add(this.centerOffset);
// 计算水平坐标
const angleRad = this.currentAngle * Math.PI / 180;
const x = targetWorldPos.x + Math.sin(angleRad) * this.radius;
const z = targetWorldPos.z + Math.cos(angleRad) * this.radius;
// 设置摄像机世界坐标
this.node.worldPosition = new Vec3(
x,
targetWorldPos.y + this.heightOffset,
z
);
// 确保准确朝向目标中心点
this.node.lookAt(targetWorldPos);
}
// 触摸事件处理(保持不变)
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.lastTouchX = event.getLocationX();
}
private onTouchMove(event: EventTouch) {
if (!this.isTouching) return;
const currentTouchX = event.getLocationX();
const deltaX = currentTouchX - this.lastTouchX;
// 更新角度
this.currentAngle -= deltaX * this.rotationSpeed;
this.currentAngle = (this.currentAngle + 360) % 360;
// 立即更新摄像机位置
this.updateCameraPosition();
this.lastTouchX = currentTouchX;
}
private onTouchEnd() {
this.isTouching = false;
}
}