| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- import { _decorator, Component, Node, Vec3, tween, find, Camera } from 'cc';
- const { ccclass, property } = _decorator;
- /**
- * 画面震动管理器
- * 负责管理整个游戏画面的震动效果
- */
- export class ScreenShakeManager {
- private static instance: ScreenShakeManager = null;
-
- // 相机节点
- private cameraNode: Node = null;
-
- // 震动相关属性
- private originalCameraPosition: Vec3 = new Vec3();
- private isShaking: boolean = false;
- private currentShakeTween: any = null;
-
- // 震动设置
- private vibrationEnabled: boolean = true;
-
- private constructor() {
- // 私有构造函数,确保单例模式
- }
-
- /**
- * 获取单例实例
- */
- public static getInstance(): ScreenShakeManager {
- if (!ScreenShakeManager.instance) {
- ScreenShakeManager.instance = new ScreenShakeManager();
- }
- return ScreenShakeManager.instance;
- }
-
- /**
- * 初始化相机节点
- * @param cameraNode 相机节点引用
- */
- public initialize(cameraNode: Node): void {
- this.cameraNode = cameraNode;
- if (this.cameraNode) {
- this.originalCameraPosition = this.cameraNode.position.clone();
- console.log('[ScreenShakeManager] 相机节点初始化完成');
- } else {
- console.warn('[ScreenShakeManager] 相机节点为空,画面震动功能将不可用');
- }
- }
-
- /**
- * 播放画面震动效果
- * @param intensity 震动强度 (像素)
- * @param duration 震动持续时间 (秒)
- * @param frequency 震动频率 (次数)
- */
- public playScreenShake(intensity: number = 10, duration: number = 0.5, frequency: number = 8): void {
- // 检查震动是否启用
- if (!this.vibrationEnabled) {
- console.log('[ScreenShakeManager] 震动已禁用,跳过画面震动');
- return;
- }
-
- // 检查相机节点是否存在
- if (!this.cameraNode) {
- console.warn('[ScreenShakeManager] 相机节点不存在,无法播放画面震动');
- return;
- }
-
- // 如果正在震动,先停止当前震动
- this.stopScreenShake();
-
- console.log(`[ScreenShakeManager] 开始画面震动 - 强度: ${intensity}, 持续时间: ${duration}s, 频率: ${frequency}`);
-
- // 标记为正在震动
- this.isShaking = true;
-
- // 保存当前位置作为原始位置
- this.originalCameraPosition = this.cameraNode.position.clone();
-
- // 创建震动序列
- let shakeTween = tween(this.cameraNode);
- const singleShakeTime = duration / frequency;
-
- for (let i = 0; i < frequency; i++) {
- // 计算震动强度衰减
- const currentIntensity = intensity * (1 - i / frequency);
-
- // 随机方向震动
- const randomAngle = Math.random() * Math.PI * 2;
- const offsetX = Math.cos(randomAngle) * currentIntensity;
- const offsetY = Math.sin(randomAngle) * currentIntensity;
-
- const targetPosition = this.originalCameraPosition.clone();
- targetPosition.x += offsetX;
- targetPosition.y += offsetY;
-
- shakeTween = shakeTween.to(singleShakeTime, {
- position: targetPosition
- }, {
- easing: 'sineInOut'
- });
- }
-
- // 最后回到原始位置
- shakeTween = shakeTween.to(singleShakeTime * 0.5, {
- position: this.originalCameraPosition
- }, {
- easing: 'sineOut'
- }).call(() => {
- this.isShaking = false;
- this.currentShakeTween = null;
- console.log('[ScreenShakeManager] 画面震动结束');
- });
-
- this.currentShakeTween = shakeTween;
- this.currentShakeTween.start();
- }
-
- /**
- * 停止画面震动
- */
- public stopScreenShake(): void {
- if (this.currentShakeTween) {
- this.currentShakeTween.stop();
- this.currentShakeTween = null;
- }
-
- if (this.isShaking && this.cameraNode) {
- // 立即回到原始位置
- this.cameraNode.position = this.originalCameraPosition.clone();
- this.isShaking = false;
- console.log('[ScreenShakeManager] 画面震动已停止');
- }
- }
-
- /**
- * 检查是否正在震动
- */
- public isScreenShaking(): boolean {
- return this.isShaking;
- }
-
- /**
- * 设置震动启用状态
- */
- public setVibrationEnabled(enabled: boolean): void {
- this.vibrationEnabled = enabled;
- console.log(`[ScreenShakeManager] 震动设置: ${enabled ? '启用' : '禁用'}`);
-
- // 如果禁用震动且正在震动,立即停止
- if (!enabled && this.isShaking) {
- this.stopScreenShake();
- }
- }
-
- /**
- * 获取震动启用状态
- */
- public getVibrationEnabled(): boolean {
- return this.vibrationEnabled;
- }
-
- /**
- * 播放轻微震动(用于普通攻击)
- */
- public playLightShake(): void {
- this.playScreenShake(6, 0.3, 6);
- }
-
- /**
- * 播放中等震动(用于重击)
- */
- public playMediumShake(): void {
- this.playScreenShake(10, 0.5, 8);
- }
-
- /**
- * 播放强烈震动(用于爆炸或特殊攻击)
- */
- public playHeavyShake(): void {
- this.playScreenShake(15, 0.8, 12);
- }
-
- /**
- * 根据攻击类型播放对应的震动效果
- */
- public playShakeByAttackType(attackType: string, intensity?: number): void {
- switch (attackType.toLowerCase()) {
- case 'light':
- case 'normal':
- case 'melee':
- this.playLightShake();
- break;
- case 'heavy':
- case 'strong':
- this.playMediumShake();
- break;
- case 'explosive':
- case 'critical':
- case 'special':
- this.playHeavyShake();
- break;
- default:
- // 如果指定了强度,使用自定义震动
- if (intensity !== undefined) {
- this.playScreenShake(intensity, 0.5, 8);
- } else {
- this.playLightShake();
- }
- break;
- }
- }
-
- onDestroy() {
- // 清理震动效果
- this.stopScreenShake();
-
- // 清除单例引用
- if (ScreenShakeManager.instance === this) {
- ScreenShakeManager.instance = null;
- }
- }
- }
|