unity webgl and browser javascript communication - javascript

So i have this problem with communicating between browser and unity webgl,
basically what i want to do is generate objects in unity's scene with javascript code from the view the webgl is being played. In other words, view will have javascript code to create game objects after the scene loaded, not sure if this is possible yet.
i've read the unity documentation but i haven't found an example of how to implement the code shown there or if it's what i'm looking for.
https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html this is what i have been reading, specially the code visibility part, but since i've never worked with frontend that much i'm a bit clueless.

What you can do is to send messages to Unity inside your Javascript code but you'll let Unity do the dirty work about instantiating objects.
This is an example that I just made:
First you create a C# script that spawns your object/prefab, like this:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MyObjectSpawner : MonoBehaviour {
public Transform Prefab;
public void Spawn(string data) {
var instance = Instantiate(Prefab);
// do what you like with your instantiated object and the data from the javascript here
}
}
Now you create an object inside the scene and attach this script to it. Keep attention about the name you give to the Game Object you just created, this will be important in the next step. For now, let's say we named it "MyGameObject".
The last step is your javascript inside the game page container. For this example, I've created a button and when it's clicked, the spawnUnityObject() method is called. Like this:
HTML:
<button type="button" onclick="spawnUnityObject()">Press me</button>
Javascript:
function spawnUnityObject() {
// game object in the scene, method name, method parameter
SendMessage('MyGameObject', 'Spawn', 'Super string');
}
The result will be: when you click the "Press me" button inside the html, the game will spawn an object and you can use the "Super string" as a data inside the Spawn() method.
I hope this helps you. Let me know if you need more details.

Related

Blazor server side problem share javascript code

I'm developing my project with Blazor Server-side.
While I develop, I used javascript code to implement things that hard to implement by C#.
However, I'm facing something weird situation. (I guess it is problem for javascript)
Suppose there are 2 users(A, B). When 'A' user do some action that call javascript code, if 'B' user into same page, 'A' users action affects to 'B' user.
I implemented web page that have 3d scene with threejs. As I explained above, when User 'A' move some object with mouse event(mousemove, mousedown..), if User 'B' accesses the same page, 3d objects of B are moved to the location where User 'A' moved.
Originally, when user access to web page I developed, 3d objects's position should be 0,0,0.
My Guess
I don't use prototype or class(use variable and functions globally. I'm new to javascript.. )
Javascript runs on server-side(share resources??, If then, how can I solve it)
I'm guessing the javascript would be problem, but if you have any other opinions, would you please share?
Edited
I've solved this problem using DotNetObjectReference.Create(this);
C#
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
//send created instance to javascript
var dotNetObjRef = DotNetObjectReference.Create(this);
await JSRuntime.InvokeVoidAsync("SetObjectRef", dotNetObjRef);
}
await base.OnAfterRenderAsync(firstRender);
}
[JSInvokable]
public async Task enableSomething(bool bEnable)
{
var something = bEnable;
}
//== before edit
//[JSInvokable]
//public static async Task enableSomethingStatic(bool bEnable)
//{
// var something = bEnable;
//}
Javascript
var objectRef;
function SetObjectRef(ref) {
objectRef = ref;
}
//call c# function
objectRef.invokeMethodAsync("enableSomething", true);
It was problem of 'static' method as I guessed.
If you declare C# method called from javascript as 'static' and this method changes something of UI variable, this method can affect another users.
So I create instance of current page and send it javascript and when I need to call C# methods from javascript, I call methods using created instance.
Is there any problem or issue, please share it.
Sorry for my bad English.
JavaScript runs client side only. I don't see how two windows, let alone two users, would share data.
Almost for sure, the problem is that you are injecting a singleton service-- which means the server will use one instance for all users.
If so, you have two choices:
(1) add logic to your singleton service to incorporate users. (For example, a dictionary with UserID/Property name for key, and a column for Value)
(2) go to Startup.cs and change the suspect singleton service to .AddScoped(), which will create a new instance for each user.
For right now, I think the latter solution will solve your problem immediately. However, don't underestimate the value of Singletons-- they'll be very useful for other things.

What's is "this" refer to in Phaser 3?

I'm new to Javascript and want to make simple games with Phaser 3, and I found that Javascript seems to be a little different from other OOP languages like C++ or Java. I checked out the tutorial in the official website and some other tutorial page, most of the code is like:
var config = {
...
scene: {
preload: preload,
create: create,
update: update
}
}
var game = new Phaser.Game(config)
function preload(){
this.load.img(...)
}
My question is what is the ‍"this" in the preload() indicate to? Is it means the "game" we defined before?
And how to check the object's class in console? typeof() only tells "object".
this is an instance of Phaser.Scene and not Phaser.Game.
The other answers are incorrect. The code is running the browser.
To see the docs for a Scene you can look here
In the code you have this is a pointer to your game instance which is why you can call Phaser methods to load assets, adjust the camera, etc.
In your config you are setting which function is called during the preload step in the game. When Phaser runs it calls your function (which just happens to be named preload too) and sets the scope of this to the game instance.

Calling Java function from Rhino

Calling Javascript functions running inside Rhino from Java is easy enough - that after all is why Rhino was created. The thing I am having trouble establishing is this:
Context: I have a Phonegap CLI (v 6.3.3) Android project (API 19+) where I do a great deal of processing via loadable JavaScript running inside rhino
A Phonegap plugin - which I am creating at the same time as the actual Phonegap app - contains class called Storage which provides public, static, methods such as readFromFile(String fileName), writeToFile(String fileName,String data) etc.
What I want to be able to do is to call Storage.readFromFile etc from my loaded JavaScript code in Rhino.
Just how this should be done is not too clear to me. From the searches I have done thus far it involves using ScriptableObject.putProperty to pass the Java class in question, Storage in my case to JavaScript. However, how this should be done and then how it should be used at the JS end leaves me rather confused.
I would be most grateful to anyone here who might be able to point me in the right direction
Given that Rhino has less than 100 followers here it should perhaps come as little surprise that this question was not answered. In the mean time I have managed to find the solution myself and it turns out to be very simple. I share it below for the benefit of anyone else running into this thread.
My Storage class is very simple. It goes something like this
public class Storage
{
public static boolean haveFile(){}
public static boolean readFromFile(String fname){}
...
}
When I call Javascript from Java via Rhino I simply pass a new instance of the Storage class as the last of my function parameters
Context rhino = Context.enter();
Object[] functionParams = new Object[] {"Other parameters",new Storage()};
rhino.setOptimizationLevel(-1);
try
{
Scriptable scope = rhino.initStandardObjects();
String rhinoLog = "var log = Packages.io.vec.ScriptAPI.log;";
String code = /*Javascript code here* as shown separately below/;
rhino.evaluateString(scope, rhinoLog + code, "ScriptAPI", 1, null);
Function function = (Function) scope.get("jsFunction", scope);
Object jsResult = function.call(rhino,scope,scope,functionParams);
}
where the Javascript code is
function jsFunction(a,s)
{
//a - or a,b,c etc - here will be the "other" parameters
//s - will be the instance of the Java side Storage class passed above
//now you can do things like
s.writeToFile('fileName','fileData');
var fd = s.readFromFile('fileName');
s.dropFile('fileName');
...
}

Create a JSAPIPtr in javascript side of firebreath

I have a requirement as follows:
I wanted to initialize a user-defined class inheriting from FB::JSAPIAuto but I wanted to create it plugin independent..like
In JS, earlier i used to do this::
plugin().CreateJSAPIObject("someParameter");
//in order to initialize the c++ object with a value..It was successfully compiling..
What I want to do is to create a c++ object plugin independent
So in JS>>
UserDefinedJSAPIClassPtr obj=new UserDefinedJSAPIClass();
obj->SetMember1="This is Member 1";
//not necessarily using new keyword
plugin().DoSomethingWithObject(obj);
I came to know of boost::clipp library..and other numerous frameworks but am finding difficulty...as everything is strongly tied to the root JSAPI.
My doubt>>Is this possible?
My objective later on>>
P.S:: DoSomethingWithObject(FB::variant& object) will get the members of the JSAPI object (set in the JS side) and process them
EDIT after Taxilian's answer::
what in the case of this,
In JS side,
function AnotherJavascriptfunction(member1)
{
member1='2';
}
var UserClass=function(color,settings){}
var userObject=new UserClass('Red',AnotherJavascriptfunction);
plugin().DoTheChanges(userObject);
In FB side,
how do i access member1.?
which method should i Look for to get the member of settings
Regards,
Pratik
Definitely not possible to create a JSAPIPtr from javascript, but you can create a normal javascript object and pass it into a JSAPI method; it'll be a FB::JSObjectPtr type and you can then call methods/properties on it using Invoke, GetProperty, SetProperty, etc.

referencing the html object that made the ExternalInterface.call to the javascript function called

i apologize if my terminology is off, my actionscript skills are pretty weak sauce.
so, i have some actionscript that makes a
ExternalInterface.call('someFunction');
call.
is it possible to reference the html object that made the call to someFunction directly using the ExternalInterface.call call?
Assume that the object that makes the call also has some Callbacks (via ExternalInterface.addCallback) that are accessible via javascript.
Currently:
Actionscript source
ExternalInterface.call("someFunction");
ExternalInterface.addCallback("someCallback",someASfunction);
Javascript source
function someFunction(){
document.getElementById('idOfSWFObject').someCallback();
}
I'm thinking there must be a way of:
Actionscript source
ExternalInterface.call("someFunction",THE_OBJECT_MAKING_THE_CALL);
ExternalInterface.addCallback("someCallback",someASfunction);
Javascript source
function someFunction(o){
o.someCallback();
}
once again, sorry about the terminology. tried to lace it with as many keywords for future searches.
thanks!
I guess you are talking about ExternalInterface.objectID. This property returns an id associated with flash container in object or embed tag.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExternalInterface.html?filter_flex=4.1&filter_flashplayer=10.2&filter_air=2.en#objectID
I suggest that you should also pass the name of "someCallback" to you JS method. This way there will be no need to hardcode it in JS.
Here's an example
// Actionscript source
const jsMethodName:String = "someFunction";
const asCallbackName:String = "someCallback";
ExternalInterface.call(jsMethodName+"(document.getElementById("++")"++");");
ExternalInterface.addCallback(asCallbackName,someASfunction);
// Javascript source
function someFunction(flashId, callbackName)
{
var flashContainer = document.getElementById(flashId);
flashContainer["callbackName"]();
}
EDIT: If you really want to get a reference to flash DOM object in someFunction arguments, you may achieve it in a bit tricky way (I would rather not, but just for your interest).
// Actionscript source
const jsMethodName:String = "someFunction";
const asCallbackName:String = "someCallback";
ExternalInterface.addCallback(asCallbackName,someASfunction);
ExternalInterface.call(
"function(){"+
jsMethodName+"("+
"document.getElementById('"+ExternalInterface.objectID+"'),"+
"'"+asCallbackName+"'"+
");"+
"}"
);
// Javascript source
function someFunction(flashContainer, callbackName)
{
flashContainer[callbackName]();
}
This way you inject some JS code from flash into js. It works, but looks messy.

Categories