Blockly Blocks Manipulating Unity C# SCripts

487 views
Skip to first unread message

Laurie Gale

unread,
Feb 2, 2021, 4:29:23 AM2/2/21
to Blockly
Hi,

I'm currently creating a 3D racing game to improve the debugging ability of students aged 9-11 as part of a university project. To do this, I'm creating a game in Unity which can be manipulated by blockly code. But after lots of searching on how to do this, I'm still not sure on how to use the code generators in particular.

Most people code their games in js but this has deprecated on Unity and I don't have experience with it, so want to minimise use with it. I'd like to know how how code in the code generators for the blocks I've created can be linked to certain methods in my Unity scripts? Was using Lua for the basic logic blocks but not sure how to generate the code that's specific to the game mechanics.

e.g. for the block "turn x degrees," this needs to translate to code that sets the variable turnAngle to x.

Unfortunately I can't give loads of time to coding this so also need a quick solution.

Thanks in advance!

Beka Westberg

unread,
Feb 2, 2021, 6:35:30 PM2/2/21
to blo...@googlegroups.com
Hello :D

> Was using Lua for the basic logic blocks but not sure how to generate the code that's specific to the game mechanics.

So if I'm understanding correctly, you already have a lua-interpreter set up that allows the objects in your game to move? If so I think you've got the most challenging part down :D

Creating blocks that generate Lua should be pretty easy from here. First of all you'll want to check out the docs on generating code. Anywhere it references Blockly.JavaScript, just replace that with Blockly.Lua.

For example if you have a block that looks like this:
turn-degrees.png

With the block definition:
```
{
  "type": "turn_degrees",
  "message0": "turn %1 degrees",
  "args0": [
    {
      "type": "input_value",
      "name": "DEGREES"
    }
  ],
  "inputsInline": true,
  "colour": 230,
}
```

Your code generator might look like:
```
Blockly.Lua['turn_degrees'] = function(block) {
  var degrees = Blockly.Lua.valueToCode(block, 'DEGREES', Blockly.Lua.ORDER_ATOMIC);
  var code = 'turnAngle = ' + degrees + \n';
  return code;
};
```

> 3D racing game to improve the debugging ability of students aged 9-11 as part of a university project

That sounds super cool! If you ever have updates/publish be sure to post about it here! I'd love updates on this project :D

I hope that helps! If you have any further questions please reply!
--Beka

--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/blockly/ff96f8f6-f1a7-445f-b293-f142fd8d698bn%40googlegroups.com.

Uwe K

unread,
Feb 3, 2021, 2:55:02 AM2/3/21
to Blockly

Hi,

if you already have embedded a Lua interpreter in your game, you only need to make your C# code callable from Lua. Assuming you use the Moonsharp interpreter, you'd do it like this:

```CSharp
script = new Script();
script.Globals[ "turnDegrees" ] = (System.Action<int>)( degrees => yourCSharpCodeHere );
script.DoString( yourBlocklyCode );
```

Here is the relevant documentation: https://www.moonsharp.org/callback.html

An alternative would be to have Blockly generate Javascript and to run the program in the HTML page that contains your game. Your "turn" block could than generate Javascript code that sends a message to the Unity game.

Laurie Gale

unread,
Feb 3, 2021, 5:48:32 AM2/3/21
to Blockly
Hi Beka,

Thanks so much for the help you've already given. Unfortunately I haven't created the Lua interpreter and don't have any experience doing this. In my C# scripts for the game there are methods that I want the block-based methods to be able to manipulate but don't know how I'd do this through a Lua interpreter, is there any useful documentation in relation to Lua interpreters?

Thanks again!

Beka Westberg

unread,
Feb 3, 2021, 9:40:17 AM2/3/21
to blo...@googlegroups.com
Looks like Uwe/Seldom has got you covered! Moonsharp looks like a great option (w/ a killer name)

Best,
Beka

Laurie Gale

unread,
Feb 4, 2021, 12:23:59 PM2/4/21
to Blockly
In response to your comment Uwe K,

I'm now using MoonSharp within my project but I'm also getting slightly confused.

So does the Lua generated by the blocks directly reference the C# scripts in the Unity game, or is this done using MoonSharp?
To roll with the example above and assuming there is a unity function called turn(float degrees), would I set the code variable in the turn block code generator to call this C# turn method using the sort of code you've mentioned? Or would I just write some intermediary statement that MoonSharp would recognise and use to call the turn method?

Let me know if that doesn't make sense.

Thanks again!

Uwe K

unread,
Feb 4, 2021, 4:06:37 PM2/4/21
to Blockly
Lua code can't directly reference you C# scripts, you have to explicitly expose some C# methods or objects to the Lua interpreter. I think of Lua scripts as game mods and of the exposed C# methods as the game's modding API.

That script.Globals["turnDegrees"]... line in my post is where a C# method is exposed/registered to the Lua interpreter. If you run Lua code that contains a function call like "turnDegrees(5)", the interpreter (Moonsharp) will know to call your C# method. Your block generator would have to produce a line of Lua like "turnDegrees(5)".

If you want to see an example, here is a Unity game driven by Lua scripts: https://app.code-it-studio.de/makerspace/68
There is a code tab in the right column, where you can see Lua code that matches the blocks.

I hope this helps. I think what you are doing is pretty ambitious for a university project.

Laurie Gale

unread,
Feb 5, 2021, 10:16:27 AM2/5/21
to Blockly
Thanks so much for your help Uwe K and you're right, this is definitely more difficult than I was anticipating. Since I haven't really made any progress I'm going to have a go at generating JS to communicate with the game via WebGL instead. Hopefully that is more simple to get working.

Laurie Gale

unread,
Feb 18, 2021, 3:09:19 PM2/18/21
to Blockly
Hi,

I've progressed a bit since I wrote the last post and now have custom generators for each block that I've created which use the SendMessage() method to interact with C# scripts within my Unity game.

The problem now is that there is no code being generated, probably because there is something wrong with my generator. Within the code generator js file, I'm using the line:
      var unityInstance = UnityLoader.instantiate("unityContainer", "Build/DebuggingGame.json")
However, since this line is in my code generator, there is no visible unityContainer as this is contained within the index.html file. unityInstance needs to exist within the code generator so that the blocks can generate code like unityInstance.SendMessage('Racecar','turn',15).

The index.html includes a run button, which when clicked, runs the following code:
      var code = Blockly.Javascript.workspaceToCode(engineWorkspace);
      //alert("Running code");
      alert(code);
      try {
        eval(code);
      }
      catch (e) {
        alert(e); /
      }

Does the workspaceToCode method need to be called by a different filename? And how do I generate code that makes use of a correct unityInstance variable?

Hope this makes sense!

Beka Westberg

unread,
Feb 18, 2021, 5:41:37 PM2/18/21
to blo...@googlegroups.com
Hello!

You say:
> unityInstance needs to exist within the code generator so that the blocks can generate code like unityInstance.SendMessage('Racecar','turn',15).

But luckily, I don't think that's necessarily the case =) Block code generators are generating code /strings/ not actual code. This means that the variables included in the code strings only need to be available where the code is /interpreted/ not where it is /generated/.

So when you do this bit:
eval(code);
Your unityInstance needs to be within the scope of the eval() call. But when you do this bit:
Blockly.Javascript.workspaceToCode(engineWorkspace);
Your unityInstance does /not/ need to be within the scope of your individual block generators.

Or at least that's what it seems like from what you're describing hehe. Does that sound right?

Best wishes,
--Beka


Uwe K

unread,
Feb 19, 2021, 6:17:38 AM2/19/21
to Blockly
Yes, the game does not have to be loaded before code generation, only before evaluation. Your generator should not call SendMessage, but return a text that calls SendMessage when it's evaluated. Like this:

```JavaScript
Blockly.JavaScript["car_turn"] = function(block) {
    let angle = Blockly.JavaScript.valueToCode(block, 'ANGLE', Blockly.JavaScript.ORDER_ATOMIC) || '0';
    return `unityInstance.SendMessage( 'Racecar', 'turn', ${angle} )\n`;
};
```

Laurie Gale

unread,
Feb 19, 2021, 10:17:24 AM2/19/21
to Blockly
Thanks very much Uwe K and Beka both of your comments are really helpful! So if no code is being generated successfully, will that be down to an error in the code generator? For reference I get this error when pressing a button that calls the code I've displayed in my previous comment (caused by the workspaceToCode call):
 Uncaught TypeError: Cannot read property 'workspaceToCode' of undefined

Thanks again!

Laurie Gale

unread,
Feb 19, 2021, 10:37:55 AM2/19/21
to Blockly
Ignore me! Just a capitalisation error aha
Message has been deleted

Laurie Gale

unread,
Mar 15, 2021, 10:35:07 AM3/15/21
to Blockly
Ok so I have one more slight problem. In my block based language that communicates with Unity, I'd like to have if statements that are dependent on the state of objects within the Unity game. For example:

** BLOCKLY BLOCKS REPRESENTATION**
When space is pressed:
If car health < 25 then
    Speed up by 5KpH
else
     Speed up by 25KpH

So this is code that needs to be checked every frame so it would be well suited to the update method. Currently, I'm using a while true loop but this does not work properly. Either when I eval the code, the code never stops evaluating and hence I can't interact with the Unity game, or if I change it to something like "while (raceStarted)" the code completes the eval method but never runs the code as the while loop condition is only checked within eval.

So, is there any way of repeatedly executing code generated by the block generators so that it can repeatedly interact with Unity, or is eval the only place where code is executed?

Uwe K

unread,
Mar 15, 2021, 11:38:01 AM3/15/21
to Blockly
There are other ways to run your code besides eval: (1) the Function constructor, (2) creating a script element via code and (3) js-interpreter. I like option two.

None of them fix your infinite loop problem though. You'll have to wait a moment at the end of each loop iteration. Which I think requires setTimeout wrapped in a Promise. Which means your update function has be async. So it's not the slightest of problems.
Reply all
Reply to author
Forward
0 new messages