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.
- package/drscript/Define.ts +21 -1
- package/drscript/KeyAdapter.ts +11 -0
- package/drscript/PlatformAdapter.ts +31 -73
- package/drscript/PlatformUtil.ts +30 -0
- package/drscript/README.md +1 -7
- package/drscript/UIAdapter.ts +99 -105
- package/drscript/ad-sdk/reporters/reporter.js +1 -1
- package/drscript/component/BtnExtra.ts +4 -11
- package/drscript/focus/FocusManager.ts +167 -170
- package/drscript/focus/FocusVisualLayer.ts +124 -94
- package/drscript/virtualgamepad/VirtualGamepad.ts +638 -0
- package/drscript/virtualgamepad/VirtualGamepadView.ts +311 -280
- package/package.json +1 -1
- package/drscript/focus/FocusItem.ts +0 -39
- package/drscript/focus/FocusItem.ts.meta +0 -10
- package/drscript/focus/FocusScope.ts +0 -10
- package/drscript/focus/FocusScope.ts.meta +0 -10
- package/drscript/virtualgamepad/VirtualGamepadClient.ts +0 -214
- package/drscript/virtualgamepad/VirtualGamepadConfig.ts +0 -70
- package/drscript/virtualgamepad/VirtualGamepadManager.ts +0 -809
package/drscript/Define.ts
CHANGED
|
@@ -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
|
+
}
|
package/drscript/KeyAdapter.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
39
|
+
this.focus.setFocusStyle(focusIcon);
|
|
33
40
|
UIAdapter._zhName = cnName;
|
|
34
|
-
UIAdapter.
|
|
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
|
-
|
|
75
|
+
private static get isCocos() { return window['cc'] != undefined; }
|
|
80
76
|
/** 是否基座环境 */
|
|
81
|
-
public static get isWebBridge() { return
|
|
77
|
+
public static get isWebBridge() { return this.webBridge.isAvailable(); }
|
|
82
78
|
/** 是否可以观看视频 */
|
|
83
|
-
|
|
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
|
-
|
|
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
|
-
|
|
169
|
+
this.focus.focus(button);
|
|
186
170
|
}
|
|
187
171
|
|
|
188
|
-
/** 导航到指定按钮 */
|
|
189
172
|
public static focusButton(btn: cc.Node) {
|
|
190
|
-
|
|
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
|
+
}
|
package/drscript/README.md
CHANGED
|
@@ -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 外部回调
|