drgame-cc 1.0.45 → 1.0.47
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/drres/focus/focus_1/gesture.atlas +34 -0
- package/drres/focus/focus_1/gesture.atlas.meta +6 -0
- package/drres/focus/focus_1/gesture.json +1 -0
- package/drres/focus/focus_1/gesture.json.meta +10 -0
- package/drres/focus/focus_1/gesture.png +0 -0
- package/drres/{icons/pointer-yellow-60.png.meta → focus/focus_1/gesture.png.meta} +14 -14
- package/drres/focus/focus_1.meta +13 -0
- package/drres/focus/focus_2/gesture.atlas +41 -0
- package/drres/focus/focus_2/gesture.atlas.meta +6 -0
- package/drres/focus/focus_2/gesture.json +1 -0
- package/drres/focus/focus_2/gesture.json.meta +10 -0
- package/drres/focus/focus_2/gesture.png +0 -0
- package/drres/{icons/pointer-blue-60.png.meta → focus/focus_2/gesture.png.meta} +13 -13
- package/drres/focus/focus_2.meta +13 -0
- package/drres/focus/focus_3/gesture.atlas +34 -0
- package/drres/focus/focus_3/gesture.atlas.meta +6 -0
- package/drres/focus/focus_3/gesture.json +1 -0
- package/drres/focus/focus_3/gesture.json.meta +10 -0
- package/drres/focus/focus_3/gesture.png +0 -0
- package/drres/{icons/pointer-pink-60.png.meta → focus/focus_3/gesture.png.meta} +12 -12
- package/drres/focus/focus_3.meta +13 -0
- package/drres/focus/focus_4/gesture.atlas +20 -0
- package/drres/focus/focus_4/gesture.atlas.meta +6 -0
- package/drres/focus/focus_4/gesture.json +1 -0
- package/drres/focus/focus_4/gesture.json.meta +10 -0
- package/drres/focus/focus_4/gesture.png +0 -0
- package/drres/focus/focus_4/gesture.png.meta +38 -0
- package/drres/focus/focus_4.meta +13 -0
- package/drres/focus.meta +13 -0
- package/drres/prefab/ExitWin.prefab +2 -2
- package/drres/prefab/Toast.prefab +378 -378
- package/drscript/{ad/AdManager.ts.meta → BtnExtra.ts.meta} +1 -1
- package/drscript/Define.ts +17 -2
- package/drscript/{ad/AdSlot.ts.meta → Define.ts.meta} +1 -1
- package/drscript/{ad/AggregateAdProvider.ts.meta → ExitWin.ts.meta} +1 -1
- package/drscript/GameAnalytics.ts +37 -118
- package/drscript/{ad/IAdProvider.ts.meta → GameAnalytics.ts.meta} +1 -1
- package/drscript/HelperWin.ts.meta +10 -0
- package/drscript/Info.ts.meta +10 -0
- package/drscript/InternalUitl.ts.meta +10 -0
- package/drscript/KeyAdapter.ts +133 -0
- package/drscript/KeyAdapter.ts.meta +10 -0
- package/drscript/Loader.ts.meta +10 -0
- package/drscript/PlatformAdapter.ts +178 -192
- package/drscript/PlatformAdapter.ts.meta +10 -0
- package/drscript/README.md +91 -805
- package/drscript/README.md.meta +6 -0
- package/drscript/UIAdapter.ts +324 -0
- package/drscript/UIAdapter.ts.meta +10 -0
- package/drscript/WebBridge.ts +1 -1
- package/drscript/WebBridge.ts.meta +10 -0
- package/drscript/ad-sdk/reporters/superset-lewo.js +6 -0
- package/drscript/ad-sdk/types/enums.d.ts +1 -0
- package/drscript/ad-sdk.meta +13 -0
- package/drscript/ad.meta +13 -0
- package/drscript/component/AlertTip.ts +25 -0
- package/drscript/component/AlertTip.ts.meta +10 -0
- package/drscript/component/BtnExtra.ts +17 -0
- package/drscript/component/BtnExtra.ts.meta +10 -0
- package/drscript/{ExitWin.ts → component/ExitWin.ts} +6 -8
- package/drscript/component/ExitWin.ts.meta +10 -0
- package/drscript/{HelperWin.ts → component/HelperWin.ts} +5 -19
- package/drscript/component/HelperWin.ts.meta +10 -0
- package/drscript/component.meta +13 -0
- package/drscript/config.meta +13 -0
- package/drscript/core.meta +13 -0
- package/drscript/focus/FocusItem.ts +1 -19
- package/drscript/focus/FocusManager.ts +157 -198
- package/drscript/focus/FocusVisualLayer.ts +74 -163
- package/drscript/focus.meta +13 -0
- package/drscript/input/KeyboardMove.ts +40 -11
- package/drscript/input/KeyboardMove.ts.meta +10 -0
- package/drscript/input.meta +13 -0
- package/drscript/interface.meta +13 -0
- package/drscript/pinyin.meta +13 -0
- package/drscript/toast.meta +13 -0
- package/drscript/virtualgamepad.meta +13 -0
- package/package.json +1 -1
- package/drres/config/default.json +0 -108
- package/drres/config/default.json.meta +0 -6
- package/drres/icons/pointer-blue-60.png +0 -0
- package/drres/icons/pointer-pink-60.png +0 -0
- package/drres/icons/pointer-white-60.png +0 -0
- package/drres/icons/pointer-yellow-60.png +0 -0
- package/drscript/Info.ts +0 -78
- package/drscript/InternalUitl.ts +0 -65
- package/drscript/ad/AdManager.ts +0 -174
- package/drscript/ad/AdSlot.ts +0 -44
- package/drscript/ad/AggregateAdProvider.ts +0 -149
- package/drscript/ad/IAdProvider.ts +0 -39
- package/drscript/ad/MockAdProvider.ts +0 -36
- package/drscript/ad/MockAdProvider.ts.meta +0 -10
- package/drscript/ad/SelfAdProvider.ts +0 -41
- package/drscript/ad/SelfAdProvider.ts.meta +0 -10
- package/drscript/config/TvUiConfig.ts +0 -155
- package/drscript/config/TvUiConfig.ts.meta +0 -10
- package/drscript/config/TvUiConfigManager.ts +0 -133
- package/drscript/config/TvUiConfigManager.ts.meta +0 -10
- package/drscript/core/BackManager.ts +0 -38
- package/drscript/core/BackManager.ts.meta +0 -10
- package/drscript/core/NativeBridge.ts +0 -137
- package/drscript/core/NativeBridge.ts.meta +0 -10
- package/drscript/core/TvUi.ts +0 -69
- package/drscript/core/TvUi.ts.meta +0 -10
- package/drscript/core/TvUiRoot.ts +0 -137
- package/drscript/core/TvUiRoot.ts.meta +0 -10
- package/drscript/icon/IconConfig.ts +0 -7
- package/drscript/icon/IconConfig.ts.meta +0 -10
- package/drscript/icon/IconManager.ts +0 -97
- package/drscript/icon/IconManager.ts.meta +0 -10
- package/drscript/input/KeyCodeAdapter.ts +0 -23
- package/drscript/input/RemoteInputManager.ts +0 -105
- package/drscript/interface/ILobbyBridge.ts +0 -5
- package/drscript/toast/ToastComponent.ts +0 -35
- package/drscript/toast/ToastComponent.ts.meta +0 -10
- package/drscript/toast/ToastManager.ts +0 -66
- package/drscript/toast/ToastManager.ts.meta +0 -10
- package/drscript/toast/TvExitConfirmDialog.ts +0 -334
- package/drscript/toast/TvExitConfirmDialog.ts.meta +0 -10
- package/drscript/toast/UIFunctions.ts +0 -150
- package/drscript/toast/UIFunctions.ts.meta +0 -10
|
@@ -1,116 +1,73 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import KeyCodeAdapter, { TvRemoteKey } from "../input/KeyCodeAdapter";
|
|
3
|
-
import FocusScope from "./FocusScope";
|
|
4
|
-
|
|
5
|
-
export interface FocusOptions {
|
|
6
|
-
root?: cc.Node;
|
|
7
|
-
scopeId?: string;
|
|
8
|
-
focusId?: string;
|
|
9
|
-
iconKey?: string;
|
|
10
|
-
up?: string;
|
|
11
|
-
down?: string;
|
|
12
|
-
left?: string;
|
|
13
|
-
right?: string;
|
|
14
|
-
onClick?: Function;
|
|
15
|
-
onFocus?: Function;
|
|
16
|
-
onBlur?: Function;
|
|
17
|
-
focusScale?: number;
|
|
18
|
-
showCursor?: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface FocusCursorOptions {
|
|
22
|
-
basePath?: string;
|
|
23
|
-
normalPath?: string;
|
|
24
|
-
focusPath?: string;
|
|
25
|
-
corner?: string;
|
|
26
|
-
width?: number;
|
|
27
|
-
height?: number;
|
|
28
|
-
offsetX?: number;
|
|
29
|
-
offsetY?: number;
|
|
30
|
-
}
|
|
1
|
+
import { KeyCode } from "../ad-sdk/ad-sdk";
|
|
31
2
|
|
|
32
3
|
export interface FocusRuntimeItem {
|
|
33
4
|
node: cc.Node;
|
|
34
|
-
root?: cc.Node;
|
|
35
|
-
scopeId: string;
|
|
36
|
-
focusId: string;
|
|
37
|
-
iconKey?: string;
|
|
38
|
-
up?: string;
|
|
39
|
-
down?: string;
|
|
40
|
-
left?: string;
|
|
41
|
-
right?: string;
|
|
42
|
-
onClick?: Function;
|
|
43
5
|
onFocus?: Function;
|
|
44
6
|
onBlur?: Function;
|
|
45
|
-
|
|
46
|
-
baseScaleX: number;
|
|
47
|
-
baseScaleY: number;
|
|
7
|
+
onClick?: Function;
|
|
48
8
|
focusScale: number;
|
|
49
9
|
showCursor: boolean;
|
|
10
|
+
offset: cc.Vec2;
|
|
50
11
|
}
|
|
51
12
|
|
|
52
13
|
type FocusListener = (item: FocusRuntimeItem | null, previous?: FocusRuntimeItem | null) => void;
|
|
53
14
|
|
|
15
|
+
interface ScopeInfo {
|
|
16
|
+
scopeId: string;
|
|
17
|
+
lastNodeUuid: string;
|
|
18
|
+
/** 绑定的窗口/场景节点(用于返回键自动处理) */
|
|
19
|
+
node?: cc.Node;
|
|
20
|
+
/** 节点类型 */
|
|
21
|
+
nodeType?: "window" | "scene";
|
|
22
|
+
/** 自定义返回回调 */
|
|
23
|
+
onBack?: () => boolean | void;
|
|
24
|
+
}
|
|
25
|
+
|
|
54
26
|
export default class FocusManager {
|
|
55
27
|
private static readonly FOCUS_SCALE_ACTION_TAG: number = 9911;
|
|
56
28
|
private static readonly BASE_SCALE_X_KEY: string = "__tvFocusBaseScaleX";
|
|
57
29
|
private static readonly BASE_SCALE_Y_KEY: string = "__tvFocusBaseScaleY";
|
|
58
30
|
private static items: FocusRuntimeItem[] = [];
|
|
59
|
-
private static itemMap: { [
|
|
60
|
-
private static
|
|
61
|
-
private static
|
|
62
|
-
private static
|
|
31
|
+
private static itemMap: { [uuid: string]: FocusRuntimeItem } = {};
|
|
32
|
+
private static scopeMap: { [uuid: string]: string } = {};
|
|
33
|
+
private static currentNodeUuid: string = "";
|
|
34
|
+
private static scopes: ScopeInfo[] = [];
|
|
35
|
+
private static activeScopeId: string = "";
|
|
63
36
|
private static listeners: FocusListener[] = [];
|
|
64
|
-
private static cursorOptions: FocusCursorOptions | null = null;
|
|
65
37
|
|
|
66
|
-
|
|
67
|
-
this.cursorOptions = options;
|
|
68
|
-
}
|
|
38
|
+
private static readonly DEFAULT_FOCUS_SCALE = 1.08;
|
|
69
39
|
|
|
70
|
-
public static
|
|
71
|
-
return this.cursorOptions;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
public static register(target: cc.Node | any, options: FocusOptions = {}) {
|
|
40
|
+
public static register(target: cc.Node | any, options: { scopeId?: string; onFocus?: Function; onBlur?: Function; onClick?: Function; focusScale?: number; showCursor?: boolean; offset?: cc.Vec2 } = {}): void {
|
|
75
41
|
let node = this.resolveNode(target);
|
|
76
42
|
if (!node) return;
|
|
77
43
|
let component = this.resolveComponent(target, node);
|
|
78
|
-
let previousItem = this.findItemByNode(node);
|
|
79
|
-
let previousBaseScale = previousItem ? { x: previousItem.baseScaleX, y: previousItem.baseScaleY } : null;
|
|
80
44
|
this.unregister(node);
|
|
81
45
|
|
|
82
|
-
let
|
|
83
|
-
this.
|
|
84
|
-
|
|
46
|
+
let uuid = node.uuid;
|
|
47
|
+
this.getNodeBaseScale(node);
|
|
48
|
+
|
|
49
|
+
let scopeId = options.scopeId || (component && component.scopeId) || this.activeScopeId;
|
|
50
|
+
this.scopeMap[uuid] = scopeId;
|
|
85
51
|
|
|
86
52
|
let item: FocusRuntimeItem = {
|
|
87
53
|
node: node,
|
|
88
|
-
root: options.root,
|
|
89
|
-
scopeId: options.scopeId || (component && component.scopeId) || this.activeScopeId || "page",
|
|
90
|
-
focusId: focusId,
|
|
91
|
-
iconKey: options.iconKey || (component && component.iconKey) || "",
|
|
92
|
-
up: options.up || (component && component.up) || "",
|
|
93
|
-
down: options.down || (component && component.down) || "",
|
|
94
|
-
left: options.left || (component && component.left) || "",
|
|
95
|
-
right: options.right || (component && component.right) || "",
|
|
96
|
-
onClick: options.onClick,
|
|
97
54
|
onFocus: options.onFocus || (component && component.onFocus),
|
|
98
55
|
onBlur: options.onBlur || (component && component.onBlur),
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
showCursor: options.showCursor !== false
|
|
56
|
+
onClick: options.onClick,
|
|
57
|
+
focusScale: options.focusScale || (component && component.focusScale) || this.DEFAULT_FOCUS_SCALE,
|
|
58
|
+
showCursor: options.showCursor !== false,
|
|
59
|
+
offset: options.offset || cc.v2(0, 0)
|
|
104
60
|
};
|
|
105
61
|
|
|
106
62
|
this.items.push(item);
|
|
107
|
-
this.itemMap[
|
|
63
|
+
this.itemMap[uuid] = item;
|
|
108
64
|
this.ensureFocus();
|
|
109
65
|
}
|
|
110
66
|
|
|
111
67
|
public static unregister(target: cc.Node | any) {
|
|
112
68
|
let node = this.resolveNode(target);
|
|
113
69
|
if (!node) return;
|
|
70
|
+
delete this.scopeMap[node.uuid];
|
|
114
71
|
for (let i = this.items.length - 1; i >= 0; i--) {
|
|
115
72
|
if (this.items[i].node == node) {
|
|
116
73
|
this.removeItemAt(i);
|
|
@@ -123,21 +80,25 @@ export default class FocusManager {
|
|
|
123
80
|
if (!root) return;
|
|
124
81
|
for (let i = this.items.length - 1; i >= 0; i--) {
|
|
125
82
|
let item = this.items[i];
|
|
126
|
-
if (
|
|
83
|
+
if (this.isChildOf(item.node, root)) {
|
|
84
|
+
delete this.scopeMap[item.node.uuid];
|
|
127
85
|
this.removeItemAt(i);
|
|
128
86
|
}
|
|
129
87
|
}
|
|
130
88
|
this.ensureFocus();
|
|
131
89
|
}
|
|
132
90
|
|
|
133
|
-
|
|
134
|
-
if (!
|
|
91
|
+
private static unregisterByUuid(uuid: string) {
|
|
92
|
+
if (!uuid) return;
|
|
135
93
|
for (let i = this.items.length - 1; i >= 0; i--) {
|
|
136
|
-
if (this.items[i].
|
|
94
|
+
if (this.items[i].node.uuid == uuid) {
|
|
95
|
+
delete this.scopeMap[uuid];
|
|
96
|
+
this.removeItemAt(i);
|
|
97
|
+
}
|
|
137
98
|
}
|
|
138
99
|
}
|
|
139
100
|
|
|
140
|
-
public static registerButtons(root: cc.Node
|
|
101
|
+
public static registerButtons(root: cc.Node) {
|
|
141
102
|
if (!root) return;
|
|
142
103
|
this.unregisterByRoot(root);
|
|
143
104
|
this.walk(root, (node: cc.Node) => {
|
|
@@ -145,31 +106,36 @@ export default class FocusManager {
|
|
|
145
106
|
let button = node.getComponent(cc.Button);
|
|
146
107
|
if (!button) return;
|
|
147
108
|
this.register(node, {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
iconKey: options.iconKey,
|
|
151
|
-
focusScale: options.focusScale || 1.08,
|
|
109
|
+
scopeId: this.activeScopeId,
|
|
110
|
+
focusScale: this.DEFAULT_FOCUS_SCALE,
|
|
152
111
|
onClick: () => this.invokeButton(button)
|
|
153
112
|
});
|
|
154
113
|
});
|
|
114
|
+
|
|
155
115
|
this.ensureFocus();
|
|
156
116
|
}
|
|
157
117
|
|
|
158
|
-
public static pushScope(scopeId: string,
|
|
118
|
+
public static pushScope(scopeId: string, options?: { node?: cc.Node; nodeType?: "window" | "scene"; onBack?: () => boolean | void; skipEnsureFocus?: boolean }) {
|
|
159
119
|
scopeId = scopeId || "modal";
|
|
160
120
|
let currentScope = this.getActiveScope();
|
|
161
|
-
if (currentScope) currentScope.
|
|
121
|
+
if (currentScope) currentScope.lastNodeUuid = this.currentNodeUuid;
|
|
162
122
|
for (let i = 0; i < this.scopes.length; i++) {
|
|
163
123
|
if (this.scopes[i].scopeId == scopeId) {
|
|
164
124
|
this.scopes.splice(i, 1);
|
|
165
125
|
break;
|
|
166
126
|
}
|
|
167
127
|
}
|
|
168
|
-
this.scopes.push(
|
|
128
|
+
this.scopes.push({ scopeId, lastNodeUuid: "", node: options?.node, nodeType: options?.nodeType, onBack: options?.onBack });
|
|
169
129
|
this.activeScopeId = scopeId;
|
|
170
|
-
this.
|
|
171
|
-
if (
|
|
172
|
-
|
|
130
|
+
this.clearFocus();
|
|
131
|
+
if (!options?.skipEnsureFocus) this.ensureFocus();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** 移除作用域并清理其下所有注册焦点 */
|
|
135
|
+
public static removeScope(node: cc.Node) {
|
|
136
|
+
if (!node) return;
|
|
137
|
+
this.popScope(node.uuid);
|
|
138
|
+
this.unregisterByRoot(node);
|
|
173
139
|
}
|
|
174
140
|
|
|
175
141
|
public static popScope(scopeId?: string) {
|
|
@@ -181,50 +147,77 @@ export default class FocusManager {
|
|
|
181
147
|
break;
|
|
182
148
|
}
|
|
183
149
|
}
|
|
150
|
+
// 清理已弹出作用域下的所有条目
|
|
151
|
+
for (let i = this.items.length - 1; i >= 0; i--) {
|
|
152
|
+
if (this.scopeMap[this.items[i].node.uuid] == target) {
|
|
153
|
+
this.removeItemAt(i);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
184
156
|
let active = this.scopes[this.scopes.length - 1];
|
|
185
|
-
this.activeScopeId = active ? active.scopeId : "
|
|
186
|
-
let restored = active && active.
|
|
157
|
+
this.activeScopeId = active ? active.scopeId : "";
|
|
158
|
+
let restored = active && active.lastNodeUuid ? this.focus(active.lastNodeUuid) : false;
|
|
187
159
|
if (!restored) {
|
|
188
|
-
this.
|
|
160
|
+
this.clearFocus();
|
|
189
161
|
this.ensureFocus();
|
|
190
162
|
}
|
|
191
163
|
}
|
|
192
164
|
|
|
165
|
+
/** 获取最顶层绑定了节点的作用域 */
|
|
166
|
+
public static getTopNodeScope(): ScopeInfo | null {
|
|
167
|
+
for (let i = this.scopes.length - 1; i >= 0; i--) {
|
|
168
|
+
if (this.scopes[i].node) return this.scopes[i];
|
|
169
|
+
}
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** 获取所有作用域(只读副本) */
|
|
174
|
+
public static getScopes(): ReadonlyArray<ScopeInfo> {
|
|
175
|
+
return this.scopes;
|
|
176
|
+
}
|
|
177
|
+
|
|
193
178
|
public static reset() {
|
|
194
179
|
let old = this.getCurrentFocusItem();
|
|
195
180
|
if (old) this.setFocusVisual(old, false, true);
|
|
196
181
|
this.items = [];
|
|
197
182
|
this.itemMap = {};
|
|
198
|
-
this.
|
|
199
|
-
this.
|
|
200
|
-
this.
|
|
183
|
+
this.scopeMap = {};
|
|
184
|
+
this.currentNodeUuid = "";
|
|
185
|
+
this.scopes = [];
|
|
186
|
+
this.activeScopeId = "";
|
|
201
187
|
this.emitFocusChanged(null, old);
|
|
202
188
|
}
|
|
203
189
|
|
|
204
|
-
public static focus(target: string | cc.Node): boolean {
|
|
190
|
+
public static focus(target: string | cc.Node, silent: boolean = false): boolean {
|
|
205
191
|
this.cleanup();
|
|
206
192
|
if (!target) return false;
|
|
207
|
-
let
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
193
|
+
let uuid = typeof target == "string" ? target : target.uuid;
|
|
194
|
+
let item = this.itemMap[uuid];
|
|
195
|
+
if (!item || !this.isItemActive(item) || !this.isInActiveScope(item)) return false;
|
|
196
|
+
|
|
197
|
+
let previous: FocusRuntimeItem | null = this.getCurrentFocusItem();
|
|
198
|
+
if (uuid == this.currentNodeUuid && uuid) {
|
|
199
|
+
let current = this.getCurrentFocusItem();
|
|
200
|
+
if (current) {
|
|
201
|
+
this.setFocusVisual(current, true);
|
|
202
|
+
// 总是触发位置更新,即使静默模式也要更新视觉位置
|
|
203
|
+
this.emitFocusChanged(current, previous || current);
|
|
216
204
|
}
|
|
205
|
+
return true;
|
|
217
206
|
}
|
|
218
|
-
if (
|
|
219
|
-
this.
|
|
207
|
+
if (previous) this.setFocusVisual(previous, false);
|
|
208
|
+
this.currentNodeUuid = uuid || "";
|
|
209
|
+
let current: FocusRuntimeItem | null = this.getCurrentFocusItem();
|
|
210
|
+
if (current) {
|
|
211
|
+
let scope = this.getActiveScope();
|
|
212
|
+
if (scope) scope.lastNodeUuid = current.node.uuid;
|
|
213
|
+
this.setFocusVisual(current, true);
|
|
214
|
+
}
|
|
215
|
+
// 总是触发位置更新,确保视觉层收到通知
|
|
216
|
+
this.emitFocusChanged(current, previous);
|
|
220
217
|
return true;
|
|
221
218
|
}
|
|
222
219
|
|
|
223
|
-
public static
|
|
224
|
-
return this.focus(node);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
public static move(direction: TvUiDirection): boolean {
|
|
220
|
+
public static move(direction: KeyCode): boolean {
|
|
228
221
|
this.cleanup();
|
|
229
222
|
let current = this.getCurrentFocusItem();
|
|
230
223
|
if (!current) {
|
|
@@ -232,22 +225,19 @@ export default class FocusManager {
|
|
|
232
225
|
return !!this.getCurrentFocusItem();
|
|
233
226
|
}
|
|
234
227
|
|
|
235
|
-
let explicitId = current[direction];
|
|
236
|
-
if (explicitId && this.focus(explicitId)) return true;
|
|
237
|
-
|
|
238
228
|
let vector = this.getDirectionVector(direction);
|
|
239
|
-
let currentCenter = this.getWorldCenter(current.node);
|
|
229
|
+
let currentCenter = this.getWorldCenter(current.node).add(current.offset);
|
|
240
230
|
let best: FocusRuntimeItem | null = null;
|
|
241
231
|
let bestScore = Number.MAX_VALUE;
|
|
242
232
|
|
|
243
233
|
for (let i = 0; i < this.items.length; i++) {
|
|
244
234
|
let item = this.items[i];
|
|
245
235
|
if (item == current || !this.isItemActive(item) || !this.isInActiveScope(item)) continue;
|
|
246
|
-
let center = this.getWorldCenter(item.node);
|
|
236
|
+
let center = this.getWorldCenter(item.node).add(item.offset);
|
|
247
237
|
let dx = center.x - currentCenter.x;
|
|
248
238
|
let dy = center.y - currentCenter.y;
|
|
249
|
-
if (vector.x != 0 && dx * vector.x <=
|
|
250
|
-
if (vector.y != 0 && dy * vector.y <=
|
|
239
|
+
if (vector.x != 0 && dx * vector.x <= 0) continue;
|
|
240
|
+
if (vector.y != 0 && dy * vector.y <= 0) continue;
|
|
251
241
|
let primary = vector.x != 0 ? Math.abs(dx) : Math.abs(dy);
|
|
252
242
|
let secondary = vector.x != 0 ? Math.abs(dy) : Math.abs(dx);
|
|
253
243
|
let score = primary + secondary * 2;
|
|
@@ -258,7 +248,7 @@ export default class FocusManager {
|
|
|
258
248
|
}
|
|
259
249
|
|
|
260
250
|
if (best) {
|
|
261
|
-
this.
|
|
251
|
+
this.focus(best.node.uuid);
|
|
262
252
|
return true;
|
|
263
253
|
}
|
|
264
254
|
return this.moveByOrder(direction == "left" || direction == "down" ? -1 : 1);
|
|
@@ -272,40 +262,18 @@ export default class FocusManager {
|
|
|
272
262
|
item.onClick();
|
|
273
263
|
return true;
|
|
274
264
|
}
|
|
275
|
-
|
|
276
|
-
|
|
265
|
+
let focusItem = item.node.getComponent("FocusItem") as any;
|
|
266
|
+
if (focusItem && focusItem.onConfirm) {
|
|
267
|
+
focusItem.onConfirm();
|
|
277
268
|
return true;
|
|
278
269
|
}
|
|
279
270
|
this.invokeButton(item.node.getComponent(cc.Button));
|
|
280
271
|
return true;
|
|
281
272
|
}
|
|
282
273
|
|
|
283
|
-
public static back(): boolean {
|
|
284
|
-
return false;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
public static handleKey(keyCode: number): boolean {
|
|
288
|
-
let key = KeyCodeAdapter.toRemoteKey(keyCode);
|
|
289
|
-
if (key == TvRemoteKey.Ok) return this.confirm();
|
|
290
|
-
if (key == TvRemoteKey.Left) return this.move("left");
|
|
291
|
-
if (key == TvRemoteKey.Right) return this.move("right");
|
|
292
|
-
if (key == TvRemoteKey.Up) return this.move("up");
|
|
293
|
-
if (key == TvRemoteKey.Down) return this.move("down");
|
|
294
|
-
if (key == TvRemoteKey.Back) return this.back();
|
|
295
|
-
return false;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
public static clickCurrent(): boolean {
|
|
299
|
-
return this.confirm();
|
|
300
|
-
}
|
|
301
|
-
|
|
302
274
|
public static getCurrentFocusItem(): FocusRuntimeItem | null {
|
|
303
|
-
let item = this.itemMap[this.
|
|
304
|
-
return this.isItemActive(item) ? item : null;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
public static getActiveScopeId(): string {
|
|
308
|
-
return this.activeScopeId;
|
|
275
|
+
let item = this.itemMap[this.currentNodeUuid];
|
|
276
|
+
return (item && this.isItemActive(item) && this.isInActiveScope(item)) ? item : null;
|
|
309
277
|
}
|
|
310
278
|
|
|
311
279
|
public static onFocusChanged(listener: FocusListener) {
|
|
@@ -318,34 +286,20 @@ export default class FocusManager {
|
|
|
318
286
|
if (index >= 0) this.listeners.splice(index, 1);
|
|
319
287
|
}
|
|
320
288
|
|
|
321
|
-
|
|
322
|
-
if (focusId == this.currentFocusId && focusId) {
|
|
323
|
-
let current = this.getCurrentFocusItem();
|
|
324
|
-
if (current && !silent) {
|
|
325
|
-
this.setFocusVisual(current, true);
|
|
326
|
-
this.emitFocusChanged(current, current);
|
|
327
|
-
}
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
289
|
+
public static clearFocus() {
|
|
330
290
|
let previous: FocusRuntimeItem | null = this.getCurrentFocusItem();
|
|
331
291
|
if (previous) this.setFocusVisual(previous, false);
|
|
332
|
-
this.
|
|
333
|
-
|
|
334
|
-
if (current) {
|
|
335
|
-
let scope = this.getActiveScope();
|
|
336
|
-
if (scope) scope.lastFocusId = current.focusId;
|
|
337
|
-
this.setFocusVisual(current, true);
|
|
338
|
-
}
|
|
339
|
-
if (!silent) this.emitFocusChanged(current, previous);
|
|
340
|
-
if (silent && previous) this.emitFocusChanged(null, previous);
|
|
292
|
+
this.currentNodeUuid = "";
|
|
293
|
+
if (previous) this.emitFocusChanged(null, previous);
|
|
341
294
|
}
|
|
342
295
|
|
|
343
296
|
private static setFocusVisual(item: FocusRuntimeItem, focused: boolean, immediate: boolean = false) {
|
|
344
297
|
if (!item || !item.node || !item.node.isValid) return;
|
|
345
298
|
this.setButtonSpriteVisual(item, focused);
|
|
346
299
|
item.node.stopActionByTag(this.FOCUS_SCALE_ACTION_TAG);
|
|
347
|
-
let
|
|
348
|
-
let
|
|
300
|
+
let baseScale = this.getNodeBaseScale(item.node);
|
|
301
|
+
let targetScaleX = focused ? baseScale.x * item.focusScale : baseScale.x;
|
|
302
|
+
let targetScaleY = focused ? baseScale.y * item.focusScale : baseScale.y;
|
|
349
303
|
if (immediate) {
|
|
350
304
|
item.node.setScale(targetScaleX, targetScaleY);
|
|
351
305
|
} else {
|
|
@@ -353,8 +307,8 @@ export default class FocusManager {
|
|
|
353
307
|
action.setTag(this.FOCUS_SCALE_ACTION_TAG);
|
|
354
308
|
item.node.runAction(action);
|
|
355
309
|
}
|
|
356
|
-
if (focused && item.onFocus) item.onFocus
|
|
357
|
-
if (!focused && item.onBlur) item.onBlur
|
|
310
|
+
if (focused && item.onFocus) item.onFocus();
|
|
311
|
+
if (!focused && item.onBlur) item.onBlur();
|
|
358
312
|
}
|
|
359
313
|
|
|
360
314
|
private static setButtonSpriteVisual(item: FocusRuntimeItem, focused: boolean) {
|
|
@@ -368,18 +322,34 @@ export default class FocusManager {
|
|
|
368
322
|
if (spriteFrame) sprite.spriteFrame = spriteFrame;
|
|
369
323
|
}
|
|
370
324
|
|
|
325
|
+
private static _ensureFocusRetry: number = 0;
|
|
326
|
+
private static readonly _ENSURE_FOCUS_MAX_RETRY = 3;
|
|
327
|
+
|
|
371
328
|
private static ensureFocus() {
|
|
372
329
|
this.cleanup();
|
|
373
330
|
if (this.getCurrentFocusItem()) return;
|
|
374
331
|
let activeScope = this.getActiveScope();
|
|
375
|
-
if (activeScope && activeScope.
|
|
332
|
+
if (activeScope && activeScope.lastNodeUuid && this.focus(activeScope.lastNodeUuid)) return;
|
|
376
333
|
for (let i = 0; i < this.items.length; i++) {
|
|
377
334
|
let item = this.items[i];
|
|
378
335
|
if (this.isItemActive(item) && this.isInActiveScope(item)) {
|
|
379
|
-
this.
|
|
336
|
+
this.focus(item.node.uuid);
|
|
337
|
+
this._ensureFocusRetry = 0;
|
|
380
338
|
return;
|
|
381
339
|
}
|
|
382
340
|
}
|
|
341
|
+
// 有注册的按钮但暂无活跃节点,可能是节点尚未完全初始化,延迟重试
|
|
342
|
+
if (this.items.length > 0 && this._ensureFocusRetry < this._ENSURE_FOCUS_MAX_RETRY) {
|
|
343
|
+
this._ensureFocusRetry++;
|
|
344
|
+
setTimeout(() => {
|
|
345
|
+
this.ensureFocus();
|
|
346
|
+
}, 50);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
// 超过重试次数/无注册项,清除焦点状态
|
|
350
|
+
this._ensureFocusRetry = 0;
|
|
351
|
+
this.currentNodeUuid = "";
|
|
352
|
+
this.emitFocusChanged(null, null);
|
|
383
353
|
}
|
|
384
354
|
|
|
385
355
|
private static moveByOrder(step: number): boolean {
|
|
@@ -390,13 +360,13 @@ export default class FocusManager {
|
|
|
390
360
|
if (activeItems.length <= 0) return false;
|
|
391
361
|
let index = 0;
|
|
392
362
|
for (let i = 0; i < activeItems.length; i++) {
|
|
393
|
-
if (activeItems[i].
|
|
363
|
+
if (activeItems[i].node.uuid == this.currentNodeUuid) {
|
|
394
364
|
index = i;
|
|
395
365
|
break;
|
|
396
366
|
}
|
|
397
367
|
}
|
|
398
368
|
let next = (index + step + activeItems.length) % activeItems.length;
|
|
399
|
-
this.
|
|
369
|
+
this.focus(activeItems[next].node.uuid);
|
|
400
370
|
return true;
|
|
401
371
|
}
|
|
402
372
|
|
|
@@ -404,10 +374,11 @@ export default class FocusManager {
|
|
|
404
374
|
let item = this.items[index];
|
|
405
375
|
if (!item) return;
|
|
406
376
|
this.setFocusVisual(item, false, true);
|
|
407
|
-
delete this.itemMap[item.
|
|
377
|
+
delete this.itemMap[item.node.uuid];
|
|
378
|
+
delete this.scopeMap[item.node.uuid];
|
|
408
379
|
this.items.splice(index, 1);
|
|
409
|
-
if (this.
|
|
410
|
-
this.
|
|
380
|
+
if (this.currentNodeUuid == item.node.uuid) {
|
|
381
|
+
this.currentNodeUuid = "";
|
|
411
382
|
this.emitFocusChanged(null, item);
|
|
412
383
|
}
|
|
413
384
|
}
|
|
@@ -426,10 +397,10 @@ export default class FocusManager {
|
|
|
426
397
|
}
|
|
427
398
|
|
|
428
399
|
private static isInActiveScope(item?: FocusRuntimeItem | null): boolean {
|
|
429
|
-
return !!item && item.
|
|
400
|
+
return !!item && this.scopeMap[item.node.uuid] == this.activeScopeId;
|
|
430
401
|
}
|
|
431
402
|
|
|
432
|
-
private static getActiveScope():
|
|
403
|
+
private static getActiveScope(): ScopeInfo | null {
|
|
433
404
|
for (let i = this.scopes.length - 1; i >= 0; i--) {
|
|
434
405
|
if (this.scopes[i].scopeId == this.activeScopeId) return this.scopes[i];
|
|
435
406
|
}
|
|
@@ -441,10 +412,10 @@ export default class FocusManager {
|
|
|
441
412
|
return cc.v2(box.x + box.width / 2, box.y + box.height / 2);
|
|
442
413
|
}
|
|
443
414
|
|
|
444
|
-
private static getDirectionVector(direction:
|
|
445
|
-
if (direction ==
|
|
446
|
-
if (direction ==
|
|
447
|
-
if (direction ==
|
|
415
|
+
private static getDirectionVector(direction: KeyCode): cc.Vec2 {
|
|
416
|
+
if (direction == KeyCode.Left) return cc.v2(-1, 0);
|
|
417
|
+
if (direction == KeyCode.Right) return cc.v2(1, 0);
|
|
418
|
+
if (direction == KeyCode.Up) return cc.v2(0, 1);
|
|
448
419
|
return cc.v2(0, -1);
|
|
449
420
|
}
|
|
450
421
|
|
|
@@ -479,15 +450,7 @@ export default class FocusManager {
|
|
|
479
450
|
return target;
|
|
480
451
|
}
|
|
481
452
|
|
|
482
|
-
private static
|
|
483
|
-
if (!node) return null;
|
|
484
|
-
for (let i = 0; i < this.items.length; i++) {
|
|
485
|
-
if (this.items[i].node == node) return this.items[i];
|
|
486
|
-
}
|
|
487
|
-
return null;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
private static getNodeBaseScale(node: cc.Node, preferred?: { x: number, y: number } | null): { x: number, y: number } {
|
|
453
|
+
private static getNodeBaseScale(node: cc.Node): { x: number, y: number } {
|
|
491
454
|
let nodeAny: any = node as any;
|
|
492
455
|
let storedX = nodeAny[this.BASE_SCALE_X_KEY];
|
|
493
456
|
let storedY = nodeAny[this.BASE_SCALE_Y_KEY];
|
|
@@ -495,7 +458,7 @@ export default class FocusManager {
|
|
|
495
458
|
return { x: storedX, y: storedY };
|
|
496
459
|
}
|
|
497
460
|
|
|
498
|
-
let baseScale =
|
|
461
|
+
let baseScale = {
|
|
499
462
|
x: this.readScale(node, "scaleX"),
|
|
500
463
|
y: this.readScale(node, "scaleY")
|
|
501
464
|
};
|
|
@@ -516,10 +479,6 @@ export default class FocusManager {
|
|
|
516
479
|
return typeof value == "number" && isFinite(value);
|
|
517
480
|
}
|
|
518
481
|
|
|
519
|
-
private static createFocusId(node: cc.Node): string {
|
|
520
|
-
return "focus_" + (node.name || "node") + "_" + this.items.length;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
482
|
private static walk(node: cc.Node, visitor: (node: cc.Node) => void) {
|
|
524
483
|
visitor(node);
|
|
525
484
|
for (let i = 0; i < node.childrenCount; i++) {
|
|
@@ -535,4 +494,4 @@ export default class FocusManager {
|
|
|
535
494
|
}
|
|
536
495
|
return false;
|
|
537
496
|
}
|
|
538
|
-
}
|
|
497
|
+
}
|