234 lines
6.4 KiB
TypeScript
Raw Normal View History

2025-01-24 16:05:05 +08:00
import ccui from "@xuyanfeng/cc-ui";
import { IUiMenuItem } from "@xuyanfeng/cc-ui/types/cc-menu/const";
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";
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";
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();
if (event.button === 0) {
// 左键拾取
this.updateHintDown(event, el);
} else {
// 其他按键取消
2025-02-06 16:53:06 +08:00
this.pickCancel();
}
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);
}
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);
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();
}
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
}
});
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];
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);
}
}