drgame-cc 1.0.50 → 1.0.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,4 +48,24 @@ export const AnalyticsEventMap: Record<AnalyticsEvent, { ep: string; expose: str
48
48
  [AnalyticsEvent.WatchVideoContinueButton]: { ep: "watch_video_continue_button", expose: "watch_video_continue_expose", click: "watch_video_continue_click" },
49
49
  [AnalyticsEvent.ReplayButton]: { ep: "replay_button", expose: "replay_expose", click: "replay_click" },
50
50
  [AnalyticsEvent.RewardVideoAd]: { ep: "reward_video_ad", expose: "ad_expose" },
51
- };
51
+ };
52
+
53
+ /** 奖励模式 */
54
+ export enum AwardModel {
55
+ /** 视频奖励 */
56
+ Video = "video",
57
+ /** 免费 */
58
+ Free = "free",
59
+ /** 付费时间限制 */
60
+ TimeLimit = "time_limit",
61
+ }
62
+
63
+ /** 渠道类型 */
64
+ export enum EAppItem {
65
+ /** 小米 */
66
+ Xiaomi = "25",
67
+ /** 乐窝 */
68
+ LeWo = "29",
69
+ /** 咪咕 */
70
+ Migu = "30",
71
+ }
@@ -6,6 +6,14 @@ export class KeyAdapter {
6
6
  private static keyHandler: ((event: { key: KeyCode, action: KeyAction }) => void) | null = null;
7
7
  private static keyboardBound: boolean = false;
8
8
 
9
+ /** 虚拟手柄模式:激活时忽略键盘/遥控器/AdSdk 输入 */
10
+ private static _virtualGamepadActive: boolean = false;
11
+
12
+ /** 设置虚拟手柄模式,连接时自动禁用键盘/遥控器输入 */
13
+ public static setVirtualGamepadMode(active: boolean) {
14
+ KeyAdapter._virtualGamepadActive = active;
15
+ }
16
+
9
17
  /** 防重复:记录上次处理的按键,同一按键在 150ms 内忽略重复 */
10
18
  private static lastKey: string = "";
11
19
  private static lastAction: string = "";
@@ -70,16 +78,19 @@ export class KeyAdapter {
70
78
  }
71
79
 
72
80
  private static onKeyboardDown(event: cc.Event.EventKeyboard) {
81
+ if (KeyAdapter._virtualGamepadActive) return;
73
82
  const key = KeyAdapter.KEYBOARD_MAP[event.keyCode];
74
83
  if (key) KeyAdapter.dispatchKey(key, KeyAction.Down);
75
84
  }
76
85
 
77
86
  private static onKeyboardUp(event: cc.Event.EventKeyboard) {
87
+ if (KeyAdapter._virtualGamepadActive) return;
78
88
  const key = KeyAdapter.KEYBOARD_MAP[event.keyCode];
79
89
  if (key) KeyAdapter.dispatchKey(key, KeyAction.Up);
80
90
  }
81
91
 
82
92
  private static dispatchKey(key: KeyCode, action: KeyAction) {
93
+ if (KeyAdapter._virtualGamepadActive) return;
83
94
  // console.log(`[KeyAdapter] dispatchKey: ${key}, action: ${action}`);
84
95
  // 防重复:同一按键+动作在 150ms 内重复触发则不处理
85
96
  let now = Date.now();
@@ -1,11 +1,10 @@
1
1
  import { AdEvent, AdPlatform, AdSdk, AdType, ActionType, Reporter } from "./ad-sdk/ad-sdk";
2
- import { BtnExtra } from "./component/BtnExtra";
2
+ import BtnExtra from "./component/BtnExtra";
3
3
  import HelperWin from "./component/HelperWin";
4
- import { AnalyticsAction, AnalyticsEvent, AnalyticsEventMap, EVideoScene, FingerStyle } from "./Define";
5
- import FocusVisualLayer from "./focus/FocusVisualLayer";
4
+ import { AnalyticsAction, AnalyticsEvent, AnalyticsEventMap, AwardModel, EAppItem, EVideoScene, FingerStyle } from "./Define";
6
5
  import { Loader } from "./Loader";
6
+ import { PlatformUtil } from "./PlatformUtil";
7
7
  import { UIAdapter } from "./UIAdapter";
8
- import { WebBridge } from "./WebBridge";
9
8
 
10
9
  /** 平台适配器,公共 API 入口 */
11
10
  export class PlatformAdapter {
@@ -15,6 +14,10 @@ export class PlatformAdapter {
15
14
  public static back = UIAdapter.back;
16
15
  /** WebBridge */
17
16
  public static get webBridge() { return UIAdapter.webBridge; }
17
+ /** 渠道类型 */
18
+ private static appItem: EAppItem = EAppItem.Xiaomi;
19
+ /** 是否是会员 */
20
+ private static isVIP: boolean = false;
18
21
 
19
22
  private static contentId: string = "";
20
23
 
@@ -28,20 +31,16 @@ export class PlatformAdapter {
28
31
  * @param focusIcon 焦点的样式
29
32
  */
30
33
  public static async init(cnName: string, minigameID: number, focusIcon: FingerStyle) {
34
+ // ── 初始化渠道类型 ──
35
+ this.appItem = PlatformUtil.getUrlParam('appItem') as EAppItem || EAppItem.Xiaomi;
36
+ this.isVIP = PlatformUtil.getUrlParam('isVIP') === '1';
37
+
31
38
  // ── UI 初始化 ──
32
- FocusVisualLayer.setStyle(focusIcon);
39
+ this.focus.setFocusStyle(focusIcon);
33
40
  UIAdapter._zhName = cnName;
34
- UIAdapter.webBridge = new WebBridge();
35
- UIAdapter.init({ focusEnabled: true });
41
+ await UIAdapter.init();
36
42
 
37
43
  this.contentId = minigameID.toString();
38
- console.log(`[sdk-version] ${UIAdapter.version}`);
39
-
40
- // ── Cocos 环境初始化 ──
41
- if (this.isCocos) {
42
- UIAdapter.toastPool = new cc.NodePool();
43
- UIAdapter.prefab = await UIAdapter.loadPrefab('drres/prefab/Toast');
44
- }
45
44
 
46
45
  // ── 初始化广告 SDK ──
47
46
  await AdSdk.init({
@@ -65,10 +64,7 @@ export class PlatformAdapter {
65
64
  });
66
65
  }
67
66
 
68
- // ── 生命周期收尾 ──
69
67
  AdSdk.onGameReady(UIAdapter.version);
70
- UIAdapter.hookLoadScene();
71
- UIAdapter.back.setFallback(() => UIAdapter.backHandler());
72
68
  }
73
69
 
74
70
  // ========================================================================
@@ -76,18 +72,28 @@ export class PlatformAdapter {
76
72
  // ========================================================================
77
73
 
78
74
  /** 是否 Cocos 环境 */
79
- public static get isCocos() { return window['cc'] != undefined; }
75
+ private static get isCocos() { return window['cc'] != undefined; }
80
76
  /** 是否基座环境 */
81
- public static get isWebBridge() { return UIAdapter.webBridge.isAvailable(); }
77
+ public static get isWebBridge() { return this.webBridge.isAvailable(); }
82
78
  /** 是否可以观看视频 */
83
- public static get canWatchVideo() { return this.isXiaomi; }
84
- /** 是否 VIP 用户 */
85
- public static get isVIP() { return UIAdapter._isVIP; }
79
+ private static get canWatchVideo() { return this.isXiaomi; }
86
80
  /** 是否小米平台 */
87
81
  public static get isXiaomi() {
88
82
  if (typeof window === 'undefined') return null;
89
83
  return window['AppBridge'] || null;
90
84
  }
85
+ /** 是否需要观看视频 */
86
+ private static get needWatchVideo() {
87
+ return this.canWatchVideo && !this.isVIP;
88
+ }
89
+ private static get needTimeLimit() {
90
+ return !this.isVIP && this.appItem === EAppItem.Migu;
91
+ }
92
+
93
+ /** 奖励模式 */
94
+ public static get awardModel(): AwardModel {
95
+ return this.needWatchVideo ? AwardModel.Video : this.needTimeLimit ? AwardModel.TimeLimit : AwardModel.Free;
96
+ }
91
97
 
92
98
  // ========================================================================
93
99
  // Toast
@@ -101,13 +107,6 @@ export class PlatformAdapter {
101
107
  // 广告
102
108
  // ========================================================================
103
109
 
104
- /**
105
- * 显示奖励视频
106
- * @param scene 视频场景
107
- * @param rewardType 奖励类型
108
- * @param callback 回调函数
109
- * @param target 回调函数的this指向
110
- */
111
110
  public static async showRewardVideo(scene: EVideoScene, rewardType: string, callback: Function, target?: any) {
112
111
  let finishFired = false;
113
112
  let fireFinish = () => {
@@ -124,7 +123,6 @@ export class PlatformAdapter {
124
123
  };
125
124
 
126
125
  if (this.canWatchVideo) {
127
- // 监听奖励(用户完整看完广告触发)
128
126
  try {
129
127
  const result = await AdSdk.requestAd({
130
128
  adType: AdType.RewardVideo,
@@ -151,50 +149,30 @@ export class PlatformAdapter {
151
149
  // 按钮注册
152
150
  // ========================================================================
153
151
 
154
- /**
155
- * 注册按钮事件,有 BtnExtra 组件会自动切换按钮图片
156
- * @param button 按钮节点
157
- */
158
152
  public static registerButton(button: cc.Node) {
159
153
  var sprite = button.getComponent(cc.Sprite);
160
154
  var btnExtra = button.getComponent(BtnExtra);
161
155
  var onFocus = () => { sprite.spriteFrame = btnExtra.hoverSprite; };
162
156
  var onRomove = () => { sprite.spriteFrame = btnExtra.normalSprite; };
163
- UIAdapter.focus.register(button, { onFocus: onFocus, onBlur: onRomove });
157
+ this.focus.register(button, { onFocus: onFocus, onBlur: onRomove });
164
158
  }
165
159
 
166
- /**
167
- * 按名称注册按钮
168
- * @param name 按钮名称
169
- * @param parent 查找的父节点,默认场景节点
170
- */
171
160
  public static registerButtonByName(name: string, parent: cc.Node = null) {
172
161
  if (!parent) parent = cc.director.getScene();
173
162
  let button = this.findChildByName(parent, name);
174
163
  this.registerButton(button);
175
164
  }
176
165
 
177
- /**
178
- * 导航到指定名称的按钮
179
- * @param name 按钮名称
180
- * @param parent 查找的父节点,默认场景节点
181
- */
182
166
  public static focusButtonByName(name: string, parent: cc.Node = null) {
183
167
  if (!parent) parent = cc.director.getScene();
184
168
  let button = this.findChildByName(parent, name);
185
- UIAdapter.focus.focus(button);
169
+ this.focus.focus(button);
186
170
  }
187
171
 
188
- /** 导航到指定按钮 */
189
172
  public static focusButton(btn: cc.Node) {
190
- UIAdapter.focus.focus(btn);
173
+ this.focus.focus(btn);
191
174
  }
192
175
 
193
- /**
194
- * 递归查找指定名称的子节点
195
- * @param parent 父节点
196
- * @param name 子节点名称
197
- */
198
176
  public static findChildByName(parent: cc.Node, name: string): cc.Node | null {
199
177
  if (parent.name === name) return parent;
200
178
  for (let i = 0; i < parent.children.length; i++) {
@@ -208,31 +186,20 @@ export class PlatformAdapter {
208
186
  // 场景 / 窗口 栈
209
187
  // ========================================================================
210
188
 
211
- /** 显示预制体场景(压入场景栈,返回键可回溯)
212
- * @param onBack 自定义返回处理,返回 false 表示不关闭,保留当前场景
213
- */
214
189
  public static showScene(scene: cc.Node, onBack?: () => boolean | void) { UIAdapter.showScene(scene, onBack); }
215
- /** 关闭预制体场景(从栈中移除,不销毁) */
216
190
  public static hideScene(scene: cc.Node) { UIAdapter.hideScene(scene); }
217
- /** 打开界面
218
- * @param onBack 自定义返回处理,返回 false 表示不关闭,保留当前窗口
219
- */
220
191
  public static showWindow(window: cc.Node, onBack?: () => boolean | void) { UIAdapter.showWindow(window, onBack); }
221
- /** 关闭界面 */
222
192
  public static hideWindow(window: cc.Node) { UIAdapter.hideWindow(window); }
223
- /** 刷新导航按钮 */
224
193
  public static refreshFocus(window: cc.Node) { UIAdapter.refreshFocus(window); }
225
194
 
226
195
  // ========================================================================
227
196
  // 进度 / 加载
228
197
  // ========================================================================
229
198
 
230
- /** 设置启动页进度条 */
231
199
  public static setProgress(progress: number, tip: string) {
232
200
  if (window["setProgress"]) window["setProgress"](progress, tip);
233
201
  }
234
202
 
235
- /** 关闭启动页 */
236
203
  public static closeLoading() {
237
204
  if (window["closeLoading"]) window["closeLoading"]();
238
205
  }
@@ -241,12 +208,6 @@ export class PlatformAdapter {
241
208
  // 上报
242
209
  // ========================================================================
243
210
 
244
- /**
245
- * 上报事件
246
- * @param event 事件类型
247
- * @param action 操作类型,默认点击
248
- * @param adRequestId 广告请求ID
249
- */
250
211
  public static report(event: AnalyticsEvent, action: AnalyticsAction = AnalyticsAction.Click, adRequestId?: string) {
251
212
  const def = AnalyticsEventMap[event];
252
213
  if (!def) {
@@ -266,11 +227,9 @@ export class PlatformAdapter {
266
227
  if (event === AnalyticsEvent.RewardVideoAd && adRequestId) {
267
228
  reportItem.ad_request_id = adRequestId;
268
229
  }
269
- // 由 Reporter 内部队列批量上报
270
230
  Reporter.report(reportItem);
271
231
  }
272
232
 
273
- /** 批量上报事件 */
274
233
  public static reportBatch(events: AnalyticsEvent[]) {
275
234
  if (events.length === 0) return;
276
235
  const items: any[] = [];
@@ -286,7 +245,6 @@ export class PlatformAdapter {
286
245
  if (items.length > 0) Reporter.reportBatch(items);
287
246
  }
288
247
 
289
- /** 显示帮助窗口 */
290
248
  public static async showHelperWin(url: string, cb: () => void) {
291
249
  var key = `${UIAdapter._zhName}-isFirst`;
292
250
  var isFirst = cc.sys.localStorage.getItem(key);
@@ -0,0 +1,30 @@
1
+ export class PlatformUtil {
2
+ static isBrowser: boolean = cc.sys.isBrowser;
3
+ private _browserParams: Map<string, string> = new Map();
4
+
5
+ /** 获取浏览器 URL 查询参数 */
6
+ private get browserParams(): Map<string, string> {
7
+ if (this._browserParams.size > 0) return this._browserParams;
8
+
9
+ const query = window.location.search.substring(1);
10
+ const params = new Map<string, string>();
11
+ if (!query) return params;
12
+
13
+ const vars = query.split("&");
14
+ for (let i = 0; i < vars.length; i++) {
15
+ const pair = vars[i].split("=");
16
+ const key = decodeURIComponent(pair[0]);
17
+ const value = decodeURIComponent(pair[1] || "");
18
+ params.set(key, value);
19
+ }
20
+ this._browserParams = params;
21
+ return params;
22
+ }
23
+
24
+ /** 获取指定 URL 参数的值 */
25
+ static getUrlParam(key: string): string | null {
26
+ if (!PlatformUtil.isBrowser) return null;
27
+ const params = new PlatformUtil().browserParams;
28
+ return params.get(key) || null;
29
+ }
30
+ }
@@ -58,13 +58,7 @@ PlatformAdapter.showHelperWin('skeleton', () => {
58
58
  PlatformAdapter.report(AnalyticsEvent.StartGame, AnalyticsAction.Click);
59
59
  // 批量上报
60
60
  PlatformAdapter.reportBatch([AnalyticsEvent.StartGame, AnalyticsEvent.LevelComplete]);
61
- ```
62
- ### 1.8 属性
63
- ```typescript
64
- PlatformAdapter.isCocos // 是否 Cocos 环境
65
- PlatformAdapter.isWebBridge // 是否基座环境
66
- PlatformAdapter.canWatchVideo // 是否可以观看视频(小米 TV)
67
- PlatformAdapter.isVIP // 是否 VIP 用户
61
+
68
62
  ```
69
63
  ## 二、KeyAdapter 按键适配
70
64
  ### 2.1 外部回调