/** * 埋点管理器 - 负责游戏内事件追踪和数据上报 */ // 事件属性类型定义 export interface EventProperties { [key: string]: string | number | boolean; } // 小程序生命周期事件属性 export interface MPLifecycleProperties { scene?: number; // 场景值 query?: string; // 启动参数 shareTicket?: string; // 分享票据 referrerInfo?: any; // 来源信息 } // 场景加载事件属性 export interface SceneLoadProperties { scene_name: string; // 场景名称 load_time?: number; // 加载时长(ms) success: boolean; // 是否成功 error_msg?: string; // 错误信息 } // 游戏进度事件属性 export interface GameProgressProperties { level?: number; // 关卡等级 score?: number; // 分数 time_spent?: number; // 耗时(秒) result?: string; // 结果 } // 方块合成事件属性 export interface BlockMergeProperties extends EventProperties { merge_level: number; // 合成等级 (2, 3, 4) weapon_type?: string; // 武器类型 shape_type?: string; // 形状类型 session_id?: string; // 会话ID } // 游戏失败事件属性 export interface GameFailureProperties extends EventProperties { $event_duration: number; // 停留时长(秒) $section_id: number; // 关卡id $section_name: string; // 关卡名称 $section_type: string; // 关卡类型 (0=主线关卡,1=活动关卡,2=挑战关卡,3=支线关卡) } // 商店打开事件属性 export interface OpenShopProperties extends EventProperties { shop_type?: string; // 商店类型 entry_point?: string; // 进入商店的入口点 user_level?: number; // 用户等级 user_money?: number; // 用户金币数量 user_diamonds?: number; // 用户钻石数量 } // 小程序分享事件属性 export interface MPShareProperties extends EventProperties { share_type?: string; // 分享类型 (game_result, achievement, invite) share_content?: string; // 分享内容描述 share_target?: string; // 分享目标 (friend, group, timeline) level?: number; // 当前关卡 score?: number; // 当前分数 user_level?: number; // 用户等级 } // 查看商城内容事件属性 export interface ViewMallContentProperties extends EventProperties { content_type?: string; // 内容类型 (weapon, skill, decoration) content_id?: string; // 内容ID content_name?: string; // 内容名称 price?: number; // 价格 currency_type?: string; // 货币类型 (coin, diamond) user_money?: number; // 用户当前金币 user_diamonds?: number; // 用户当前钻石 view_duration?: number; // 查看时长(秒) } // 用户首次注册事件属性 export interface UserFirstRegisterProperties extends EventProperties { register_time?: number; // 注册时间戳 channel?: string; // 注册渠道(如 wechat_game, web) scene?: number; // 启动场景值 query?: string; // 启动参数 } // 小程序注册事件属性 export interface MPRegisterProperties extends EventProperties { register_time?: number; // 注册时间戳 scene?: number; // 启动场景值 query?: string; // 启动参数 } // 小程序登录事件属性 export interface MPLoginProperties extends EventProperties { login_time?: number; // 登录时间戳 scene?: number; // 启动场景值 query?: string; // 启动参数 } // 小程序登出事件属性 export interface MPLogoutProperties extends EventProperties { logout_time?: number; // 登出时间戳 scene?: number; // 场景值 } // 创建角色事件属性 export interface CreateRoleProperties extends EventProperties { role_id: string; // 角色ID role_name?: string; // 角色名称 role_class?: string; // 角色职业/类型 create_time?: number; // 创建时间戳 user_level?: number; // 用户等级 } // 广告展示事件属性 export interface AdShowProperties extends EventProperties { ad_type?: string; // 广告类型 (rewarded_video, banner, interstitial) ad_placement?: string; // 广告位置 (shop_reward, level_reward, extra_coins) ad_source?: string; // 广告来源 reward_type?: string; // 奖励类型 (coins, diamonds, items) reward_amount?: number; // 奖励数量 user_level?: number; // 用户等级 show_result?: string; // 展示结果 (success, failed, closed) } // 小程序添加收藏事件属性 export interface MPAddFavoritesProperties extends EventProperties { favorite_type?: string; // 收藏类型 (game, achievement, score) trigger_point?: string; // 触发点 (game_end, achievement_unlock, manual) user_level?: number; // 用户等级 game_progress?: number; // 游戏进度百分比 } // 方块选择点击事件属性 export interface BlockSelectionClickProperties extends EventProperties { button_type: string; // 按钮类型 (add_ball, add_coin, refresh_block) button_cost?: number; // 按钮费用 user_money?: number; // 用户当前金币数量 user_level?: number; // 用户等级 usage_count?: number; // 该按钮的使用次数 success: boolean; // 操作是否成功 failure_reason?: string; // 失败原因(如金币不足) } // 开始关卡事件属性 export interface StartSectionProperties extends EventProperties { $section_id: number; // 关卡ID $section_name: string; // 关卡名称 $section_type: string; // 关卡类型 (0=主线关卡,1=活动关卡,2=挑战关卡,3=支线关卡) total_waves?: number; // 总波次数 total_enemies?: number; // 总敌人数量 energy_max?: number; // 初始最大能量值 user_level?: number; // 用户等级 user_money?: number; // 用户当前金币数量 background_image?: string; // 背景图片 } /** * 埋点管理器单例类 */ export class AnalyticsManager { private static instance: AnalyticsManager; private isEnabled: boolean = true; private sessionId: string; private userId: string; private deviceInfo: any = {}; private constructor() { this.sessionId = this.generateSessionId(); this.userId = this.getUserId(); this.initDeviceInfo(); } /** * 获取单例实例 */ public static getInstance(): AnalyticsManager { if (!AnalyticsManager.instance) { AnalyticsManager.instance = new AnalyticsManager(); } return AnalyticsManager.instance; } /** * 初始化埋点管理器 */ public init(): void { console.log('[AnalyticsManager] 埋点管理器初始化完成'); console.log('[AnalyticsManager] SessionId:', this.sessionId); console.log('[AnalyticsManager] UserId:', this.userId); } /** * 设置埋点开关 */ public setEnabled(enabled: boolean): void { this.isEnabled = enabled; console.log('[AnalyticsManager] 埋点功能', enabled ? '已启用' : '已禁用'); } /** * 发送事件 */ public track(eventName: string, properties: EventProperties = {}): void { if (!this.isEnabled) { return; } const eventData = { event_name: eventName, timestamp: Date.now(), session_id: this.sessionId, user_id: this.userId, device_info: this.deviceInfo, properties: properties }; // 输出到控制台(实际项目中应该发送到服务器) console.log('[AnalyticsManager] 事件追踪:', JSON.stringify(eventData, null, 2)); // 这里可以集成第三方埋点SDK,如: // - 微信小游戏数据助手 // - TalkingData // - 友盟统计 // - 自定义服务器接口 this.sendToServer(eventData); } // ==================== 小程序生命周期事件 ==================== /** * 小程序启动事件 */ public trackMPLaunch(properties: MPLifecycleProperties = {}): void { this.track('$MPLaunch', { scene: properties.scene || 0, query: properties.query || '', shareTicket: properties.shareTicket || '', referrerInfo: JSON.stringify(properties.referrerInfo || {}), ...properties }); } /** * 小程序显示事件 */ public trackMPShow(properties: MPLifecycleProperties = {}): void { this.track('$MPShow', { scene: properties.scene || 0, query: properties.query || '', ...properties }); } /** * 小程序隐藏事件 */ public trackMPHide(): void { this.track('$MPHide', { hide_time: Date.now() }); } // ==================== 场景加载事件 ==================== /** * 场景加载开始事件 */ public trackSceneLoadStart(sceneName: string): void { this.track('$SceneLoadStart', { scene_name: sceneName, start_time: Date.now() }); } /** * 场景加载完成事件 */ public trackSceneLoaded(properties: SceneLoadProperties): void { this.track('$SceneLoaded', { scene_name: properties.scene_name, load_time: properties.load_time || 0, success: properties.success, error_msg: properties.error_msg || '', ...properties }); } /** * 场景卸载事件 */ public trackSceneUnloaded(sceneName: string): void { this.track('$SceneUnloaded', { scene_name: sceneName, unload_time: Date.now() }); } // ==================== 游戏进度事件 ==================== /** * 完成关卡事件 */ public trackCompleteSection(properties: GameProgressProperties): void { this.track('$CompleteSection', { level: properties.level || 1, score: properties.score || 0, time_spent: properties.time_spent || 0, result: properties.result || 'success', ...properties }); } /** * 等级提升事件 */ public trackUpdateLevel(oldLevel: number, newLevel: number): void { this.track('$UpdateLevel', { old_level: oldLevel, new_level: newLevel, level_diff: newLevel - oldLevel }); } // ==================== 新手引导事件 ==================== /** * 新手引导开始事件 */ public trackTutorialStart(): void { this.track('$TutorialStart', { start_time: Date.now() }); } /** * 新手引导完成事件 */ public trackTutorialFinish(timeSpent: number): void { this.track('$TutorialFinish', { time_spent: timeSpent, finish_time: Date.now() }); } // ==================== 方块合成事件 ==================== /** * 追踪方块合成等级达成事件 * @param mergeLevel 合成等级 (2, 3, 4) * @param weaponType 武器类型 * @param shapeType 形状类型 */ public trackBlockMergeLevel(mergeLevel: number, weaponType?: string, shapeType?: string): void { if (mergeLevel < 2 || mergeLevel > 4) { console.warn(`[Analytics] Invalid merge level: ${mergeLevel}. Only levels 2-4 are tracked.`); return; } const properties: BlockMergeProperties = { merge_level: mergeLevel, session_id: this.sessionId }; if (weaponType) { properties.weapon_type = weaponType; } if (shapeType) { properties.shape_type = shapeType; } // 上报合成等级达成事件 this.track('$block_merge', properties); console.log(`[Analytics] Block merge level ${mergeLevel} achieved:`, properties); } /** * 追踪方块合成等级2达成 */ public trackMergeLevel2(weaponType?: string, shapeType?: string): void { this.trackBlockMergeLevel(2, weaponType, shapeType); } /** * 追踪方块合成等级3达成 */ public trackMergeLevel3(weaponType?: string, shapeType?: string): void { this.trackBlockMergeLevel(3, weaponType, shapeType); } /** * 追踪方块合成等级4达成 */ public trackMergeLevel4(weaponType?: string, shapeType?: string): void { this.trackBlockMergeLevel(4, weaponType, shapeType); } /** * 追踪游戏失败事件(墙体摧毁) */ public trackGameFailure(properties: GameFailureProperties): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $GameFailure 事件'); return; } console.log('[AnalyticsManager] 追踪游戏失败事件:', properties); this.track('$GameFailure', properties); } /** * 追踪商店打开事件 */ public trackOpenShop(properties: OpenShopProperties = {}): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $OpenShop 事件'); return; } console.log('[AnalyticsManager] 追踪商店打开事件:', properties); this.track('$OpenShop', properties); } /** * 追踪方块选择点击事件 */ public trackBlockSelectionClick(properties: BlockSelectionClickProperties): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $block_selection_click 事件'); return; } console.log('[AnalyticsManager] 追踪方块选择点击事件:', properties); this.track('$block_selection_click', properties); } /** * 追踪开始关卡事件 */ public trackStartSection(properties: StartSectionProperties): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $StartSection 事件'); return; } console.log('[AnalyticsManager] 追踪开始关卡事件:', properties); this.track('$StartSection', properties); } // ==================== 小程序分享事件 ==================== /** * 追踪小程序分享事件 */ public trackMPShare(properties: MPShareProperties = {}): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $MPShare 事件'); return; } console.log('[AnalyticsManager] 追踪小程序分享事件:', properties); this.track('$MPShare', properties); } // ==================== 商城内容查看事件 ==================== /** * 追踪查看商城内容事件 */ public trackViewMallContent(properties: ViewMallContentProperties = {}): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $ViewMallContent 事件'); return; } console.log('[AnalyticsManager] 追踪查看商城内容事件:', properties); this.track('$ViewMallContent', properties); } // ==================== 广告展示事件 ==================== /** * 追踪广告展示事件 */ public trackAdShow(properties: AdShowProperties = {}): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $AdShow 事件'); return; } console.log('[AnalyticsManager] 追踪广告展示事件:', properties); this.track('$AdShow', properties); } // ==================== 小程序添加收藏事件 ==================== /** * 追踪小程序添加收藏事件 */ public trackMPAddFavorites(properties: MPAddFavoritesProperties = {}): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $MPAddFavorites 事件'); return; } console.log('[AnalyticsManager] 追踪小程序添加收藏事件:', properties); this.track('$MPAddFavorites', properties); } // ==================== 用户注册与账号事件 ==================== /** * 追踪用户首次注册事件 */ public trackUserFirstRegister(properties: UserFirstRegisterProperties = {}): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $UserFirstRegister 事件'); return; } const payload = { register_time: properties.register_time || Date.now(), channel: properties.channel || (typeof wx !== 'undefined' ? 'wechat_game' : 'web'), scene: properties.scene || 0, query: properties.query || '', ...properties }; console.log('[AnalyticsManager] 追踪用户首次注册事件:', payload); this.track('$UserFirstRegister', payload); } /** * 追踪小程序注册事件 */ public trackMPRegister(properties: MPRegisterProperties = {}): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $MPRegister 事件'); return; } const payload = { register_time: properties.register_time || Date.now(), scene: properties.scene || 0, query: properties.query || '', ...properties }; console.log('[AnalyticsManager] 追踪小程序注册事件:', payload); this.track('$MPRegister', payload); } /** * 追踪小程序登录事件 */ public trackMPLogin(properties: MPLoginProperties = {}): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $MPLogin 事件'); return; } const payload = { login_time: properties.login_time || Date.now(), scene: properties.scene || 0, query: properties.query || '', ...properties }; console.log('[AnalyticsManager] 追踪小程序登录事件:', payload); this.track('$MPLogin', payload); } /** * 追踪小程序登出事件 */ public trackMPLogout(properties: MPLogoutProperties = {}): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $MPLogout 事件'); return; } const payload = { logout_time: properties.logout_time || Date.now(), scene: properties.scene || 0, ...properties }; console.log('[AnalyticsManager] 追踪小程序登出事件:', payload); this.track('$MPLogout', payload); } /** * 追踪创建角色事件 */ public trackCreateRole(properties: CreateRoleProperties): void { if (!this.isEnabled) { console.log('[AnalyticsManager] 埋点已禁用,跳过 $CreateRole 事件'); return; } const payload = { role_id: properties.role_id, role_name: properties.role_name || '', role_class: properties.role_class || '', create_time: properties.create_time || Date.now(), user_level: properties.user_level || 1, ...properties }; console.log('[AnalyticsManager] 追踪创建角色事件:', payload); this.track('$CreateRole', payload); } // ==================== 私有方法 ==================== /** * 生成会话ID */ private generateSessionId(): string { return 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); } /** * 获取用户ID */ private getUserId(): string { const storage: any = (globalThis as any).localStorage; const wxAny: any = (globalThis as any).wx; let userId: string | null = null; try { if (storage && typeof storage.getItem === 'function') { userId = storage.getItem('analytics_user_id'); } else if (wxAny && typeof wxAny.getStorageSync === 'function') { userId = wxAny.getStorageSync('analytics_user_id') || null; } } catch { // ignore storage errors } if (!userId) { userId = 'user_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); try { if (storage && typeof storage.setItem === 'function') { storage.setItem('analytics_user_id', userId); } else if (wxAny && typeof wxAny.setStorageSync === 'function') { wxAny.setStorageSync('analytics_user_id', userId); } } catch { // ignore storage errors } } return userId; } /** * 初始化设备信息 */ private initDeviceInfo(): void { const safeNavigator: any = (globalThis as any).navigator || {}; const safeScreen: any = (globalThis as any).screen || {}; const wxAny: any = (globalThis as any).wx; // 优先使用微信小游戏的系统信息,无需时区字段 if (wxAny && typeof wxAny.getSystemInfoSync === 'function') { const sys = wxAny.getSystemInfoSync(); this.deviceInfo = { platform: 'wechat_game', user_agent: safeNavigator.userAgent || 'wechat_game', screen_width: sys.screenWidth ?? safeScreen.width ?? 0, screen_height: sys.screenHeight ?? safeScreen.height ?? 0, language: sys.language || safeNavigator.language || 'zh_CN', brand: sys.brand, model: sys.model, system: sys.system, version: sys.version, pixelRatio: sys.pixelRatio }; } else { // Web 环境的基础设备信息,移除时区字段以避免 Intl 依赖 this.deviceInfo = { platform: 'web', user_agent: safeNavigator.userAgent || 'unknown', screen_width: safeScreen.width || 0, screen_height: safeScreen.height || 0, language: safeNavigator.language || 'en' }; } } /** * 发送数据到服务器 */ private sendToServer(eventData: any): void { // 实际项目中应该发送到服务器 // 这里只是模拟发送过程 // 示例:使用fetch发送到服务器 /* fetch('/api/analytics/track', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(eventData) }).catch(error => { console.error('[AnalyticsManager] 发送埋点数据失败:', error); }); */ // 或者集成第三方SDK // 例如:wx.reportAnalytics(eventName, eventData); } } // 导出单例实例,方便全局使用 export const Analytics = AnalyticsManager.getInstance();