2025-01-24 16:05:05 +08:00
|
|
|
import ccui from "@xuyanfeng/cc-ui";
|
|
|
|
import { IUiMenuItem } from "@xuyanfeng/cc-ui/types/cc-menu/const";
|
2025-01-25 16:47:56 +08:00
|
|
|
import { throttle } from "lodash";
|
|
|
|
import { toRaw } from "vue";
|
2025-01-24 17:42:06 +08:00
|
|
|
import { Msg } from "../../../core/types";
|
2025-01-24 16:05:05 +08:00
|
|
|
import { DocumentEvent } from "../../const";
|
2025-01-25 16:47:56 +08:00
|
|
|
import { appStore } from "../../inject-view/store";
|
2025-01-24 16:05:05 +08:00
|
|
|
import { Inspector } from "../inspector";
|
|
|
|
import { DrawOptions, HintAdapter, RectPoints } from "./adapter";
|
|
|
|
import { HintV2 } from "./hint-v2";
|
|
|
|
import { HintV3 } from "./hint-v3";
|
|
|
|
declare const cc: any;
|
|
|
|
|
2025-02-06 16:53:06 +08:00
|
|
|
export const PickShortKey = "Escape";
|
|
|
|
|
2025-01-24 16:05:05 +08:00
|
|
|
/**
|
|
|
|
* 只负责管理hint的流程
|
|
|
|
*/
|
|
|
|
export class Hint {
|
|
|
|
private engineVersion: string = "";
|
|
|
|
private hintAdapter: HintAdapter = null;
|
|
|
|
public setEngineVersion(version: string) {
|
|
|
|
this.engineVersion = version;
|
|
|
|
if (version.startsWith("2.")) {
|
|
|
|
this.hintAdapter = new HintV2();
|
|
|
|
} else if (version.startsWith("3.")) {
|
|
|
|
this.hintAdapter = new HintV3();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private inspector: Inspector = null;
|
|
|
|
constructor(inspector: Inspector) {
|
|
|
|
this.inspector = inspector;
|
2025-01-25 18:24:37 +08:00
|
|
|
document.addEventListener(DocumentEvent.InspectorClear, () => {
|
|
|
|
this.cleanHover();
|
|
|
|
this.cleanSelected();
|
|
|
|
});
|
2025-01-24 16:05:05 +08:00
|
|
|
document.addEventListener(DocumentEvent.GameInspectorBegan, (event: CustomEvent) => {
|
|
|
|
const el = this.getTargetElement();
|
|
|
|
if (!el) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const cursor = el.style.cursor;
|
|
|
|
el.style.cursor = "zoom-in";
|
2025-01-25 16:47:56 +08:00
|
|
|
|
|
|
|
const mousedown = (event: MouseEvent) => {
|
2025-01-24 16:05:05 +08:00
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
2025-02-06 16:53:06 +08:00
|
|
|
pickEnd();
|
2025-01-25 16:47:56 +08:00
|
|
|
|
|
|
|
if (event.button === 0) {
|
|
|
|
// 左键拾取
|
|
|
|
this.updateHintDown(event, el);
|
|
|
|
} else {
|
|
|
|
// 其他按键取消
|
2025-02-06 16:53:06 +08:00
|
|
|
this.pickCancel();
|
2025-01-25 16:47:56 +08:00
|
|
|
}
|
2025-01-24 16:05:05 +08:00
|
|
|
};
|
2025-02-06 16:53:06 +08:00
|
|
|
function pickEnd() {
|
|
|
|
document.removeEventListener("keydown", keydown, true);
|
|
|
|
el.removeEventListener("mousedown", mousedown, true);
|
|
|
|
el.removeEventListener("mousemove", mousemove, true);
|
|
|
|
el.style.cursor = cursor;
|
|
|
|
const e = new CustomEvent(DocumentEvent.GameInspectorEnd);
|
|
|
|
document.dispatchEvent(e);
|
|
|
|
}
|
|
|
|
|
2025-01-25 16:47:56 +08:00
|
|
|
const mousemove = (event: MouseEvent) => {
|
|
|
|
this.updateHitMoveThrottle(event, el);
|
|
|
|
};
|
2025-02-06 16:53:06 +08:00
|
|
|
const keydown = (event: KeyboardEvent) => {
|
|
|
|
if (event.key === PickShortKey) {
|
|
|
|
pickEnd();
|
|
|
|
this.pickCancel();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
document.addEventListener("keydown", keydown, true);
|
2025-01-25 16:47:56 +08:00
|
|
|
el.addEventListener("mousemove", mousemove, true);
|
|
|
|
el.addEventListener("mousedown", mousedown, true);
|
2025-01-24 16:05:05 +08:00
|
|
|
});
|
|
|
|
}
|
2025-02-06 16:53:06 +08:00
|
|
|
private pickCancel() {
|
|
|
|
this.updateHitMoveThrottle.cancel();
|
|
|
|
this.cleanHover();
|
|
|
|
}
|
2025-01-25 16:47:56 +08:00
|
|
|
private updateHitMoveThrottle = throttle(this.updateHintMove, 300);
|
|
|
|
private updateHintMove(event: MouseEvent, canvas: HTMLCanvasElement) {
|
|
|
|
const nodes = this.getMouseNodes(event, canvas);
|
|
|
|
if (nodes.length) {
|
|
|
|
const node = nodes[0];
|
|
|
|
this.setHover(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private getMouseNodes(event: MouseEvent, canvas: HTMLCanvasElement): Array<any> {
|
2025-01-24 16:05:05 +08:00
|
|
|
this.inspector.updateTreeInfo(false);
|
2025-01-24 17:42:06 +08:00
|
|
|
const { x, y } = this.hintAdapter.convertMousePos(event, canvas);
|
2025-01-24 16:05:05 +08:00
|
|
|
const nodes = [];
|
2025-01-24 17:42:06 +08:00
|
|
|
this.inspector.forEachNode((node) => {
|
|
|
|
const b = this.hintAdapter.hitTest(node, x, y);
|
|
|
|
if (b && node.active && node.activeInHierarchy) {
|
|
|
|
nodes.push(node);
|
2025-01-24 16:05:05 +08:00
|
|
|
}
|
|
|
|
});
|
2025-01-25 16:47:56 +08:00
|
|
|
nodes.reverse();
|
|
|
|
return nodes;
|
|
|
|
}
|
|
|
|
private updateHintDown(event: MouseEvent, canvas: HTMLCanvasElement) {
|
|
|
|
this.cleanHover();
|
|
|
|
this.cleanSelected();
|
|
|
|
const nodes = this.getMouseNodes(event, canvas);
|
|
|
|
const pickTop = toRaw(appStore().config.pickTop);
|
2025-01-25 17:44:39 +08:00
|
|
|
if (nodes.length === 1 || (pickTop && nodes.length)) {
|
2025-01-24 16:05:05 +08:00
|
|
|
const item = nodes[0];
|
2025-01-25 16:47:56 +08:00
|
|
|
this.cleanHover();
|
2025-01-24 16:05:05 +08:00
|
|
|
this.setSelected(item);
|
|
|
|
this.sendInspectNodeMsg(item);
|
|
|
|
} else {
|
|
|
|
const menu = nodes.map((item) => {
|
|
|
|
const path = this.getPath(item);
|
|
|
|
return {
|
|
|
|
name: path,
|
|
|
|
callback: () => {
|
|
|
|
this.cleanHover();
|
|
|
|
this.setSelected(item);
|
|
|
|
this.sendInspectNodeMsg(item);
|
|
|
|
},
|
|
|
|
enter: () => {
|
|
|
|
this.setHover(item);
|
|
|
|
},
|
|
|
|
leave: () => {
|
|
|
|
this.cleanHover();
|
|
|
|
},
|
|
|
|
} as IUiMenuItem;
|
|
|
|
});
|
|
|
|
ccui.menu.showMenuByMouseEvent(event, menu, 0.8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private sendInspectNodeMsg(node: any) {
|
|
|
|
if (node.uuid) {
|
|
|
|
this.inspector.sendMsgToContent(Msg.InspectNode, node.uuid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private getPath(node: any) {
|
|
|
|
let path = [];
|
|
|
|
let parent = node;
|
|
|
|
while (parent) {
|
|
|
|
path.push(parent.name);
|
|
|
|
parent = parent.parent;
|
|
|
|
}
|
|
|
|
path = path.reverse();
|
|
|
|
return path.join("/");
|
|
|
|
}
|
|
|
|
private getTargetElement(): HTMLCanvasElement | null {
|
|
|
|
// @ts-ignore
|
|
|
|
if (typeof cc !== "undefined" && cc.game && cc.game.canvas) {
|
|
|
|
// @ts-ignore
|
|
|
|
return cc.game.canvas;
|
|
|
|
} else {
|
|
|
|
null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public cleanHover() {
|
|
|
|
this.hoverNodes = [];
|
2025-01-27 17:39:51 +08:00
|
|
|
this.hintAdapter && this.hintAdapter.clear();
|
2025-01-24 16:05:05 +08:00
|
|
|
}
|
|
|
|
public cleanSelected() {
|
|
|
|
this.selectedNodes = [];
|
2025-01-27 17:39:51 +08:00
|
|
|
this.hintAdapter && this.hintAdapter.clear();
|
2025-01-24 16:05:05 +08:00
|
|
|
}
|
|
|
|
private hoverNodes = [];
|
|
|
|
private selectedNodes = [];
|
|
|
|
|
|
|
|
public update() {
|
2025-01-27 17:39:51 +08:00
|
|
|
if (!this.hintAdapter) {
|
|
|
|
return;
|
|
|
|
}
|
2025-01-24 16:05:05 +08:00
|
|
|
this.hintAdapter.initDrawNode();
|
|
|
|
if (!this.hintAdapter.isDrawValid()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.hintAdapter.clear();
|
|
|
|
this.hintAdapter.resetIndex();
|
|
|
|
// this.testRect();
|
|
|
|
this.hoverNodes.forEach((node) => {
|
|
|
|
if (node.isValid) {
|
|
|
|
this.hintNode(node, {
|
|
|
|
fill: true,
|
|
|
|
fillColor: "#00ff0055",
|
|
|
|
stroke: true,
|
|
|
|
strokeColor: "#ffffff44",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
this.selectedNodes.forEach((node) => {
|
|
|
|
if (node.isValid) {
|
|
|
|
this.hintNode(node, {
|
|
|
|
fill: false,
|
|
|
|
fillColor: "#ff0000",
|
|
|
|
stroke: true,
|
|
|
|
strokeColor: "#ff0000",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
private testRect() {
|
|
|
|
const points = new RectPoints();
|
|
|
|
points.test(100, 100);
|
|
|
|
this.hintAdapter.drawRect(points, {
|
|
|
|
fill: true,
|
|
|
|
fillColor: "#00ff0099",
|
|
|
|
stroke: true,
|
|
|
|
strokeColor: "#ff000099",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
public setHover(node: any) {
|
|
|
|
if (node.isValid) {
|
|
|
|
this.hoverNodes = [node];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public setSelected(node: any) {
|
|
|
|
if (node.isValid) {
|
|
|
|
this.selectedNodes = [node];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private hintNode(node: any, opts: DrawOptions) {
|
|
|
|
const points = this.hintAdapter.getRectPoints(node);
|
|
|
|
if (!points) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.hintAdapter.drawRect(points, opts);
|
|
|
|
}
|
|
|
|
}
|