diff --git a/_layouts/default.html b/_layouts/default.html
index 1094359..3d9d6b9 100644
--- a/_layouts/default.html
+++ b/_layouts/default.html
@@ -569,10 +569,13 @@
Asset Manager
this.loadingUITextColor = loadingUITextColor || "white";
}
CustomLoadingScreen.prototype.displayLoadingUI = function () {
+ if (document.getElementById("customLoadingScreen")) {
+ return;
+ }
var loadingDiv = document.createElement("div");
loadingDiv.id = "customLoadingScreen";
const canvasContainer = document.querySelector('.canvas-container');
- if (canvasContainer) {
+ if (canvasContainer) {
loadingDiv.style.position = "absolute";
loadingDiv.style.top = "0";
loadingDiv.style.left = "0";
@@ -1356,6 +1359,14 @@ Asset Manager
kind: 'block',
type: 'apply_impulse',
},
+ {
+ kind: 'block',
+ type: 'set_linear_velocity',
+ },
+ {
+ kind: 'block',
+ type: 'set_angular_velocity',
+ },
{
kind: 'block',
type: 'set_physics_impostor',
@@ -1371,7 +1382,11 @@ Asset Manager
{
kind: 'block',
type: 'get_joystick_force',
- }
+ },
+ {
+ kind: 'block',
+ type: 'clear_collision_cache',
+ }
]
},
{
@@ -2909,6 +2924,10 @@ Asset Manager
}
}
+ clearCollisionCache() {
+ this.processedCollisions.clear();
+ }
+
onCollision(target1, target2, callback) {
const impostor1 = this._getPhysicsImpostor(target1);
@@ -3081,6 +3100,20 @@ Asset Manager
}
}
+ setLinearVelocity(target, x, y, z) {
+ const mesh = this._getMesh(target);
+ if (mesh && mesh.physicsImpostor) {
+ mesh.physicsImpostor.setLinearVelocity(new BABYLON.Vector3(x, y, z));
+ }
+ }
+
+ setAngularVelocity(target, x, y, z) {
+ const mesh = this._getMesh(target);
+ if (mesh && mesh.physicsImpostor) {
+ mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(x, y, z));
+ }
+ }
+
getPosX(target) {
const mesh = this._getMesh(target);
return mesh ? mesh.position.x : 0;
@@ -5313,6 +5346,36 @@ Asset Manager
colour: 120,
tooltip: 'To be used inside an onCollision callback'
},
+ {
+ type: 'set_linear_velocity',
+ message0: 'Set linear velocity of %1 to x: %2 y: %3 z: %4',
+ args0: [
+ { type: 'input_value', name: 'OBJECT' },
+ { type: 'input_value', name: 'X', check: 'Number' },
+ { type: 'input_value', name: 'Y', check: 'Number' },
+ { type: 'input_value', name: 'Z', check: 'Number' },
+ ],
+ "inputsInline": true,
+ previousStatement: null,
+ nextStatement: null,
+ colour: 120,
+ tooltip: 'Sets the linear velocity of the specified object',
+ },
+ {
+ type: 'set_angular_velocity',
+ message0: 'Set angular velocity of %1 to x: %2 y: %3 z: %4',
+ args0: [
+ { type: 'input_value', name: 'OBJECT' },
+ { type: 'input_value', name: 'X', check: 'Number' },
+ { type: 'input_value', name: 'Y', check: 'Number' },
+ { type: 'input_value', name: 'Z', check: 'Number' },
+ ],
+ "inputsInline": true,
+ previousStatement: null,
+ nextStatement: null,
+ colour: 120,
+ tooltip: 'Sets the angular velocity of the specified object',
+ },
{
type: 'set_gravity',
message0: 'Set scene gravity to x: %1 y: %2 z: %3',
@@ -5623,6 +5686,15 @@ Asset Manager
"hasCollidedObjectVar": true
}
},
+ {
+ "type": "clear_collision_cache",
+ "message0": "clear collision cache",
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "#5BA55B",
+ "tooltip": "Clears the history of processed collisions, allowing them to trigger again.",
+ "helpUrl": ""
+ },
{
"type": "destroy_object",
"message0": "destroy object %1",
@@ -6470,6 +6542,10 @@ Asset Manager
return `sceneManager.onCollision(${obj1}, ${obj2}, ${callback});\n`;
};
+ javascript.javascriptGenerator.forBlock['clear_collision_cache'] = function (block, generator) {
+ return 'sceneManager.clearCollisionCache();\n';
+ };
+
javascript.javascriptGenerator.forBlock['destroy_object'] = function (block, generator) {
const objectName = generator.valueToCode(block, 'OBJECT', generator.ORDER_ATOMIC) || 'null';
return `sceneManager.destroyObject(${objectName});\n`;
@@ -6845,6 +6921,22 @@ Asset Manager
return `sceneManager.applyImpulse(${target}, ${fx}, ${fy}, ${fz}, ${px}, ${py}, ${pz});\n`;
};
+ javascript.javascriptGenerator.forBlock['set_linear_velocity'] = function (block, generator) {
+ const target = generator.valueToCode(block, 'OBJECT', generator.ORDER_ATOMIC) || 'null';
+ const x = generator.valueToCode(block, 'X', generator.ORDER_ATOMIC) || 0;
+ const y = generator.valueToCode(block, 'Y', generator.ORDER_ATOMIC) || 0;
+ const z = generator.valueToCode(block, 'Z', generator.ORDER_ATOMIC) || 0;
+ return `sceneManager.setLinearVelocity(${target}, ${x}, ${y}, ${z});\n`;
+ };
+
+ javascript.javascriptGenerator.forBlock['set_angular_velocity'] = function (block, generator) {
+ const target = generator.valueToCode(block, 'OBJECT', generator.ORDER_ATOMIC) || 'null';
+ const x = generator.valueToCode(block, 'X', generator.ORDER_ATOMIC) || 0;
+ const y = generator.valueToCode(block, 'Y', generator.ORDER_ATOMIC) || 0;
+ const z = generator.valueToCode(block, 'Z', generator.ORDER_ATOMIC) || 0;
+ return `sceneManager.setAngularVelocity(${target}, ${x}, ${y}, ${z});\n`;
+ };
+
javascript.javascriptGenerator.forBlock['get_object_pos'] = function (block, generator) {
const axis = block.getFieldValue('AXIS');
const target = generator.valueToCode(block, 'OBJECT', generator.ORDER_ATOMIC) || 'null';
diff --git a/tests/loading_screen.spec.js b/tests/loading_screen.spec.js
new file mode 100644
index 0000000..7675825
--- /dev/null
+++ b/tests/loading_screen.spec.js
@@ -0,0 +1,34 @@
+const { test, expect } = require('@playwright/test');
+
+test.describe('Loading Screen Bug Fix', () => {
+ test.beforeEach(async ({ page }) => {
+ await page.goto('/');
+ // Handle the hero overlay
+ const startButton = page.locator('#start-button');
+ if (await startButton.isVisible()) {
+ await startButton.click();
+ }
+ });
+
+ test('Multiple calls to show loading screen should not stack elements', async ({ page }) => {
+ // Inject and execute code to show loading screen multiple times
+ const testCode = `
+ var loadingScreen = new CustomLoadingScreen('Testing...', 'black', 'white');
+ sceneManager.engine.loadingScreen = loadingScreen;
+ sceneManager.engine.displayLoadingUI();
+ sceneManager.engine.displayLoadingUI();
+ sceneManager.engine.displayLoadingUI();
+ `;
+
+ await page.evaluate((code) => {
+ window.doRun(code);
+ }, testCode);
+
+ // Check number of elements with id "customLoadingScreen"
+ const count = await page.evaluate(() => {
+ return document.querySelectorAll('#customLoadingScreen').length;
+ });
+
+ expect(count).toBe(1);
+ });
+});