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

198 lines
5.0 KiB
TypeScript

import { _decorator, Component, Camera, Vec3, Quat, tween, Node, EventTarget } from 'cc';
const { ccclass, property } = _decorator;
// 自定义事件
const cameraEvent = new EventTarget();
// 运镜基础类型
enum CameraMoveType {
LINEAR,
BEZIER,
ORBIT
}
// 运镜配置接口
@ccclass('CameraShotConfig')
class CameraShotConfig {
@property({ type: Camera })
targetCamera: Camera = null;
@property(Node)
followTarget: Node = null;
@property(Vec3)
offset = new Vec3(0, 2, -5);
@property(Node)
lookAtTarget: Node = null;
@property
blendTime: number = 1.0;
@property
holdTime: number = 2.0;
@property
enableShake: boolean = false;
@property
shakeIntensity: number = 0.1;
}
// 运镜配置
class CameraTransitionManager {
@property({ type: Camera })
targetCamera: Camera = null;
@property
blendTime: number = 1.0;
@property
holdTime: number = 2.0;
@property(Node)
followTarget: Node = null;
@property(Vec3)
offset = new Vec3(0, 2, -5);
@property
fov: number = 60;
@property
lookAtTarget: Node = null;
@property
enableShake: boolean = false;
@property
shakeIntensity: number = 0.1;
}
@ccclass('CameraRigSystem')
export class CameraRigSystem extends Component {
@property({ type: Camera })
defaultCamera: Camera = null;
@property([CameraShotConfig])
shotSequence: CameraShotConfig[] = [];
private currentCamera: Camera = null;
private isTransitioning = false;
start() {
this.initializeCameras();
this.playSequence();
}
// 初始化所有相机
private initializeCameras() {
this.shotSequence.forEach(config => {
if (config.targetCamera) {
config.targetCamera.node.active = false;
}
});
this.defaultCamera.node.active = true;
this.currentCamera = this.defaultCamera;
}
// 播放运镜序列
public async playSequence() {
for (const shot of this.shotSequence) {
await this.executeShot(shot);
}
this.returnToDefault();
}
// 执行单个运镜镜头
private async executeShot(config: CameraShotConfig): Promise<void> {
return new Promise((resolve) => {
if (!config.targetCamera) {
console.warn("Missing target camera in shot config");
resolve();
return;
}
// 准备新相机
const newCamera = config.targetCamera;
newCamera.node.active = true;
// 相机跟随逻辑
if (config.followTarget) {
this.setupFollowCamera(newCamera.node, config);
}
// 运镜过渡
this.blendCameras(this.currentCamera, newCamera, config.blendTime);
// 相机震动
if (config.enableShake) {
this.addCameraShake(newCamera.node, config.shakeIntensity);
}
// 保持时间
setTimeout(() => {
this.currentCamera = newCamera;
resolve();
}, config.holdTime * 1000);
});
}
// 相机混合过渡
private blendCameras(from: Camera, to: Camera, duration: number) {
// 使用权重混合(需要自定义渲染逻辑或使用后期处理)
// 此处使用简单激活切换 + 动画过渡
tween(from.node)
.to(duration/2, { position: to.node.position })
.start();
tween(to.node)
.to(duration, { position: to.node.position })
.call(() => {
from.node.active = false;
})
.start();
}
// 设置跟随相机
private setupFollowCamera(cameraNode: Node, config: CameraShotConfig) {
const updateFollow = () => {
if (!config.followTarget) return;
const targetPos = config.followTarget.worldPosition;
const offset = config.offset;
cameraNode.worldPosition = new Vec3(
targetPos.x + offset.x,
targetPos.y + offset.y,
targetPos.z + offset.z
);
if (config.lookAtTarget) {
cameraNode.lookAt(config.lookAtTarget.worldPosition);
}
};
cameraNode.on(Node.EventType.TRANSFORM_CHANGED, updateFollow);
}
// 添加相机震动
private addCameraShake(cameraNode: Node, intensity: number) {
const originalPos = cameraNode.position.clone();
let shakeTimer = 0;
const updateShake = (dt: number) => {
shakeTimer += dt;
const x = originalPos.x + Math.sin(shakeTimer * 30) * intensity;
const y = originalPos.y + Math.cos(shakeTimer * 25) * intensity;
cameraNode.setPosition(x, y, originalPos.z);
};
this.schedule(updateShake);
}
// 返回默认相机
private returnToDefault() {
this.blendCameras(this.currentCamera, this.defaultCamera, 1.0);
}
}