drgame-cc 1.0.50 → 1.0.52
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/PlatformAdapter.ts +32 -74
- package/drscript/PlatformUtil.ts +30 -0
- 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/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
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
const { ccclass, property } = cc._decorator;
|
|
3
3
|
|
|
4
|
-
@ccclass
|
|
5
|
-
export class BtnExtra extends cc.Component {
|
|
6
|
-
@property(
|
|
7
|
-
type: cc.SpriteFrame,
|
|
8
|
-
tooltip: '悬停状态图片'
|
|
9
|
-
})
|
|
4
|
+
@ccclass
|
|
5
|
+
export default class BtnExtra extends cc.Component {
|
|
6
|
+
@property(cc.SpriteFrame)
|
|
10
7
|
hoverSprite: cc.SpriteFrame = null;
|
|
11
|
-
|
|
12
|
-
@property({
|
|
13
|
-
type: cc.SpriteFrame,
|
|
14
|
-
tooltip: '普通状态图片'
|
|
15
|
-
})
|
|
8
|
+
@property(cc.SpriteFrame)
|
|
16
9
|
normalSprite: cc.SpriteFrame = null;
|
|
17
10
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { KeyCode } from "../ad-sdk/ad-sdk";
|
|
2
|
+
import { FingerStyle } from "../Define";
|
|
3
|
+
import FocusVisualLayer from "./FocusVisualLayer";
|
|
2
4
|
|
|
3
5
|
export interface FocusRuntimeItem {
|
|
4
6
|
node: cc.Node;
|
|
@@ -25,8 +27,8 @@ interface ScopeInfo {
|
|
|
25
27
|
|
|
26
28
|
export default class FocusManager {
|
|
27
29
|
private static readonly FOCUS_SCALE_ACTION_TAG: number = 9911;
|
|
28
|
-
private static readonly
|
|
29
|
-
private static readonly
|
|
30
|
+
private static readonly PERP_WEIGHT = 3; // 垂直方向惩罚权重
|
|
31
|
+
private static readonly BASE_SCALE_KEY: string = "__tvFocusBaseScale";
|
|
30
32
|
private static items: FocusRuntimeItem[] = [];
|
|
31
33
|
private static itemMap: { [uuid: string]: FocusRuntimeItem } = {};
|
|
32
34
|
private static scopeMap: { [uuid: string]: string } = {};
|
|
@@ -35,43 +37,44 @@ export default class FocusManager {
|
|
|
35
37
|
private static activeScopeId: string = "";
|
|
36
38
|
private static listeners: FocusListener[] = [];
|
|
37
39
|
|
|
40
|
+
// ---- 视觉层管理 ----
|
|
41
|
+
private static visualLayer: FocusVisualLayer | null = null;
|
|
42
|
+
private static _focusStyle: FingerStyle = FingerStyle.Default;
|
|
43
|
+
private static _focusZIndex: number = 800;
|
|
44
|
+
private static _cursorVisible: boolean = true;
|
|
45
|
+
|
|
38
46
|
private static readonly DEFAULT_FOCUS_SCALE = 1.08;
|
|
39
47
|
|
|
40
|
-
public static register(
|
|
41
|
-
let node = this.resolveNode(target);
|
|
48
|
+
public static register(node: cc.Node, options: { scopeId?: string; onFocus?: Function; onBlur?: Function; onClick?: Function; focusScale?: number; showCursor?: boolean; offset?: cc.Vec2 } = {}): void {
|
|
42
49
|
if (!node) return;
|
|
43
|
-
let component = this.resolveComponent(target, node);
|
|
44
50
|
this.unregister(node);
|
|
45
51
|
|
|
46
|
-
let
|
|
47
|
-
this.
|
|
48
|
-
|
|
49
|
-
let scopeId = options.scopeId || (component && component.scopeId) || this.activeScopeId;
|
|
50
|
-
this.scopeMap[uuid] = scopeId;
|
|
52
|
+
let scopeId = options.scopeId || this.activeScopeId;
|
|
53
|
+
this.scopeMap[node.uuid] = scopeId;
|
|
51
54
|
|
|
52
55
|
let item: FocusRuntimeItem = {
|
|
53
56
|
node: node,
|
|
54
|
-
onFocus: options.onFocus
|
|
55
|
-
onBlur: options.onBlur
|
|
57
|
+
onFocus: options.onFocus,
|
|
58
|
+
onBlur: options.onBlur,
|
|
56
59
|
onClick: options.onClick,
|
|
57
|
-
focusScale: options.focusScale ||
|
|
60
|
+
focusScale: options.focusScale || this.DEFAULT_FOCUS_SCALE,
|
|
58
61
|
showCursor: options.showCursor !== false,
|
|
59
62
|
offset: options.offset || cc.v2(0, 0)
|
|
60
63
|
};
|
|
61
64
|
|
|
65
|
+
this.storeBaseScale(node);
|
|
62
66
|
this.items.push(item);
|
|
63
|
-
this.itemMap[uuid] = item;
|
|
67
|
+
this.itemMap[node.uuid] = item;
|
|
64
68
|
this.ensureFocus();
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
public static unregister(
|
|
68
|
-
let node = this.resolveNode(target);
|
|
71
|
+
public static unregister(node: cc.Node) {
|
|
69
72
|
if (!node) return;
|
|
70
73
|
delete this.scopeMap[node.uuid];
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
let item = this.itemMap[node.uuid];
|
|
75
|
+
if (item) {
|
|
76
|
+
let idx = this.items.indexOf(item);
|
|
77
|
+
if (idx >= 0) this.removeItemAt(idx);
|
|
75
78
|
}
|
|
76
79
|
this.ensureFocus();
|
|
77
80
|
}
|
|
@@ -79,39 +82,50 @@ export default class FocusManager {
|
|
|
79
82
|
public static unregisterByRoot(root: cc.Node) {
|
|
80
83
|
if (!root) return;
|
|
81
84
|
for (let i = this.items.length - 1; i >= 0; i--) {
|
|
82
|
-
let
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
let cur = this.items[i].node;
|
|
86
|
+
while (cur) {
|
|
87
|
+
if (cur == root) {
|
|
88
|
+
delete this.scopeMap[this.items[i].node.uuid];
|
|
89
|
+
this.removeItemAt(i);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
cur = cur.parent;
|
|
86
93
|
}
|
|
87
94
|
}
|
|
88
95
|
this.ensureFocus();
|
|
89
96
|
}
|
|
90
97
|
|
|
91
|
-
private static
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
delete this.scopeMap[uuid];
|
|
96
|
-
this.removeItemAt(i);
|
|
97
|
-
}
|
|
98
|
+
private static storeBaseScale(node: cc.Node) {
|
|
99
|
+
let anyNode = node as any;
|
|
100
|
+
if (anyNode[this.BASE_SCALE_KEY] == null) {
|
|
101
|
+
anyNode[this.BASE_SCALE_KEY] = { x: node.scaleX, y: node.scaleY };
|
|
98
102
|
}
|
|
99
103
|
}
|
|
100
104
|
|
|
105
|
+
private static getBaseScale(node: cc.Node): { x: number, y: number } {
|
|
106
|
+
return ((node as any)[this.BASE_SCALE_KEY] || { x: 1, y: 1 });
|
|
107
|
+
}
|
|
108
|
+
|
|
101
109
|
public static registerButtons(root: cc.Node) {
|
|
102
110
|
if (!root) return;
|
|
103
111
|
this.unregisterByRoot(root);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
let walk = (node: cc.Node) => {
|
|
113
|
+
// Scene 节点自身不注册,但必须遍历其子节点
|
|
114
|
+
if (!(node instanceof cc.Scene)) {
|
|
115
|
+
let button = node.getComponent(cc.Button);
|
|
116
|
+
if (button) {
|
|
117
|
+
this.register(node, {
|
|
118
|
+
scopeId: this.activeScopeId,
|
|
119
|
+
focusScale: this.DEFAULT_FOCUS_SCALE,
|
|
120
|
+
onClick: () => this.invokeButton(button)
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
for (let i = 0; i < node.childrenCount; i++) {
|
|
125
|
+
walk(node.children[i]);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
walk(root);
|
|
115
129
|
this.ensureFocus();
|
|
116
130
|
}
|
|
117
131
|
|
|
@@ -184,10 +198,70 @@ export default class FocusManager {
|
|
|
184
198
|
this.currentNodeUuid = "";
|
|
185
199
|
this.scopes = [];
|
|
186
200
|
this.activeScopeId = "";
|
|
201
|
+
if (this.visualLayer) {
|
|
202
|
+
this.visualLayer.dispose();
|
|
203
|
+
this.visualLayer = null;
|
|
204
|
+
}
|
|
187
205
|
this.emitFocusChanged(null, old);
|
|
188
206
|
}
|
|
189
207
|
|
|
190
|
-
|
|
208
|
+
// ========================================================================
|
|
209
|
+
// 视觉层管理(FocusVisualLayer 由 FocusManager 统一管理)
|
|
210
|
+
// ========================================================================
|
|
211
|
+
|
|
212
|
+
/** 显示/隐藏导航手指 */
|
|
213
|
+
public static setCursorVisible(visible: boolean): void {
|
|
214
|
+
this._cursorVisible = visible;
|
|
215
|
+
if (this.visualLayer) {
|
|
216
|
+
if (visible) {
|
|
217
|
+
const current = this.getCurrentFocusItem();
|
|
218
|
+
this.visualLayer.onFocusChanged(current);
|
|
219
|
+
} else {
|
|
220
|
+
this.visualLayer.hide();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** 导航手指是否可见 */
|
|
226
|
+
public static isCursorVisible(): boolean {
|
|
227
|
+
return this._cursorVisible;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** 初始化焦点视觉层 */
|
|
231
|
+
public static initVisualLayer(): void {
|
|
232
|
+
if (this.visualLayer) {
|
|
233
|
+
this.visualLayer.dispose();
|
|
234
|
+
this.visualLayer = null;
|
|
235
|
+
}
|
|
236
|
+
const scene = cc.director.getScene();
|
|
237
|
+
if (!scene) {
|
|
238
|
+
console.warn("[FocusManager] Cannot init visual layer: scene is null, will retry next frame");
|
|
239
|
+
setTimeout(() => this.initVisualLayer(), 0);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
this.visualLayer = new FocusVisualLayer(scene, { style: this._focusStyle, zIndex: this._focusZIndex });
|
|
244
|
+
|
|
245
|
+
// 创建后立即同步当前焦点状态
|
|
246
|
+
const current = this.getCurrentFocusItem();
|
|
247
|
+
if (current) {
|
|
248
|
+
this.visualLayer.onFocusChanged(current);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** 设置焦点样式 */
|
|
253
|
+
public static setFocusStyle(style: FingerStyle): void {
|
|
254
|
+
this._focusStyle = style;
|
|
255
|
+
if (this.visualLayer) this.visualLayer.setStyle(style);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** 设置焦点视觉层级 */
|
|
259
|
+
public static setFocusZIndex(z: number): void {
|
|
260
|
+
this._focusZIndex = z;
|
|
261
|
+
if (this.visualLayer) this.visualLayer.setZIndex(z);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
public static focus(target: string | cc.Node): boolean {
|
|
191
265
|
this.cleanup();
|
|
192
266
|
if (!target) return false;
|
|
193
267
|
let uuid = typeof target == "string" ? target : target.uuid;
|
|
@@ -196,11 +270,9 @@ export default class FocusManager {
|
|
|
196
270
|
|
|
197
271
|
let previous: FocusRuntimeItem | null = this.getCurrentFocusItem();
|
|
198
272
|
if (uuid == this.currentNodeUuid && uuid) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
this.
|
|
202
|
-
// 总是触发位置更新,即使静默模式也要更新视觉位置
|
|
203
|
-
this.emitFocusChanged(current, previous || current);
|
|
273
|
+
if (previous) {
|
|
274
|
+
this.setFocusVisual(previous, true);
|
|
275
|
+
this.emitFocusChanged(previous, previous);
|
|
204
276
|
}
|
|
205
277
|
return true;
|
|
206
278
|
}
|
|
@@ -212,7 +284,6 @@ export default class FocusManager {
|
|
|
212
284
|
if (scope) scope.lastNodeUuid = current.node.uuid;
|
|
213
285
|
this.setFocusVisual(current, true);
|
|
214
286
|
}
|
|
215
|
-
// 总是触发位置更新,确保视觉层收到通知
|
|
216
287
|
this.emitFocusChanged(current, previous);
|
|
217
288
|
return true;
|
|
218
289
|
}
|
|
@@ -225,24 +296,27 @@ export default class FocusManager {
|
|
|
225
296
|
return !!this.getCurrentFocusItem();
|
|
226
297
|
}
|
|
227
298
|
|
|
228
|
-
let vector = this.getDirectionVector(direction);
|
|
229
299
|
let currentCenter = this.getWorldCenter(current.node).add(current.offset);
|
|
230
300
|
let best: FocusRuntimeItem | null = null;
|
|
231
|
-
let
|
|
301
|
+
let bestDist = Infinity;
|
|
232
302
|
|
|
233
303
|
for (let i = 0; i < this.items.length; i++) {
|
|
234
304
|
let item = this.items[i];
|
|
235
305
|
if (item == current || !this.isItemActive(item) || !this.isInActiveScope(item)) continue;
|
|
306
|
+
|
|
236
307
|
let center = this.getWorldCenter(item.node).add(item.offset);
|
|
237
308
|
let dx = center.x - currentCenter.x;
|
|
238
309
|
let dy = center.y - currentCenter.y;
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if (
|
|
245
|
-
|
|
310
|
+
|
|
311
|
+
// 必须在目标方向一侧(Cocos Y 轴向上递增)
|
|
312
|
+
if (direction === KeyCode.Left && dx >= 0) continue;
|
|
313
|
+
if (direction === KeyCode.Right && dx <= 0) continue;
|
|
314
|
+
if (direction === KeyCode.Up && dy <= 0) continue; // 上方:dy > 0
|
|
315
|
+
if (direction === KeyCode.Down && dy >= 0) continue; // 下方:dy < 0
|
|
316
|
+
|
|
317
|
+
let dist = this.navDistance(dx, dy, direction);
|
|
318
|
+
if (dist < bestDist) {
|
|
319
|
+
bestDist = dist;
|
|
246
320
|
best = item;
|
|
247
321
|
}
|
|
248
322
|
}
|
|
@@ -251,22 +325,33 @@ export default class FocusManager {
|
|
|
251
325
|
this.focus(best.node.uuid);
|
|
252
326
|
return true;
|
|
253
327
|
}
|
|
254
|
-
return this.moveByOrder(direction
|
|
328
|
+
return this.moveByOrder(direction === KeyCode.Left || direction === KeyCode.Down ? -1 : 1);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** 方向加权距离:对垂直于移动方向的分量加重惩罚,导航更精准 */
|
|
332
|
+
private static navDistance(dx: number, dy: number, direction: KeyCode): number {
|
|
333
|
+
switch (direction) {
|
|
334
|
+
case KeyCode.Left:
|
|
335
|
+
case KeyCode.Right:
|
|
336
|
+
// 水平移动:垂直偏差 * 3
|
|
337
|
+
return Math.sqrt(dx * dx + dy * dy * this.PERP_WEIGHT);
|
|
338
|
+
case KeyCode.Up:
|
|
339
|
+
case KeyCode.Down:
|
|
340
|
+
// 垂直移动:水平偏差 * 3
|
|
341
|
+
return Math.sqrt(dx * dx * this.PERP_WEIGHT + dy * dy);
|
|
342
|
+
default:
|
|
343
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
344
|
+
}
|
|
255
345
|
}
|
|
256
346
|
|
|
257
347
|
public static confirm(): boolean {
|
|
258
|
-
this.ensureFocus();
|
|
259
348
|
let item = this.getCurrentFocusItem();
|
|
260
|
-
if (!item)
|
|
261
|
-
|
|
262
|
-
item.
|
|
263
|
-
return
|
|
264
|
-
}
|
|
265
|
-
let focusItem = item.node.getComponent("FocusItem") as any;
|
|
266
|
-
if (focusItem && focusItem.onConfirm) {
|
|
267
|
-
focusItem.onConfirm();
|
|
268
|
-
return true;
|
|
349
|
+
if (!item) {
|
|
350
|
+
this.ensureFocus();
|
|
351
|
+
item = this.getCurrentFocusItem();
|
|
352
|
+
if (!item) return false;
|
|
269
353
|
}
|
|
354
|
+
if (item.onClick) return (item.onClick(), true);
|
|
270
355
|
this.invokeButton(item.node.getComponent(cc.Button));
|
|
271
356
|
return true;
|
|
272
357
|
}
|
|
@@ -295,9 +380,8 @@ export default class FocusManager {
|
|
|
295
380
|
|
|
296
381
|
private static setFocusVisual(item: FocusRuntimeItem, focused: boolean, immediate: boolean = false) {
|
|
297
382
|
if (!item || !item.node || !item.node.isValid) return;
|
|
298
|
-
this.setButtonSpriteVisual(item, focused);
|
|
299
383
|
item.node.stopActionByTag(this.FOCUS_SCALE_ACTION_TAG);
|
|
300
|
-
let baseScale = this.
|
|
384
|
+
let baseScale = this.getBaseScale(item.node);
|
|
301
385
|
let targetScaleX = focused ? baseScale.x * item.focusScale : baseScale.x;
|
|
302
386
|
let targetScaleY = focused ? baseScale.y * item.focusScale : baseScale.y;
|
|
303
387
|
if (immediate) {
|
|
@@ -311,20 +395,6 @@ export default class FocusManager {
|
|
|
311
395
|
if (!focused && item.onBlur) item.onBlur();
|
|
312
396
|
}
|
|
313
397
|
|
|
314
|
-
private static setButtonSpriteVisual(item: FocusRuntimeItem, focused: boolean) {
|
|
315
|
-
let button = item.node.getComponent(cc.Button);
|
|
316
|
-
if (!button || button.transition != cc.Button.Transition.SPRITE) return;
|
|
317
|
-
let target = button.target || button.node;
|
|
318
|
-
if (!target || !target.isValid) return;
|
|
319
|
-
let sprite = target.getComponent(cc.Sprite);
|
|
320
|
-
if (!sprite) return;
|
|
321
|
-
let spriteFrame = focused ? (button.hoverSprite || button.pressedSprite) : button.normalSprite;
|
|
322
|
-
if (spriteFrame) sprite.spriteFrame = spriteFrame;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
private static _ensureFocusRetry: number = 0;
|
|
326
|
-
private static readonly _ENSURE_FOCUS_MAX_RETRY = 3;
|
|
327
|
-
|
|
328
398
|
private static ensureFocus() {
|
|
329
399
|
this.cleanup();
|
|
330
400
|
if (this.getCurrentFocusItem()) return;
|
|
@@ -334,37 +404,18 @@ export default class FocusManager {
|
|
|
334
404
|
let item = this.items[i];
|
|
335
405
|
if (this.isItemActive(item) && this.isInActiveScope(item)) {
|
|
336
406
|
this.focus(item.node.uuid);
|
|
337
|
-
this._ensureFocusRetry = 0;
|
|
338
407
|
return;
|
|
339
408
|
}
|
|
340
409
|
}
|
|
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
410
|
this.currentNodeUuid = "";
|
|
352
411
|
this.emitFocusChanged(null, null);
|
|
353
412
|
}
|
|
354
413
|
|
|
355
414
|
private static moveByOrder(step: number): boolean {
|
|
356
|
-
let activeItems =
|
|
357
|
-
for (let i = 0; i < this.items.length; i++) {
|
|
358
|
-
if (this.isItemActive(this.items[i]) && this.isInActiveScope(this.items[i])) activeItems.push(this.items[i]);
|
|
359
|
-
}
|
|
415
|
+
let activeItems = this.items.filter(i => this.isItemActive(i) && this.isInActiveScope(i));
|
|
360
416
|
if (activeItems.length <= 0) return false;
|
|
361
|
-
let index =
|
|
362
|
-
|
|
363
|
-
if (activeItems[i].node.uuid == this.currentNodeUuid) {
|
|
364
|
-
index = i;
|
|
365
|
-
break;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
417
|
+
let index = activeItems.findIndex(i => i.node.uuid == this.currentNodeUuid);
|
|
418
|
+
if (index < 0) index = 0;
|
|
368
419
|
let next = (index + step + activeItems.length) % activeItems.length;
|
|
369
420
|
this.focus(activeItems[next].node.uuid);
|
|
370
421
|
return true;
|
|
@@ -412,13 +463,6 @@ export default class FocusManager {
|
|
|
412
463
|
return cc.v2(box.x + box.width / 2, box.y + box.height / 2);
|
|
413
464
|
}
|
|
414
465
|
|
|
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);
|
|
419
|
-
return cc.v2(0, -1);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
466
|
private static invokeButton(button: cc.Button) {
|
|
423
467
|
if (!button || !button.node || !button.node.activeInHierarchy || !button.interactable) return;
|
|
424
468
|
var event = new cc.Event.EventCustom(cc.Node.EventType.TOUCH_END, true);
|
|
@@ -434,64 +478,17 @@ export default class FocusManager {
|
|
|
434
478
|
}
|
|
435
479
|
|
|
436
480
|
private static emitFocusChanged(item: FocusRuntimeItem | null, previous?: FocusRuntimeItem | null) {
|
|
481
|
+
// 更新焦点视觉层(受 _cursorVisible 开关控制)
|
|
482
|
+
if (this.visualLayer) {
|
|
483
|
+
if (this._cursorVisible) {
|
|
484
|
+
this.visualLayer.onFocusChanged(item);
|
|
485
|
+
} else {
|
|
486
|
+
this.visualLayer.hide();
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
// 通知外部监听者
|
|
437
490
|
for (let i = 0; i < this.listeners.length; i++) {
|
|
438
491
|
this.listeners[i](item, previous);
|
|
439
492
|
}
|
|
440
493
|
}
|
|
441
|
-
|
|
442
|
-
private static resolveNode(target: any): cc.Node | null {
|
|
443
|
-
if (!target) return null;
|
|
444
|
-
if (target instanceof cc.Node) return target;
|
|
445
|
-
return target.node || null;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
private static resolveComponent(target: any, node: cc.Node): any {
|
|
449
|
-
if (!target || target instanceof cc.Node) return node.getComponent("FocusItem");
|
|
450
|
-
return target;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
private static getNodeBaseScale(node: cc.Node): { x: number, y: number } {
|
|
454
|
-
let nodeAny: any = node as any;
|
|
455
|
-
let storedX = nodeAny[this.BASE_SCALE_X_KEY];
|
|
456
|
-
let storedY = nodeAny[this.BASE_SCALE_Y_KEY];
|
|
457
|
-
if (this.isValidScale(storedX) && this.isValidScale(storedY)) {
|
|
458
|
-
return { x: storedX, y: storedY };
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
let baseScale = {
|
|
462
|
-
x: this.readScale(node, "scaleX"),
|
|
463
|
-
y: this.readScale(node, "scaleY")
|
|
464
|
-
};
|
|
465
|
-
nodeAny[this.BASE_SCALE_X_KEY] = baseScale.x;
|
|
466
|
-
nodeAny[this.BASE_SCALE_Y_KEY] = baseScale.y;
|
|
467
|
-
return baseScale;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
private static readScale(node: cc.Node, key: string): number {
|
|
471
|
-
let nodeAny: any = node as any;
|
|
472
|
-
let value = nodeAny[key];
|
|
473
|
-
if (this.isValidScale(value)) return value;
|
|
474
|
-
value = nodeAny.scale;
|
|
475
|
-
return this.isValidScale(value) ? value : 1;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
private static isValidScale(value: any): boolean {
|
|
479
|
-
return typeof value == "number" && isFinite(value);
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
private static walk(node: cc.Node, visitor: (node: cc.Node) => void) {
|
|
483
|
-
visitor(node);
|
|
484
|
-
for (let i = 0; i < node.childrenCount; i++) {
|
|
485
|
-
this.walk(node.children[i], visitor);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
private static isChildOf(node: cc.Node, root: cc.Node): boolean {
|
|
490
|
-
let cur = node;
|
|
491
|
-
while (cur) {
|
|
492
|
-
if (cur == root) return true;
|
|
493
|
-
cur = cur.parent;
|
|
494
|
-
}
|
|
495
|
-
return false;
|
|
496
|
-
}
|
|
497
494
|
}
|