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

121 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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;
}
}