-
Notifications
You must be signed in to change notification settings - Fork 2
/
selector.ts
144 lines (128 loc) · 4.37 KB
/
selector.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/**
* @ 创建者: FBplus
* @ 创建时间: 2022-06-08 15:04:27
* @ 修改者: FBplus
* @ 修改时间: 2022-07-22 10:50:13
* @ 详情: 点选模型
*/
import * as pc from "playcanvas";
import { InputEventsMap } from "@/utils/common/InputEventsMap";
import { Tool } from "@/utils/helpers/toolBase";
import { tool, use } from "@/utils/helpers/useToolHelper";
/**
* 模型点选事件-回调表
*/
interface SelectorEventsMap
{
select: (selectedNode: pc.GraphNode, preSelectedNode: pc.GraphNode) => any;
};
/**
* 模型点选选项
*/
export interface SelectorOptions
{
inputHandler?: Tool<any, InputEventsMap>;
pickCamera?: pc.CameraComponent;
pickAreaScale?: number;
pickTag?: string;
pickNull?: boolean;
pickSame?: boolean;
pickCondition?: () => boolean;
excludeLayers?: pc.Layer[];
};
@tool("Selector")
export class Selector extends Tool<SelectorOptions, SelectorEventsMap>
{
// 默认选项
protected toolOptionsDefault: SelectorOptions = {
inputHandler: use("MouseInputer"),
pickCamera: this.app.systems.camera.cameras[0],
pickAreaScale: 0.25,
pickTag: null,
pickNull: true,
pickSame: true,
pickCondition: null,
excludeLayers: null,
};
private picker: pc.Picker;
private pickLayers: pc.Layer[];
private preSelectedNode: pc.GraphNode;
/**
* 创建模型点选器
* @param option 模型点选设置
*/
constructor(options: SelectorOptions)
{
super();
this.picker = new pc.Picker(this.app, 0, 0);
this.setOptions(options);
}
/**
* 设置模型点选器
* @param option 模型点选设置
*/
public override setOptions(options: SelectorOptions): void
{
super.setOptions(options);
// this.toolOptions.inputHandler = this.toolOptions.inputHandler || use("MouseInputer");
this.pickLayers = this.toolOptions.excludeLayers
? this.app.scene.layers.layerList.filter((layer: pc.Layer) => !this.toolOptions.excludeLayers.includes(layer))
: this.app.scene.layers.layerList;
}
/**
* 点选模型
* @param event 输入事件
* @param event.x 输入事件屏幕x坐标
* @param event.y 输入事件屏幕y坐标
*/
private pick(event: { x: number, y: number }): void
{
const options = this.toolOptions;
if (options.pickCondition && !options.pickCondition()) { return; }
const canvas = this.app.graphicsDevice.canvas;
const canvasWidth = canvas.clientWidth;
const canvasHeight = canvas.clientHeight;
this.picker.resize(canvasWidth * options.pickAreaScale, canvasHeight * options.pickAreaScale);
this.picker.prepare(options.pickCamera, this.app.scene, this.pickLayers);
const selected = this.picker.getSelection(event.x * options.pickAreaScale, event.y * options.pickAreaScale);
if (selected.length > 0 && selected[0]?.node) {
if (!options.pickTag || options.pickTag.length <= 0) {
if (!options.pickSame && this.preSelectedNode == selected[0].node) { return; }
this.fire("select", selected[0].node, this.preSelectedNode);
this.preSelectedNode = selected[0].node;
}
else {
const selectedNode = this.getModelHasTag(selected[0].node, options.pickTag);
if (!options.pickSame && this.preSelectedNode == selectedNode) { return; }
this.fire("select", selectedNode, this.preSelectedNode);
this.preSelectedNode = selectedNode;
}
}
else if (options.pickNull) {
this.fire("select", null, this.preSelectedNode);
this.preSelectedNode = null;
}
}
/**
* 从下至上找到含有某个标签的模型对象
* @param model 模型
* @param tag 标签
* @returns 包含标签的模型对象
*/
private getModelHasTag(model: pc.GraphNode, tag: string): pc.Entity
{
let node = model;
while (node && !node.tags.has(tag)) {
node = node.parent;
}
return node as pc.Entity;
}
protected override onEnable(): void
{
this.toolOptions.inputHandler.on("click", this.pick, this);
}
protected override onDisable(): void
{
this.toolOptions.inputHandler.off("click", this.pick, this);
}
}