`I have a Unity 3D Project where i can drive around with a forklift and i want to add features like picking stuff up, putting it down and colorize materials. But I have a problem with connecting the buttons (which I made in the index.html, which is generated when i run my project with webgl) with my unity code. The webgl page looks like this: my project
I already tried it with UnityLoader.instantiate but it does not work for me i get the following error: UnityLoader - error
Here is the script from my Index.html `
<script>
var container = document.querySelector("#unity-container");
var canvas = document.querySelector("#unity-canvas");
var loadingBar = document.querySelector("#unity-loading-bar");
var progressBarFull = document.querySelector("#unity-progress-bar-full");
var fullscreenButton = document.querySelector("#unity-fullscreen-button");
var warningBanner = document.querySelector("#unity-warning");
function unityShowBanner(msg, type) {
function updateBannerVisibility() {
warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
}
var div = document.createElement('div');
div.innerHTML = msg;
warningBanner.appendChild(div);
if (type == 'error') div.style = 'background: red; padding: 10px;';
else {
if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
setTimeout(function() {
warningBanner.removeChild(div);``
updateBannerVisibility();
}, 5000);
}
updateBannerVisibility();
}
var buildUrl = "Build";
var loaderUrl = buildUrl "/build.loader.js";
var config = {
dataUrl: buildUrl "/build.data",
frameworkUrl: buildUrl "/build.framework.js",
codeUrl: buildUrl "/build.wasm",
streamingAssetsUrl: "StreamingAssets",
companyName: "DefaultCompany",
productName: "warehouseOnline3D",
productVersion: "0.1",
showBanner: unityShowBanner,
};
if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
// Mobile device style: fill the whole browser client area with the game canvas:
var meta = document.createElement('meta');
meta.name = 'viewport';
meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';
document.getElementsByTagName('head')[0].appendChild(meta);
container.className = "unity-mobile";
// To lower canvas resolution on mobile devices to gain some
// performance, uncomment the following line:
// config.devicePixelRatio = 1;
canvas.style.width = window.innerWidth 'px';
canvas.style.height = window.innerHeight 'px';
unityShowBanner('WebGL builds are not supported on mobile devices.');
} else {
// Desktop style: Render the game canvas in a window that can be maximized to fullscreen:
canvas.style.width = "960px";
canvas.style.height = "600px";
}
loadingBar.style.display = "block";
var script = document.createElement("script");
script.src = loaderUrl;
script.onload = () => {
createUnityInstance(canvas, config, (progress) => {
progressBarFull.style.width = 100 * progress "%";
}).then((unityInstance) => {
loadingBar.style.display = "none";
fullscreenButton.onclick = () => {
unityInstance.SetFullscreen(1);
};
}).catch((message) => {
alert(message);
});
};
document.body.appendChild(script);
var gameInstance = UnityLoader.instantiate("gameContainer", "Build/webgl.json");
gameInstance.SendMessage("Sideloader", "test", "printed from webgl");
</script>
the function that should be called from the UnityLoader
CodePudding user response:
The way via the UnityLoader
afaik is from very early Unity WebGL versions.
You want to store the result of the createUnityInstance
within the then
block and then use it later like
<script>
let instance = null;
....
createUnityInstance(canvas, config, (progress) => {
progressBarFull.style.width = 100 * progress "%";
}).then((unityInstance) => {
instance = unityInstance;
...
then you can later on use it and do
instance.SendMessage("Sideloader", "test", "printed from webgl");
However you can not do this in the current spot in the script initilazation level. You will have to wait until that then
block was actually called and then do it for your button e.g.
<button onclick='ButtonClick()'>test</button>
...
function ButtonClick()
{
if(instance) instance.SendMessage("Sideloader", "test", "printed from webgl");
}
As a more complex alternative though you can implement a plugin and let the c# part inject a callback into it you can later call and once your project gets more complex you might want to go with that rather.
E.g. have a MyFancyPlugin.jslib
var myFancyPlugin = {
{
$CallbackPtr : {},
InitializeJavaScript : function(callbackPtr)
{
CallbackPtr = callbackPtr;
}
FancyCall : function(value)
{
const valueSize = lengthBytesUTF8(value) 1;
const valueBuffer = _malloc(dataUrlSize);
stringToUTF8(value, valueBuffer, valueSize);
Runtime.dynCall("vi", $CallbackPtr, [valueBuffer]);
free(valueBuffer);
}
};
autoAddDeps(myFancyPlugin, '$CallbackPtr');
mergInto(LibraryManager.library, myFancyPlugin);
and on your button do e.g.
<button onclick='FancyCall("TEST!")'>test</button>
and then in c#
have something like e.g.
public static class MyFancyPlugin
{
private delegate void Callback(string value);
[DllImport("__Internal")]
private static void InitializeJavaScript(Callback callback);
public static void Initialize()
{
InitializeJavaScript(OnCallbackReceived);
}
[MonoPInvokeCallback(typeof(Callback))]
private static void OnCallbackReceived(string value)
{
Debug.Log("Received from JavaScript: {value}");
}
}
where something has to call
MyFancyPlugin.Initialize();
of course