action-engine-js 1.0.0
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/LICENSE +45 -0
- package/README.md +348 -0
- package/actionengine/3rdparty/goblin/goblin.js +9609 -0
- package/actionengine/3rdparty/goblin/goblin.min.js +5 -0
- package/actionengine/camera/actioncamera.js +90 -0
- package/actionengine/camera/cameracollisionhandler.js +69 -0
- package/actionengine/character/actioncharacter.js +360 -0
- package/actionengine/character/actioncharacter3D.js +61 -0
- package/actionengine/core/app.js +430 -0
- package/actionengine/debug/basedebugpanel.js +858 -0
- package/actionengine/display/canvasmanager.js +75 -0
- package/actionengine/display/gl/programmanager.js +570 -0
- package/actionengine/display/gl/shaders/lineshader.js +118 -0
- package/actionengine/display/gl/shaders/objectshader.js +1756 -0
- package/actionengine/display/gl/shaders/particleshader.js +43 -0
- package/actionengine/display/gl/shaders/shadowshader.js +319 -0
- package/actionengine/display/gl/shaders/spriteshader.js +100 -0
- package/actionengine/display/gl/shaders/watershader.js +67 -0
- package/actionengine/display/graphics/actionmodel3D.js +191 -0
- package/actionengine/display/graphics/actionsprite3D.js +230 -0
- package/actionengine/display/graphics/lighting/actiondirectionalshadowlight.js +864 -0
- package/actionengine/display/graphics/lighting/actionlight.js +211 -0
- package/actionengine/display/graphics/lighting/actionomnidirectionalshadowlight.js +862 -0
- package/actionengine/display/graphics/lighting/lightingconstants.js +263 -0
- package/actionengine/display/graphics/lighting/lightmanager.js +789 -0
- package/actionengine/display/graphics/renderableobject.js +44 -0
- package/actionengine/display/graphics/renderers/actionrenderer2D.js +341 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/actionrenderer3D.js +655 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/canvasmanager3D.js +82 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/debugrenderer3D.js +493 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/objectrenderer3D.js +790 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/spriteRenderer3D.js +266 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/sunrenderer3D.js +140 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/waterrenderer3D.js +173 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/weatherrenderer3D.js +87 -0
- package/actionengine/display/graphics/texture/proceduraltexture.js +192 -0
- package/actionengine/display/graphics/texture/texturemanager.js +242 -0
- package/actionengine/display/graphics/texture/textureregistry.js +177 -0
- package/actionengine/input/actionscrollablearea.js +1405 -0
- package/actionengine/input/inputhandler.js +1647 -0
- package/actionengine/math/geometry/geometrybuilder.js +161 -0
- package/actionengine/math/geometry/glbexporter.js +364 -0
- package/actionengine/math/geometry/glbloader.js +722 -0
- package/actionengine/math/geometry/modelcodegenerator.js +97 -0
- package/actionengine/math/geometry/triangle.js +33 -0
- package/actionengine/math/geometry/triangleutils.js +34 -0
- package/actionengine/math/mathutils.js +25 -0
- package/actionengine/math/matrix4.js +785 -0
- package/actionengine/math/physics/actionphysics.js +108 -0
- package/actionengine/math/physics/actionphysicsobject3D.js +164 -0
- package/actionengine/math/physics/actionphysicsworld3D.js +238 -0
- package/actionengine/math/physics/actionraycast.js +129 -0
- package/actionengine/math/physics/shapes/actionphysicsbox3D.js +158 -0
- package/actionengine/math/physics/shapes/actionphysicscapsule3D.js +200 -0
- package/actionengine/math/physics/shapes/actionphysicscompoundshape3D.js +147 -0
- package/actionengine/math/physics/shapes/actionphysicscone3D.js +126 -0
- package/actionengine/math/physics/shapes/actionphysicsconvexshape3D.js +72 -0
- package/actionengine/math/physics/shapes/actionphysicscylinder3D.js +117 -0
- package/actionengine/math/physics/shapes/actionphysicsmesh3D.js +74 -0
- package/actionengine/math/physics/shapes/actionphysicsplane3D.js +100 -0
- package/actionengine/math/physics/shapes/actionphysicssphere3D.js +95 -0
- package/actionengine/math/quaternion.js +61 -0
- package/actionengine/math/vector2.js +277 -0
- package/actionengine/math/vector3.js +318 -0
- package/actionengine/math/viewfrustum.js +136 -0
- package/actionengine/network/ACTIONNETREADME.md +810 -0
- package/actionengine/network/client/ActionNetManager.js +802 -0
- package/actionengine/network/client/ActionNetManagerGUI.js +1709 -0
- package/actionengine/network/client/ActionNetManagerP2P.js +1537 -0
- package/actionengine/network/client/SyncSystem.js +422 -0
- package/actionengine/network/p2p/ActionNetPeer.js +142 -0
- package/actionengine/network/p2p/ActionNetTrackerClient.js +623 -0
- package/actionengine/network/p2p/DataConnection.js +282 -0
- package/actionengine/network/p2p/README.md +510 -0
- package/actionengine/network/p2p/example.html +502 -0
- package/actionengine/network/server/ActionNetServer.js +577 -0
- package/actionengine/network/server/ActionNetServerSSL.js +579 -0
- package/actionengine/network/server/ActionNetServerUtils.js +458 -0
- package/actionengine/network/server/SERVERREADME.md +314 -0
- package/actionengine/network/server/package-lock.json +35 -0
- package/actionengine/network/server/package.json +13 -0
- package/actionengine/network/server/start.bat +27 -0
- package/actionengine/network/server/start.sh +25 -0
- package/actionengine/network/server/startwss.bat +27 -0
- package/actionengine/sound/audiomanager.js +1589 -0
- package/actionengine/sound/soundfont/ACTIONSOUNDFONT_README.md +205 -0
- package/actionengine/sound/soundfont/actionparser.js +718 -0
- package/actionengine/sound/soundfont/actionreverb.js +252 -0
- package/actionengine/sound/soundfont/actionsoundfont.js +543 -0
- package/actionengine/sound/soundfont/sf2playerlicence.txt +29 -0
- package/actionengine/sound/soundfont/soundfont.js +2 -0
- package/dist/action-engine.min.js +328 -0
- package/package.json +35 -0
|
@@ -0,0 +1,858 @@
|
|
|
1
|
+
// game/debug/basedebugpanel.js
|
|
2
|
+
class BaseDebugPanel {
|
|
3
|
+
constructor(debugCanvas, game, options = {}) {
|
|
4
|
+
this.canvas = debugCanvas;
|
|
5
|
+
this.ctx = debugCanvas.getContext("2d");
|
|
6
|
+
this.game = game;
|
|
7
|
+
|
|
8
|
+
// Panel state
|
|
9
|
+
this.visible = false;
|
|
10
|
+
this.activeTab = options.defaultTab || 'main';
|
|
11
|
+
|
|
12
|
+
// UI settings
|
|
13
|
+
this.panelWidth = options.panelWidth || 400;
|
|
14
|
+
this.panelHeight = options.panelHeight || 500;
|
|
15
|
+
this.panelX = options.panelX || 20;
|
|
16
|
+
this.panelY = options.panelY || (this.canvas.height - this.panelHeight) / 2;
|
|
17
|
+
|
|
18
|
+
// Tabs (can be overridden by child classes)
|
|
19
|
+
this.tabs = options.tabs || [
|
|
20
|
+
{ id: 'main', label: 'Main' }
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
// Configure toggle button
|
|
24
|
+
this.toggleButton = {
|
|
25
|
+
x: options.toggleX || (this.canvas.width - 150) / 2,
|
|
26
|
+
y: options.toggleY || 10,
|
|
27
|
+
width: options.toggleWidth || 150,
|
|
28
|
+
height: options.toggleHeight || 30,
|
|
29
|
+
text: options.toggleText || "Debug Panel",
|
|
30
|
+
color: options.toggleColor || "#444444"
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Register toggle button with input system if toggleId is provided
|
|
34
|
+
if (options.toggleId) {
|
|
35
|
+
this.toggleId = options.toggleId;
|
|
36
|
+
this.game.input.registerElement(
|
|
37
|
+
this.toggleId,
|
|
38
|
+
{
|
|
39
|
+
bounds: () => ({
|
|
40
|
+
x: this.toggleButton.x,
|
|
41
|
+
y: this.toggleButton.y,
|
|
42
|
+
width: this.toggleButton.width,
|
|
43
|
+
height: this.toggleButton.height
|
|
44
|
+
})
|
|
45
|
+
},
|
|
46
|
+
"debug"
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Register the tab buttons
|
|
51
|
+
this.tabs.forEach((tab, index) => {
|
|
52
|
+
this.game.input.registerElement(
|
|
53
|
+
`${options.panelId || 'debug'}_tab_${tab.id}`,
|
|
54
|
+
{
|
|
55
|
+
bounds: () => ({
|
|
56
|
+
x: this.panelX + (index * (this.panelWidth / this.tabs.length)),
|
|
57
|
+
y: this.panelY,
|
|
58
|
+
width: this.panelWidth / this.tabs.length,
|
|
59
|
+
height: 30
|
|
60
|
+
})
|
|
61
|
+
},
|
|
62
|
+
"debug"
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Configuration for number formatting
|
|
67
|
+
this.roundingConfig = {
|
|
68
|
+
defaultPrecision: 2, // Default decimal places
|
|
69
|
+
fpsPrecision: 1, // FPS decimal places
|
|
70
|
+
positionPrecision: 2, // Position decimal places
|
|
71
|
+
anglePrecision: 4, // Normal/angle decimal places
|
|
72
|
+
timePrecision: 1 // Time/ms decimal places
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Initialize Map to store input field registrations
|
|
76
|
+
this.inputFields = new Map();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Utility function to round a number to specified decimals
|
|
80
|
+
roundTo(num, decimals = this.roundingConfig.defaultPrecision) {
|
|
81
|
+
const multiplier = Math.pow(10, decimals);
|
|
82
|
+
return Math.round(num * multiplier) / multiplier;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Format a Vector3 to a string
|
|
86
|
+
formatVector(vec) {
|
|
87
|
+
if (!vec) return "0,0,0";
|
|
88
|
+
return `${this.roundTo(vec.x || 0, this.roundingConfig.positionPrecision)},${this.roundTo(vec.y || 0, this.roundingConfig.positionPrecision)},${this.roundTo(vec.z || 0, this.roundingConfig.positionPrecision)}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Helper color functions
|
|
92
|
+
lightenColor(color) {
|
|
93
|
+
const r = parseInt(color.substr(1, 2), 16);
|
|
94
|
+
const g = parseInt(color.substr(3, 2), 16);
|
|
95
|
+
const b = parseInt(color.substr(5, 2), 16);
|
|
96
|
+
const factor = 1.3; // Lighten by 30%
|
|
97
|
+
|
|
98
|
+
return `#${Math.min(255, Math.floor(r * factor)).toString(16).padStart(2, '0')}${Math.min(255, Math.floor(g * factor)).toString(16).padStart(2, '0')}${Math.min(255, Math.floor(b * factor)).toString(16).padStart(2, '0')}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
darkenColor(color) {
|
|
102
|
+
const r = parseInt(color.substr(1, 2), 16);
|
|
103
|
+
const g = parseInt(color.substr(3, 2), 16);
|
|
104
|
+
const b = parseInt(color.substr(5, 2), 16);
|
|
105
|
+
const factor = 0.8;
|
|
106
|
+
return `#${Math.floor(r * factor).toString(16).padStart(2, "0")}${Math.floor(g * factor).toString(16).padStart(2, "0")}${Math.floor(b * factor).toString(16).padStart(2, "0")}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Register sliders with input system - similar to LightingDebugPanel
|
|
110
|
+
registerSliders(sliders, tabName) {
|
|
111
|
+
// Clear any existing slider elements for this tab
|
|
112
|
+
Object.entries(sliders).forEach(([name, slider]) => {
|
|
113
|
+
this.game.input.removeElement(slider.id, "debug");
|
|
114
|
+
if (slider.options) {
|
|
115
|
+
this.game.input.removeElement(`${slider.id}_left`, "debug");
|
|
116
|
+
this.game.input.removeElement(`${slider.id}_right`, "debug");
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Register each slider with unique bounds
|
|
121
|
+
Object.entries(sliders).forEach(([name, slider], index) => {
|
|
122
|
+
// Register the slider track
|
|
123
|
+
this.game.input.registerElement(
|
|
124
|
+
slider.id,
|
|
125
|
+
{
|
|
126
|
+
bounds: () => ({
|
|
127
|
+
x: this.panelX + 160,
|
|
128
|
+
y: this.panelY + 100 + (index * 40),
|
|
129
|
+
width: 180,
|
|
130
|
+
height: 20
|
|
131
|
+
})
|
|
132
|
+
},
|
|
133
|
+
"debug"
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
// For sliders with discrete options, register left/right buttons
|
|
137
|
+
if (slider.options) {
|
|
138
|
+
// Left button
|
|
139
|
+
this.game.input.registerElement(
|
|
140
|
+
`${slider.id}_left`,
|
|
141
|
+
{
|
|
142
|
+
bounds: () => ({
|
|
143
|
+
x: this.panelX + 160 - 30,
|
|
144
|
+
y: this.panelY + 100 + (index * 40),
|
|
145
|
+
width: 20,
|
|
146
|
+
height: 20
|
|
147
|
+
})
|
|
148
|
+
},
|
|
149
|
+
"debug"
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Right button
|
|
153
|
+
this.game.input.registerElement(
|
|
154
|
+
`${slider.id}_right`,
|
|
155
|
+
{
|
|
156
|
+
bounds: () => ({
|
|
157
|
+
x: this.panelX + 160 + 190,
|
|
158
|
+
y: this.panelY + 100 + (index * 40),
|
|
159
|
+
width: 20,
|
|
160
|
+
height: 20
|
|
161
|
+
})
|
|
162
|
+
},
|
|
163
|
+
"debug"
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Register buttons with the input system
|
|
170
|
+
registerButtons(buttons) {
|
|
171
|
+
buttons.forEach((button) => {
|
|
172
|
+
this.game.input.registerElement(
|
|
173
|
+
button.id,
|
|
174
|
+
{
|
|
175
|
+
bounds: () => ({
|
|
176
|
+
x: button.x,
|
|
177
|
+
y: button.y,
|
|
178
|
+
width: button.width,
|
|
179
|
+
height: button.height
|
|
180
|
+
})
|
|
181
|
+
},
|
|
182
|
+
"debug"
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Register toggle controls with the input system
|
|
188
|
+
registerToggles(toggles) {
|
|
189
|
+
toggles.forEach((toggle, index) => {
|
|
190
|
+
this.game.input.registerElement(
|
|
191
|
+
toggle.id,
|
|
192
|
+
{
|
|
193
|
+
bounds: () => ({
|
|
194
|
+
x: this.panelX + 20,
|
|
195
|
+
y: this.panelY + 100 + (index * 30),
|
|
196
|
+
width: 20,
|
|
197
|
+
height: 20
|
|
198
|
+
})
|
|
199
|
+
},
|
|
200
|
+
"debug"
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Handle slider interactions
|
|
206
|
+
handleOptionSliders(sliders) {
|
|
207
|
+
if (!sliders) return;
|
|
208
|
+
|
|
209
|
+
// Check for edit button clicks
|
|
210
|
+
this.inputFields.forEach((info, editBtnId) => {
|
|
211
|
+
if (this.game.input.isElementJustPressed(editBtnId, "debug")) {
|
|
212
|
+
console.log(`Edit button clicked for ${info.name}`);
|
|
213
|
+
this.showInputDialog(info.name, info.slider);
|
|
214
|
+
return; // Exit early if we found a clicked button
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
Object.entries(sliders).forEach(([name, slider]) => {
|
|
219
|
+
// Handle discrete option sliders (with left/right buttons)
|
|
220
|
+
if (slider.options) {
|
|
221
|
+
// Left button (decrease)
|
|
222
|
+
if (this.game.input.isElementJustPressed(`${slider.id}_left`, "debug")) {
|
|
223
|
+
slider.currentOption = Math.max(0, slider.currentOption - 1);
|
|
224
|
+
slider.value = slider.options[slider.currentOption];
|
|
225
|
+
if (slider.updateProperty) {
|
|
226
|
+
slider.updateProperty(slider.value);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Right button (increase)
|
|
231
|
+
if (this.game.input.isElementJustPressed(`${slider.id}_right`, "debug")) {
|
|
232
|
+
slider.currentOption = Math.min(slider.options.length - 1, slider.currentOption + 1);
|
|
233
|
+
slider.value = slider.options[slider.currentOption];
|
|
234
|
+
if (slider.updateProperty) {
|
|
235
|
+
slider.updateProperty(slider.value);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Handle continuous sliders
|
|
240
|
+
else {
|
|
241
|
+
// Direct method similar to debugpanel.js
|
|
242
|
+
if (this.game.input.isElementPressed(slider.id, "debug")) {
|
|
243
|
+
const pointerX = this.game.input.getPointerPosition().x;
|
|
244
|
+
const sliderStartX = this.panelX + 160;
|
|
245
|
+
const sliderWidth = 180;
|
|
246
|
+
|
|
247
|
+
// Calculate normalized position (0-1)
|
|
248
|
+
const percentage = Math.max(0, Math.min(1, (pointerX - sliderStartX) / sliderWidth));
|
|
249
|
+
|
|
250
|
+
// Calculate actual value based on min/max
|
|
251
|
+
let newValue = slider.min + (slider.max - slider.min) * percentage;
|
|
252
|
+
|
|
253
|
+
// Apply step if defined
|
|
254
|
+
if (slider.step) {
|
|
255
|
+
newValue = Math.round(newValue / slider.step) * slider.step;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Update slider value
|
|
259
|
+
slider.value = newValue;
|
|
260
|
+
if (slider.updateProperty) {
|
|
261
|
+
slider.updateProperty(newValue);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Initialize input dialog if needed
|
|
269
|
+
initializeInputDialog() {
|
|
270
|
+
if (!this.inputDialog) {
|
|
271
|
+
this.createInputDialog();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Draw sliders on the panel
|
|
276
|
+
drawSliders(sliders) {
|
|
277
|
+
// Make sure input dialog is created
|
|
278
|
+
this.initializeInputDialog();
|
|
279
|
+
|
|
280
|
+
// Register edit buttons if they haven't been registered yet
|
|
281
|
+
if (Object.keys(sliders).length > 0 && this.inputFields.size === 0) {
|
|
282
|
+
this.registerEditButtons(sliders);
|
|
283
|
+
}
|
|
284
|
+
Object.entries(sliders).forEach(([name, slider], index) => {
|
|
285
|
+
const sliderY = this.panelY + 100 + (index * 40);
|
|
286
|
+
|
|
287
|
+
// Draw label
|
|
288
|
+
this.ctx.fillStyle = "#ffffff";
|
|
289
|
+
this.ctx.font = "14px Arial";
|
|
290
|
+
this.ctx.textAlign = "right";
|
|
291
|
+
this.ctx.fillText(name, this.panelX + 150, sliderY + 10);
|
|
292
|
+
|
|
293
|
+
// For sliders with discrete options
|
|
294
|
+
if (slider.options) {
|
|
295
|
+
// Draw left/right buttons
|
|
296
|
+
this.drawOptionButtons(slider, sliderY);
|
|
297
|
+
|
|
298
|
+
// Draw current value
|
|
299
|
+
this.ctx.textAlign = "center";
|
|
300
|
+
this.ctx.fillText(slider.value.toString(), this.panelX + 250, sliderY + 10);
|
|
301
|
+
}
|
|
302
|
+
// For continuous sliders
|
|
303
|
+
else {
|
|
304
|
+
// Draw slider background track
|
|
305
|
+
this.ctx.fillStyle = "#444444";
|
|
306
|
+
this.ctx.fillRect(this.panelX + 160, sliderY, 180, 20);
|
|
307
|
+
|
|
308
|
+
// Calculate position based on value (clamped for display purposes)
|
|
309
|
+
let displayPercentage = 0;
|
|
310
|
+
if (slider.min !== undefined && slider.max !== undefined) {
|
|
311
|
+
// Clamp the display percentage between 0 and 1
|
|
312
|
+
displayPercentage = Math.max(0, Math.min(1, (slider.value - slider.min) / (slider.max - slider.min)));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Draw slider value fill
|
|
316
|
+
if (slider.outOfRange) {
|
|
317
|
+
// Use a special color for out-of-range values
|
|
318
|
+
this.ctx.fillStyle = (slider.value < slider.min) ? "#aa5500" : "#aa0055";
|
|
319
|
+
} else {
|
|
320
|
+
this.ctx.fillStyle = this.game.input.isElementPressed(slider.id, "debug") ? "#00ff00" : "#00aa00";
|
|
321
|
+
}
|
|
322
|
+
this.ctx.fillRect(this.panelX + 160, sliderY, 180 * displayPercentage, 20);
|
|
323
|
+
|
|
324
|
+
// Draw slider handle
|
|
325
|
+
this.ctx.fillStyle = slider.outOfRange ? "#ffaa00" : "#ffffff";
|
|
326
|
+
this.ctx.fillRect(this.panelX + 160 + (180 * displayPercentage) - 2, sliderY - 2, 4, 24);
|
|
327
|
+
|
|
328
|
+
// Draw value text
|
|
329
|
+
this.ctx.textAlign = "right";
|
|
330
|
+
const valueText = Number.isInteger(slider.value) ? slider.value.toString() : slider.value.toFixed(6);
|
|
331
|
+
|
|
332
|
+
// Use different text color for out-of-range values
|
|
333
|
+
if (slider.outOfRange) {
|
|
334
|
+
this.ctx.fillStyle = "#ffaa00";
|
|
335
|
+
// Add indicator for out-of-range values
|
|
336
|
+
if (slider.value < slider.min) {
|
|
337
|
+
this.ctx.fillText(`${valueText} (< min)`, this.panelX + 380, sliderY + 10);
|
|
338
|
+
} else {
|
|
339
|
+
this.ctx.fillText(`${valueText} (> max)`, this.panelX + 380, sliderY + 10);
|
|
340
|
+
}
|
|
341
|
+
} else {
|
|
342
|
+
this.ctx.fillStyle = "#ffffff";
|
|
343
|
+
this.ctx.fillText(valueText, this.panelX + 380, sliderY + 10);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Draw "Edit" button for precise value input
|
|
347
|
+
const hoverId = `${slider.id}_edit`;
|
|
348
|
+
const btnInfo = this.inputFields.get(hoverId);
|
|
349
|
+
|
|
350
|
+
if (btnInfo) {
|
|
351
|
+
const btnX = btnInfo.x;
|
|
352
|
+
const btnY = btnInfo.y;
|
|
353
|
+
const btnWidth = btnInfo.width;
|
|
354
|
+
const btnHeight = btnInfo.height;
|
|
355
|
+
|
|
356
|
+
// Check if mouse is hovering over the edit button
|
|
357
|
+
const isHovered = this.game.input.isElementHovered(hoverId, "debug");
|
|
358
|
+
|
|
359
|
+
// Draw edit button
|
|
360
|
+
this.ctx.fillStyle = isHovered ? "#5555ff" : "#3333aa";
|
|
361
|
+
this.ctx.fillRect(btnX, btnY, btnWidth, btnHeight);
|
|
362
|
+
this.ctx.strokeStyle = "#ffffff";
|
|
363
|
+
this.ctx.lineWidth = 1;
|
|
364
|
+
this.ctx.strokeRect(btnX, btnY, btnWidth, btnHeight);
|
|
365
|
+
|
|
366
|
+
// Draw edit button text
|
|
367
|
+
this.ctx.fillStyle = "#ffffff";
|
|
368
|
+
this.ctx.textAlign = "center";
|
|
369
|
+
this.ctx.textBaseline = "middle";
|
|
370
|
+
this.ctx.fillText("Edit", btnX + btnWidth/2, btnY + btnHeight/2);
|
|
371
|
+
this.ctx.textBaseline = "alphabetic";
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Draw option buttons for discrete sliders
|
|
378
|
+
drawOptionButtons(slider, sliderY) {
|
|
379
|
+
// Draw left button
|
|
380
|
+
const leftButtonX = this.panelX + 160 - 30;
|
|
381
|
+
const isLeftHovered = this.game.input.isElementHovered(`${slider.id}_left`, "debug");
|
|
382
|
+
this.ctx.fillStyle = isLeftHovered ? "#666666" : "#444444";
|
|
383
|
+
this.ctx.fillRect(leftButtonX, sliderY, 20, 20);
|
|
384
|
+
|
|
385
|
+
this.ctx.fillStyle = "#ffffff";
|
|
386
|
+
this.ctx.textAlign = "center";
|
|
387
|
+
this.ctx.fillText("<", leftButtonX + 10, sliderY + 10);
|
|
388
|
+
|
|
389
|
+
// Draw right button
|
|
390
|
+
const rightButtonX = this.panelX + 160 + 190;
|
|
391
|
+
const isRightHovered = this.game.input.isElementHovered(`${slider.id}_right`, "debug");
|
|
392
|
+
this.ctx.fillStyle = isRightHovered ? "#666666" : "#444444";
|
|
393
|
+
this.ctx.fillRect(rightButtonX, sliderY, 20, 20);
|
|
394
|
+
|
|
395
|
+
this.ctx.fillStyle = "#ffffff";
|
|
396
|
+
this.ctx.textAlign = "center";
|
|
397
|
+
this.ctx.fillText(">", rightButtonX + 10, sliderY + 10);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Draw toggle controls
|
|
401
|
+
drawToggles(toggles) {
|
|
402
|
+
this.ctx.textAlign = "left";
|
|
403
|
+
this.ctx.font = "14px Arial";
|
|
404
|
+
|
|
405
|
+
toggles.forEach((toggle, index) => {
|
|
406
|
+
const toggleX = this.panelX + 20;
|
|
407
|
+
const toggleY = this.panelY + 100 + (index * 30);
|
|
408
|
+
|
|
409
|
+
// Draw checkbox
|
|
410
|
+
this.ctx.strokeStyle = "#ffffff";
|
|
411
|
+
this.ctx.lineWidth = 2;
|
|
412
|
+
this.ctx.strokeRect(toggleX, toggleY, 20, 20);
|
|
413
|
+
|
|
414
|
+
// Draw check if enabled
|
|
415
|
+
if (toggle.checked) {
|
|
416
|
+
this.ctx.fillStyle = "#55ff55";
|
|
417
|
+
this.ctx.fillRect(toggleX + 4, toggleY + 4, 12, 12);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Draw label (increased spacing from 30 to 40 pixels to prevent overlap)
|
|
421
|
+
this.ctx.fillStyle = "#ffffff";
|
|
422
|
+
this.ctx.fillText(toggle.label, toggleX + 40, toggleY + 14);
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Draw button controls
|
|
427
|
+
drawButtons(buttons) {
|
|
428
|
+
buttons.forEach(button => {
|
|
429
|
+
const isHovered = this.game.input.isElementHovered(button.id, "debug");
|
|
430
|
+
|
|
431
|
+
// Draw button background
|
|
432
|
+
this.ctx.fillStyle = isHovered ? this.lightenColor(button.color) : button.color;
|
|
433
|
+
this.ctx.fillRect(button.x, button.y, button.width, button.height);
|
|
434
|
+
|
|
435
|
+
// Draw button border
|
|
436
|
+
this.ctx.strokeStyle = "#ffffff";
|
|
437
|
+
this.ctx.lineWidth = 2;
|
|
438
|
+
this.ctx.strokeRect(button.x, button.y, button.width, button.height);
|
|
439
|
+
|
|
440
|
+
// Draw button text
|
|
441
|
+
this.ctx.fillStyle = "#ffffff";
|
|
442
|
+
this.ctx.textAlign = "center";
|
|
443
|
+
this.ctx.textBaseline = "middle";
|
|
444
|
+
this.ctx.fillText(button.label, button.x + button.width / 2, button.y + button.height / 2);
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Draw the toggle button to show/hide the panel
|
|
449
|
+
drawToggleButton() {
|
|
450
|
+
if (!this.toggleId) return;
|
|
451
|
+
|
|
452
|
+
const isHovered = this.game.input.isElementHovered(this.toggleId, "debug");
|
|
453
|
+
const baseColor = this.visible ? "#00aa00" : "#666666";
|
|
454
|
+
const hoverColor = this.visible ? "#00cc00" : "#888888";
|
|
455
|
+
|
|
456
|
+
// Draw button background
|
|
457
|
+
this.ctx.fillStyle = isHovered ? hoverColor : baseColor;
|
|
458
|
+
this.ctx.fillRect(
|
|
459
|
+
this.toggleButton.x,
|
|
460
|
+
this.toggleButton.y,
|
|
461
|
+
this.toggleButton.width,
|
|
462
|
+
this.toggleButton.height
|
|
463
|
+
);
|
|
464
|
+
|
|
465
|
+
// Draw button text
|
|
466
|
+
this.ctx.fillStyle = "#ffffff";
|
|
467
|
+
this.ctx.font = "14px Arial";
|
|
468
|
+
this.ctx.textAlign = "center";
|
|
469
|
+
this.ctx.textBaseline = "middle";
|
|
470
|
+
this.ctx.fillText(
|
|
471
|
+
this.toggleButton.text,
|
|
472
|
+
this.toggleButton.x + this.toggleButton.width / 2,
|
|
473
|
+
this.toggleButton.y + this.toggleButton.height / 2
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Draw the tabs at the top of the panel
|
|
478
|
+
drawTabs() {
|
|
479
|
+
this.tabs.forEach((tab, index) => {
|
|
480
|
+
const tabX = this.panelX + (index * (this.panelWidth / this.tabs.length));
|
|
481
|
+
const tabWidth = this.panelWidth / this.tabs.length;
|
|
482
|
+
const isActive = this.activeTab === tab.id;
|
|
483
|
+
|
|
484
|
+
// For Scene panel we need to use "scene" as the prefix
|
|
485
|
+
let panelPrefix;
|
|
486
|
+
if (this.toggleId === 'sceneDebugToggle') {
|
|
487
|
+
panelPrefix = 'scene';
|
|
488
|
+
} else if (this.toggleId === 'weatherDebugToggle') {
|
|
489
|
+
panelPrefix = 'weather';
|
|
490
|
+
} else if (this.toggleId === 'lightingToggleButton') {
|
|
491
|
+
panelPrefix = 'lighting';
|
|
492
|
+
} else {
|
|
493
|
+
panelPrefix = this.toggleId ? this.toggleId.split('Toggle')[0] : 'debug';
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const tabElementId = `${panelPrefix}_tab_${tab.id}`;
|
|
497
|
+
const isHovered = this.game.input.isElementHovered(tabElementId, "debug");
|
|
498
|
+
|
|
499
|
+
// Tab background
|
|
500
|
+
this.ctx.fillStyle = isActive ? "#559955" : (isHovered ? "#557755" : "#444444");
|
|
501
|
+
this.ctx.fillRect(tabX, this.panelY, tabWidth, 30);
|
|
502
|
+
|
|
503
|
+
// Tab label
|
|
504
|
+
this.ctx.fillStyle = "#ffffff";
|
|
505
|
+
this.ctx.font = "14px Arial";
|
|
506
|
+
this.ctx.textAlign = "center";
|
|
507
|
+
this.ctx.textBaseline = "middle";
|
|
508
|
+
this.ctx.fillText(tab.label, tabX + tabWidth / 2, this.panelY + 15);
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Update method to handle input and panel state
|
|
513
|
+
update() {
|
|
514
|
+
// Check toggle button state if it exists
|
|
515
|
+
if (this.toggleId && this.game.input.isElementJustPressed(this.toggleId, "debug")) {
|
|
516
|
+
this.visible = !this.visible;
|
|
517
|
+
|
|
518
|
+
// If panel is becoming visible, additional initialization can be done here
|
|
519
|
+
if (this.visible) {
|
|
520
|
+
this.lastActivatedTime = Date.now();
|
|
521
|
+
this.onShow();
|
|
522
|
+
} else {
|
|
523
|
+
this.onHide();
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// If panel isn't visible, no need to check other inputs
|
|
528
|
+
if (!this.visible) return;
|
|
529
|
+
|
|
530
|
+
// Check tab selection
|
|
531
|
+
this.tabs.forEach(tab => {
|
|
532
|
+
// For Scene panel we need to use "scene" as the prefix
|
|
533
|
+
let panelPrefix;
|
|
534
|
+
if (this.toggleId === 'sceneDebugToggle') {
|
|
535
|
+
panelPrefix = 'scene';
|
|
536
|
+
} else if (this.toggleId === 'weatherDebugToggle') {
|
|
537
|
+
panelPrefix = 'weather';
|
|
538
|
+
} else if (this.toggleId === 'lightingToggleButton') {
|
|
539
|
+
panelPrefix = 'lighting';
|
|
540
|
+
} else {
|
|
541
|
+
panelPrefix = this.toggleId ? this.toggleId.split('Toggle')[0] : 'debug';
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const tabElementId = `${panelPrefix}_tab_${tab.id}`;
|
|
545
|
+
|
|
546
|
+
if (this.game.input.isElementJustPressed(tabElementId, "debug")) {
|
|
547
|
+
this.activeTab = tab.id;
|
|
548
|
+
this.onTabChange(tab.id);
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
// Child classes should implement their specific update logic
|
|
553
|
+
this.updateContent();
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Override these methods in child classes
|
|
557
|
+
onShow() {
|
|
558
|
+
// Called when panel becomes visible
|
|
559
|
+
this.lastActivatedTime = Date.now();
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
updateContent() {
|
|
564
|
+
// Update panel content, handle input, etc.
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Main draw method
|
|
568
|
+
draw() {
|
|
569
|
+
// Draw toggle button if we have one
|
|
570
|
+
if (this.toggleId) {
|
|
571
|
+
this.drawToggleButton();
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// If panel isn't visible, don't draw it
|
|
575
|
+
if (!this.visible) return;
|
|
576
|
+
|
|
577
|
+
// Draw panel background
|
|
578
|
+
this.ctx.fillStyle = "rgba(0, 0, 0, 0.85)";
|
|
579
|
+
this.ctx.fillRect(this.panelX, this.panelY, this.panelWidth, this.panelHeight);
|
|
580
|
+
|
|
581
|
+
// Draw tabs if we have multiple
|
|
582
|
+
if (this.tabs.length > 1) {
|
|
583
|
+
this.drawTabs();
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Child classes should implement their specific draw logic in drawContent
|
|
587
|
+
this.drawContent();
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Override this method in child classes
|
|
591
|
+
drawContent() {
|
|
592
|
+
// Draw panel content based on active tab
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Show an input dialog for precise value editing
|
|
596
|
+
showInputDialog(sliderName, slider) {
|
|
597
|
+
console.log(`Showing input dialog for ${sliderName}, current value: ${slider.value}`);
|
|
598
|
+
// Create modal dialog elements if they don't exist
|
|
599
|
+
if (!this.inputDialog) {
|
|
600
|
+
this.createInputDialog();
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Set dialog title and current value
|
|
604
|
+
this.dialogTitle.textContent = `Edit ${sliderName}`;
|
|
605
|
+
this.dialogInput.value = slider.value.toString();
|
|
606
|
+
this.currentSlider = slider;
|
|
607
|
+
|
|
608
|
+
// Show the dialog
|
|
609
|
+
this.inputDialogOverlay.style.display = 'block';
|
|
610
|
+
this.inputDialog.style.display = 'block';
|
|
611
|
+
|
|
612
|
+
// Focus the input field
|
|
613
|
+
setTimeout(() => {
|
|
614
|
+
this.dialogInput.focus();
|
|
615
|
+
this.dialogInput.select();
|
|
616
|
+
}, 10);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// Create the input dialog DOM elements
|
|
620
|
+
createInputDialog() {
|
|
621
|
+
// Create overlay for modal effect
|
|
622
|
+
this.inputDialogOverlay = document.createElement('div');
|
|
623
|
+
this.inputDialogOverlay.style.position = 'fixed';
|
|
624
|
+
this.inputDialogOverlay.style.top = '0';
|
|
625
|
+
this.inputDialogOverlay.style.left = '0';
|
|
626
|
+
this.inputDialogOverlay.style.width = '100%';
|
|
627
|
+
this.inputDialogOverlay.style.height = '100%';
|
|
628
|
+
this.inputDialogOverlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
|
|
629
|
+
this.inputDialogOverlay.style.zIndex = '999';
|
|
630
|
+
this.inputDialogOverlay.style.display = 'none';
|
|
631
|
+
|
|
632
|
+
// Create dialog container
|
|
633
|
+
this.inputDialog = document.createElement('div');
|
|
634
|
+
this.inputDialog.style.position = 'fixed';
|
|
635
|
+
this.inputDialog.style.top = '50%';
|
|
636
|
+
this.inputDialog.style.left = '50%';
|
|
637
|
+
this.inputDialog.style.transform = 'translate(-50%, -50%)';
|
|
638
|
+
this.inputDialog.style.backgroundColor = '#333';
|
|
639
|
+
this.inputDialog.style.border = '2px solid #555';
|
|
640
|
+
this.inputDialog.style.borderRadius = '5px';
|
|
641
|
+
this.inputDialog.style.padding = '15px';
|
|
642
|
+
this.inputDialog.style.zIndex = '1000';
|
|
643
|
+
this.inputDialog.style.minWidth = '250px';
|
|
644
|
+
this.inputDialog.style.color = '#fff';
|
|
645
|
+
this.inputDialog.style.display = 'none';
|
|
646
|
+
|
|
647
|
+
// Create dialog title
|
|
648
|
+
this.dialogTitle = document.createElement('div');
|
|
649
|
+
this.dialogTitle.style.fontSize = '16px';
|
|
650
|
+
this.dialogTitle.style.fontWeight = 'bold';
|
|
651
|
+
this.dialogTitle.style.marginBottom = '10px';
|
|
652
|
+
this.dialogTitle.textContent = 'Edit Value';
|
|
653
|
+
|
|
654
|
+
// Create input field
|
|
655
|
+
this.dialogInput = document.createElement('input');
|
|
656
|
+
this.dialogInput.type = 'text';
|
|
657
|
+
this.dialogInput.style.width = '100%';
|
|
658
|
+
this.dialogInput.style.padding = '5px';
|
|
659
|
+
this.dialogInput.style.marginBottom = '15px';
|
|
660
|
+
this.dialogInput.style.backgroundColor = '#222288';
|
|
661
|
+
this.dialogInput.style.color = '#fff';
|
|
662
|
+
this.dialogInput.style.border = '1px solid #555';
|
|
663
|
+
this.dialogInput.style.borderRadius = '3px';
|
|
664
|
+
|
|
665
|
+
// Create button container
|
|
666
|
+
const buttonContainer = document.createElement('div');
|
|
667
|
+
buttonContainer.style.display = 'flex';
|
|
668
|
+
buttonContainer.style.justifyContent = 'space-between';
|
|
669
|
+
|
|
670
|
+
// Create OK button
|
|
671
|
+
this.dialogOkButton = document.createElement('button');
|
|
672
|
+
this.dialogOkButton.textContent = 'OK';
|
|
673
|
+
this.dialogOkButton.style.padding = '5px 15px';
|
|
674
|
+
this.dialogOkButton.style.backgroundColor = '#00aa00';
|
|
675
|
+
this.dialogOkButton.style.color = '#fff';
|
|
676
|
+
this.dialogOkButton.style.border = 'none';
|
|
677
|
+
this.dialogOkButton.style.borderRadius = '3px';
|
|
678
|
+
this.dialogOkButton.style.cursor = 'pointer';
|
|
679
|
+
|
|
680
|
+
// Create Cancel button
|
|
681
|
+
this.dialogCancelButton = document.createElement('button');
|
|
682
|
+
this.dialogCancelButton.textContent = 'Cancel';
|
|
683
|
+
this.dialogCancelButton.style.padding = '5px 15px';
|
|
684
|
+
this.dialogCancelButton.style.backgroundColor = '#aa0000';
|
|
685
|
+
this.dialogCancelButton.style.color = '#fff';
|
|
686
|
+
this.dialogCancelButton.style.border = 'none';
|
|
687
|
+
this.dialogCancelButton.style.borderRadius = '3px';
|
|
688
|
+
this.dialogCancelButton.style.cursor = 'pointer';
|
|
689
|
+
|
|
690
|
+
// Add buttons to container
|
|
691
|
+
buttonContainer.appendChild(this.dialogOkButton);
|
|
692
|
+
buttonContainer.appendChild(this.dialogCancelButton);
|
|
693
|
+
|
|
694
|
+
// Add elements to dialog
|
|
695
|
+
this.inputDialog.appendChild(this.dialogTitle);
|
|
696
|
+
this.inputDialog.appendChild(this.dialogInput);
|
|
697
|
+
this.inputDialog.appendChild(buttonContainer);
|
|
698
|
+
|
|
699
|
+
// Add dialog to document
|
|
700
|
+
document.body.appendChild(this.inputDialogOverlay);
|
|
701
|
+
document.body.appendChild(this.inputDialog);
|
|
702
|
+
|
|
703
|
+
// Add event listeners
|
|
704
|
+
const self = this;
|
|
705
|
+
|
|
706
|
+
// OK button confirms input
|
|
707
|
+
this.dialogOkButton.addEventListener('click', function() {
|
|
708
|
+
self.confirmInputDialog();
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
// Cancel button closes dialog without changes
|
|
712
|
+
this.dialogCancelButton.addEventListener('click', function() {
|
|
713
|
+
self.closeInputDialog();
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
// Enter key confirms input
|
|
717
|
+
this.dialogInput.addEventListener('keydown', function(e) {
|
|
718
|
+
if (e.key === 'Enter') {
|
|
719
|
+
self.confirmInputDialog();
|
|
720
|
+
e.preventDefault();
|
|
721
|
+
} else if (e.key === 'Escape') {
|
|
722
|
+
self.closeInputDialog();
|
|
723
|
+
e.preventDefault();
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
// Allow clicks on the overlay to close the dialog
|
|
728
|
+
this.inputDialogOverlay.addEventListener('click', function(e) {
|
|
729
|
+
self.closeInputDialog();
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
// But prevent clicks on the dialog from bubbling to the overlay
|
|
733
|
+
this.inputDialog.addEventListener('click', function(e) {
|
|
734
|
+
e.stopPropagation();
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// Confirm the input and update the slider value
|
|
739
|
+
confirmInputDialog() {
|
|
740
|
+
if (!this.currentSlider) return;
|
|
741
|
+
|
|
742
|
+
try {
|
|
743
|
+
const numValue = parseFloat(this.dialogInput.value);
|
|
744
|
+
if (!isNaN(numValue)) {
|
|
745
|
+
// Don't clamp values - allow any input value to be used
|
|
746
|
+
let finalValue = numValue;
|
|
747
|
+
|
|
748
|
+
// Flag if the value is outside the slider's normal range
|
|
749
|
+
if (this.currentSlider.min !== undefined && this.currentSlider.max !== undefined) {
|
|
750
|
+
if (numValue < this.currentSlider.min || numValue > this.currentSlider.max) {
|
|
751
|
+
// Mark the slider as having an out-of-range value
|
|
752
|
+
this.currentSlider.outOfRange = true;
|
|
753
|
+
} else {
|
|
754
|
+
// Reset the flag if value is back in range
|
|
755
|
+
this.currentSlider.outOfRange = false;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// Update slider value (no clamping)
|
|
760
|
+
this.currentSlider.value = finalValue;
|
|
761
|
+
if (this.currentSlider.updateProperty) {
|
|
762
|
+
this.currentSlider.updateProperty(finalValue);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
} catch (e) {
|
|
766
|
+
console.error("Error parsing number input:", e);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
this.closeInputDialog();
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// Close the input dialog without saving changes
|
|
773
|
+
closeInputDialog() {
|
|
774
|
+
if (this.inputDialog) {
|
|
775
|
+
this.inputDialog.style.display = 'none';
|
|
776
|
+
}
|
|
777
|
+
if (this.inputDialogOverlay) {
|
|
778
|
+
this.inputDialogOverlay.style.display = 'none';
|
|
779
|
+
}
|
|
780
|
+
this.currentSlider = null;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Handle tab or panel visibility changes
|
|
784
|
+
onHide() {
|
|
785
|
+
// Close input dialog if open
|
|
786
|
+
this.closeInputDialog();
|
|
787
|
+
|
|
788
|
+
// Clear edit buttons when panel is hidden
|
|
789
|
+
this.clearEditButtons();
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
onTabChange(tabId) {
|
|
793
|
+
// Close input dialog if open
|
|
794
|
+
this.closeInputDialog();
|
|
795
|
+
|
|
796
|
+
// Re-register edit buttons for the new tab
|
|
797
|
+
const sliders = this.getActiveSliders();
|
|
798
|
+
if (sliders && Object.keys(sliders).length > 0) {
|
|
799
|
+
this.registerEditButtons(sliders);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
// Register edit buttons for sliders
|
|
806
|
+
registerEditButtons(sliders) {
|
|
807
|
+
// First, clear any existing edit buttons
|
|
808
|
+
this.clearEditButtons();
|
|
809
|
+
|
|
810
|
+
Object.entries(sliders).forEach(([name, slider], index) => {
|
|
811
|
+
if (!slider.options) { // Only for numeric sliders
|
|
812
|
+
const sliderY = this.panelY + 100 + (index * 40);
|
|
813
|
+
const btnX = this.panelX + 400;
|
|
814
|
+
const btnY = sliderY - 2;
|
|
815
|
+
const btnWidth = 45; // Wider button
|
|
816
|
+
const btnHeight = 26; // Taller button
|
|
817
|
+
|
|
818
|
+
const hoverId = `${slider.id}_edit`;
|
|
819
|
+
|
|
820
|
+
// Register the edit button with input system
|
|
821
|
+
this.game.input.registerElement(
|
|
822
|
+
hoverId,
|
|
823
|
+
{
|
|
824
|
+
bounds: () => ({
|
|
825
|
+
x: btnX - 2, // Add a bit more hit area
|
|
826
|
+
y: btnY - 2, // Add a bit more hit area
|
|
827
|
+
width: btnWidth + 4, // Add a bit more hit area
|
|
828
|
+
height: btnHeight + 4 // Add a bit more hit area
|
|
829
|
+
})
|
|
830
|
+
},
|
|
831
|
+
"debug"
|
|
832
|
+
);
|
|
833
|
+
|
|
834
|
+
this.inputFields.set(hoverId, {
|
|
835
|
+
slider: slider,
|
|
836
|
+
name: name,
|
|
837
|
+
x: btnX,
|
|
838
|
+
y: btnY,
|
|
839
|
+
width: btnWidth,
|
|
840
|
+
height: btnHeight
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
// Clear all registered edit buttons
|
|
849
|
+
clearEditButtons() {
|
|
850
|
+
// Remove all buttons from the input system
|
|
851
|
+
this.inputFields.forEach((info, id) => {
|
|
852
|
+
this.game.input.removeElement(id, "debug");
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
// Clear the inputFields map
|
|
856
|
+
this.inputFields.clear();
|
|
857
|
+
}
|
|
858
|
+
}
|