diff --git a/api/animate.js b/api/animate.js index 462c8045..bd770753 100644 --- a/api/animate.js +++ b/api/animate.js @@ -241,6 +241,35 @@ export const flockAnimate = { }); }); }, + async glideToObject( + meshName1, + meshName2, + { + duration = 1, + reverse = false, + loop = false, + easing = "Linear", + } = {}, + ) { + return new Promise(async (resolve) => { + await flock.whenModelReady(meshName1, async function (mesh1) { + if (mesh1) { + flock.whenModelReady(meshName2, async function (mesh2) { + if (mesh2) { + const x = mesh2.position.x; + const y = mesh2.position.y; + const z = mesh2.position.z; + glideTo(meshName1, {x, y, z, duration, reverse, loop, easing}); + } else { + resolve(); + } + }); + } else { + resolve(); // Resolve immediately if mesh1 is not available + } + }); + }); + }, resolvePropertyToAnimate(property, mesh) { if (!mesh) { console.warn("Mesh not found."); diff --git a/blocks/animate.js b/blocks/animate.js index d043aaab..7538d76b 100644 --- a/blocks/animate.js +++ b/blocks/animate.js @@ -166,6 +166,72 @@ export function defineAnimateBlocks() { }, }; + Blockly.Blocks["glide_to_object"] = { + init: function () { + this.jsonInit({ + type0: "glide_to_object", + message0: translate("glide_to_object"), + args0: [ + { + type: "field_variable", + name: "MODEL1", + variable: window.currentMesh, + }, + { + type: "field_variable", + name: "MODEL2", + variable: "mesh2", + }, + { + type: "input_value", + name: "DURATION", + check: "Number", + }, + { + type: "field_dropdown", + name: "MODE", + options: [ + getDropdownOption("AWAIT"), + getDropdownOption("START"), + ], + }, + { + type: "field_checkbox", + name: "REVERSE", + checked: false, + text: "reverse", + }, + { + type: "field_checkbox", + name: "LOOP", + checked: false, + text: "loop", + }, + { + type: "field_dropdown", + name: "EASING", + options: [ + getDropdownOption("Linear"), + getDropdownOption("SineEase"), + getDropdownOption("CubicEase"), + getDropdownOption("QuadraticEase"), + getDropdownOption("ExponentialEase"), + getDropdownOption("BounceEase"), + getDropdownOption("ElasticEase"), + getDropdownOption("BackEase"), + ], + }, + ], + previousStatement: null, + nextStatement: null, + colour: categoryColours["Animate"], + tooltip: getTooltip("glide_to_object"), + }); + this.setHelpUrl(getHelpUrlFor(this.type)); + this.setStyle("animate_blocks"); + }, + }; + Blockly.Blocks["rotate_anim"] = { init: function () { this.jsonInit({ diff --git a/flock.js b/flock.js index 48354e3a..6d7dffe2 100644 --- a/flock.js +++ b/flock.js @@ -912,6 +912,7 @@ export const flock = { applyForce: this.applyForce?.bind(this), moveByVector: this.moveByVector?.bind(this), glideTo: this.glideTo?.bind(this), + glideToObject: this.glideToObject?.bind(this), wait: this.wait?.bind(this), createAnimation: this.createAnimation?.bind(this), animateFrom: this.animateFrom?.bind(this), diff --git a/generators.js b/generators.js index 33a0e7da..052d052d 100644 --- a/generators.js +++ b/generators.js @@ -230,6 +230,29 @@ export function defineGenerators() { return `${asyncWrapper}glideTo(${meshName}, { x: ${x}, y: ${y}, z: ${z}, duration: ${duration}, reverse: ${reverse}, loop: ${loop}, easing: "${easing}" });\n`; }; + javascriptGenerator.forBlock["glide_to_object"] = function (block) { + const meshName1 = javascriptGenerator.nameDB_.getName( + block.getFieldValue("MODEL1"), + Blockly.Names.NameType.VARIABLE, + ); + + const meshName2 = javascriptGenerator.nameDB_.getName( + block.getFieldValue("MODEL2"), + Blockly.Names.NameType.VARIABLE, + ); + const x = meshMap[meshName2]?.position.x; + const y = meshMap[meshName2]?.position.y; + const z = meshMap[meshName2]?.position.z; + const duration = getFieldValue(block, "DURATION", "0"); + const mode = block.getFieldValue("MODE"); + const reverse = block.getFieldValue("REVERSE") === "TRUE"; + const loop = block.getFieldValue("LOOP") === "TRUE"; + const easing = block.getFieldValue("EASING"); + const asyncWrapper = mode === "AWAIT" ? "await " : ""; + + return `${asyncWrapper}glideToObject(${meshName1}, ${meshName2}, { duration: ${duration}, reverse: ${reverse}, loop: ${loop}, easing: "${easing}" });\n`; + }; + javascriptGenerator.forBlock["rotate_anim"] = function (block) { const meshName = javascriptGenerator.nameDB_.getName( block.getFieldValue("MESH_VAR"), diff --git a/locale/en.js b/locale/en.js index 8aaaee85..cba66c1a 100644 --- a/locale/en.js +++ b/locale/en.js @@ -144,6 +144,7 @@ export default { // Custom block translations - Animate blocks glide_to: "glide %1 to x %2 y %3 z %4 in %5 ms\n%6 return? %7 loop? %8 %9", glide_to_seconds: "glide %1 to x %2 y %3 z %4 in %5 seconds \n%6 return? %7 loop? %8 %9", + glide_to_object: "glide %1 to %2 in %3 seconds \n%4 return? %5 loop? %6 %7", rotate_anim: "rotate %1 to x %2 y %3 z %4 in %5 ms\n%6 reverse? %7 loop? %8 %9", rotate_anim_seconds: "rotate %1 to x %2 y %3 z %4 in %5 seconds\n%6 reverse? %7 loop? %8 %9", animate_property: "animate %1 %2 to %3 in %4 ms reverse? %5 loop? %6 %7", diff --git a/toolbox.js b/toolbox.js index 573abc97..9e9b01a2 100644 --- a/toolbox.js +++ b/toolbox.js @@ -1884,6 +1884,21 @@ const toolboxAnimate = { }, }, }, + { + kind: "block", + type: "glide_to_object", + keyword: "glide", + inputs: { + DURATION: { + shadow: { + type: "math_number", + fields: { + NUM: 1, + }, + }, + }, + }, + }, { kind: "block", type: "rotate_anim_seconds",