Unity Exporter mesh component scripts - how to call outside of Unity?

I know how to create scripts and have them run (such as spinning a cube). I’m wondering if there’s a way to access the classes outside of Unity. I plan on integrating this into another React project with an HTML UI.

I can see that there’s a global PROJECT object and I can call script functions from there, however I’m not sure how to refer to the correct instance.

@MackeyK24 do you have any thoughts on how to pull this off?

I know this works:

BABYLON.SceneManager.GetInstance(). getScene(). getNodeByName("Cube"). metadata. components.find(comp => comp.klass == "PROJECT.Rotator"). instance.stop()

That finds the gameobject called Cube, looks for script called PROJECT.Rotator then runs the function stop()

Just checking that this is the optimal way.

I really gotta get my new version out… Its so much simpler…

Within a script component class, to reference another component attached to the same transform, you would call GetComponent and to access an arbitrary class on any transform from anywhere else you would use SceneManager.FindScriptComponent

Note: I thinks its called FindSceneComponent in the legacy toolkit you are currently working with

But basically its like Unity: Unity - Scripting API: GameObject.GetComponent

In Unity, you would do something like this to get a reference to a component:

using UnityEngine;

public class GetComponentExample : MonoBehaviour
{
    void Start()
    {
        HingeJoint hinge = gameObject.GetComponent(typeof(HingeJoint)) as HingeJoint;

        if (hinge != null)
            hinge.useSpring = false;
    }
}

Same exact usage in Babylon:

module PROJECT {
    export class GetComponentExample extends BABYLON.ScriptComponent {
        public constructor(transform: BABYLON.TransformNode, scene: BABYLON.Scene, properties: any = {}) {
            super(transform, scene, properties);
        }

        protected start(): void {
            var hinge:PROJECT.HingeJoint = this.getComponent("PROJECT.HingeJoint");
            
            if (hinge != null)
                hinge.useSpring = false;            
        }
    }
}

Here is an example helper function from my speedway demo used to instantiate a prefab of a fully scripted and setup mustang vehicle object (Hierarchy of models with various scripts attached) that can be called from anywhere… Even the Playgraound

protected static CreateMustangVehicle(scene:BABYLON.Scene, container:BABYLON.AssetContainer, prefab:string, name:string, player:BABYLON.PlayerNumber, startPosition:BABYLON.AbstractMesh, heightOffset:number, enableInput:boolean, attachCamera:boolean, topSpeed:number, powerRatio:number, skillLevel:number, bodyColor:BABYLON.Color3, wheelColor:BABYLON.Color3 = null, wheelType:number = 0, decalIndex:number = 0):BABYLON.TransformNode {
    const mustangVehicle:BABYLON.TransformNode = BABYLON.SceneManager.InstantiatePrefab(container, prefab, name);
    if (mustangVehicle != null) {
        mustangVehicle.rotationQuaternion = startPosition.rotationQuaternion.clone();
        mustangVehicle.position = startPosition.position.clone();
        mustangVehicle.position.y += heightOffset;
        const autoBodyShop:PROJECT.AutoBodyGarage = BABYLON.SceneManager.FindScriptComponent(mustangVehicle, "PROJECT.AutoBodyGarage");
        const inputController:PROJECT.VehicleInputController = BABYLON.SceneManager.FindScriptComponent(mustangVehicle, "PROJECT.VehicleInputController");
        const cameraManager:PROJECT.VehicleCameraManager = BABYLON.SceneManager.FindScriptComponent(mustangVehicle, "PROJECT.VehicleCameraManager");
        const carController:PROJECT.StandardCarController = BABYLON.SceneManager.FindScriptComponent(mustangVehicle, "PROJECT.StandardCarController");
        if (autoBodyShop != null) autoBodyShop.setupVehicleMaterials(bodyColor, wheelColor, wheelType, decalIndex);
        if (carController != null) {        
            carController.lowSpeedAngle = (player === 0) ? 20 : 10;
            carController.highSpeedAngle = (player === 0) ? 10 : 1;
            carController.topEngineSpeed = topSpeed;
            carController.powerCoefficient = powerRatio;
        }
        if (inputController != null) {
            inputController.enableInput = false;
            inputController.playerNumber = player;
            inputController.driverSkillLevel = skillLevel;
        }
        if (cameraManager != null && attachCamera === true) {
            cameraManager.enableCamera = true;
            cameraManager.followBehind = true;
            cameraManager.attachPlayerCamera(player);
        }
    } else {
        BABYLON.Tools.Warn("===> Failed to instantiate mustang prefab: " + name);
    }
    return mustangVehicle;
}

The SceneManager Extension is Unity Style Micro Framework i created to provide Babylon Developers with same kind of Unity Workflow And Game Mechanics :slight_smile:

I am trying to get the new version out as best i can… But its just me… Lots of functionality to re-produce by myself

1 Like

Ok cool, trying to figure it out at the moment.

I tried BABYLON.SceneManager.GetInstance().findSceneComponents("PROJECT.Rotator", BABYLON.SceneManager.GetInstance().getScene())

but that’s returning null. Not sure if I did it correctly.

Can I see the whole script file ?

From script components, you can use this.manager for the instance of the scene manager extension. You can also use this.scene to get the current scene itself

And it looks like you using the plural FindSceneComponents

Use the singular FindSceneComponent

My script looks like this:
/* Babylon Mesh Component Template */

module PROJECT {

    export class Rotator extends BABYLON.MeshComponent {

        private rotateSpeed: number = 1.0;

        public constructor(owner: BABYLON.AbstractMesh, scene: BABYLON.Scene, tick: boolean = true, propertyBag: any = {}) {

            super(owner, scene, tick, propertyBag);

        }

        protected ready() :void {

            this.rotateSpeed = this.getProperty("rotateSpeed", 1.0);

        }

        protected stop(): void {

            this.rotateSpeed = 0;

        }

        protected update() :void {

            this.mesh.rotation.y += (this.rotateSpeed * this.manager.deltaTime);

        }

    }

}

Then in the web console I type a command like this:

web_console

(I’m testing in the web console 'cos eventually this will be incorporated into another React project and I need to trigger some of the 3D functions from within React)

It should be something like this then, from the console:

var rotator = BABYLON.SceneManager.GetInstance().findSceneComponent("PROJECT.Rotator", someMeshComponent);

This will look for the PROJECT.Rotator scene component klass attached to some mesh :slight_smile:

Then you can call:

rotator.stop()

Note: There should be a babylon.manager.d.ts file right along side the babylon.manager.js

This will tell you the function signatures for the helper functions…

Note: That legacy version was all a proof of concept for me. The Scene Manager Helper functions are not very well documented… Have to use the .d.ts files to get a idea of what you can do with it… Some of my early videos go into what you can do with script components and the scene manager.

When i get the new version out, I will better document the Scene Manager and its features as well as the new super fancy GLTF Exporter the toolkit has become :slight_smile:

1 Like

Thanks for the tips!
So if the mesh component is Cube how do I reference that?
Should I use:
var cube = BABYLON.SceneManager.GetInstance(). getScene(). getNodeByName("Cube")

then:
var rotator = BABYLON.SceneManager.GetInstance().findSceneComponent("PROJECT.Rotator", cube);

or all together I could do it like:
var instance = BABYLON.SceneManager.GetInstance();
var cube = instance.getScene(). getNodeByName(“Cube”);
var rotator = instance.findSceneComponent(“PROJECT.Rotator”, cube);

Yep… that should work

Beware … the scene manager get instance is only valid if you load a scene… I don’t think it’s available if you create a new scene from scratch…

FYI… this is not an issue with the new redesign

1 Like

While I’ve got you here, do you know what’s happening with GPU compression? I can call engine.setTextureFormatToUse() and it’ll even return the format for the OS I’m using, but when I check the inspector its not loading any of the compressed files. Its still loading JPG and PNG but ignoring the ones with -dxt.ktx in their filename.

I don’t use ktx version 1

I actually started to use ktx2 compression. The new toolkit will generate either PNG or KTX2 files. But the gltf parser currently does not fully support it yet…

I’m am waiting on @bghgary work for ktx2 support for gltf

Actually ktx version 1 does work. I was just calling engine.setTextureFormatToUse() after the scene had already loaded :laughing: