找回密码
 立即注册
查看: 748|回复: 4

[笔记] 开源:可嵌入Unity游戏的BASIC语言

[复制链接]
发表于 2021-5-11 09:12 | 显示全部楼层 |阅读模式
春节期间,撸了不少Unity游戏源码。如果想在Unity游戏里内置一个编程环境——比如,玩家可以直接修改NPC的逻辑,或在游戏里通过脚本来修房子,或者小朋友可以在游戏里学编程——目前比较标准的选择包括:
    MoonSharp:这是Lua语言的C#实现,https://www.moonsharp.org/MiniScript:一个专门为Unity C#环境设计的简化版编程语言,MiniScript Home PageDynamic C#: 一个在C# runtime里跑C#的实现,Dynamic C# | Integration | Unity Asset Store等等……当然,类似的选择不是太多。主要是因为游戏内支持脚本编程的需求不算大,大多数编程语言在选择解释器或编译器的实现方式时,也较少考虑C#。
纯粹为了好玩,我春节时花了两三周时间,把微软的Small Basic编程语言(Small Basic)改写成了一个Unity内可用的版本,算是丰富一下游戏内脚本语言的选择吧。开源在这里:
改造后的语言起名叫Interactive Small Basic (ISB)。与原版的Small Basic相比,主要区别有
(1)可以方便地在命令行、脚本环境使用。比如可以当计算器使:
  1. ] 308 + 73.5 * 2
  2. 455.0
  3. ] 88 mod 7
  4. 4
复制代码
可以逐行执行:
  1. ] a = 10
  2. ] a
  3. 10
  4. ] for i = 1 to a
  5. >   print(math.sin(i))
  6. > endfor
  7. 0.841470984807896
  8. 0.909297426825682
  9. 0.141120008059867
  10. -0.756802495307928
  11. -0.958924274663138
  12. -0.279415498198926
  13. 0.656986598718789
  14. 0.989358246623382
  15. 0.412118485241757
  16. -0.54402111088937
复制代码
(2)删掉了原版Small Basic代码里所有冗长、复杂的“基于XML的数据驱动编程模式”,scanner,parser,runtime等模块里的大部分逻辑,都由代码本身自洽地解决,不需要外部XML来定义。
(3)通过C#的反射机制,很容易给ISB增加适应某个新环境的扩展库。比如想在Unity环境里,为ISB语言增加一个“创建小球”的扩展库,就很简单地实现一个C# class就好,没有任何复杂的注册或接口声明逻辑:
  1. public class Game
  2. {
  3.     [Doc("Example lib function to access Unity objects.")]
  4.     public void AddBall(NumberValue x, NumberValue y, NumberValue z)
  5.     {
  6.         GameObject prefab = Resources.Load<GameObject>("Prefabs/Sphere");
  7.         if (prefab != null)
  8.         {
  9.             Object.Instantiate(prefab,
  10.                 new Vector3((float)x.ToNumber(), (float)y.ToNumber(), (float)z.ToNumber()),
  11.                 Quaternion.identity);
  12.         }
  13.         else
  14.         {
  15.             Debug.Log("Failed to load prefab.");
  16.         }
  17.     }
  18. }
复制代码
上面的扩展库实现后,启动ISB runtime时给出类名,ISB代码里就可以简单调用:
  1. Game.AddBall(x, y, z)
复制代码
(4)scanner,parser到runtime之间,我引入了一个实验性质的IR(中间表示)层。ISB的runtime里实际执行的是这个中间层的指令。这个中间层的语法类似WebAssembly,纯粹是为了展示ISB未来有能力移植到各种不同的运行环境,或者类似的runtime未来有能力在Unity游戏里运行各种不同的编程语言。
实现这个中间层时,不但没做任何优化(所以,别跟我说编译原理教科书里教的东西都比我实现的多),还刻意留了许多冗余实现(比如编译后的中间代码里随处可见的nop)——主要是为了让这个实验层级更简单,不涉及任何复杂逻辑,能跑通就好。
可以通过命令行把BASIC语言代码编译成ISB中间代码,例如:
  1. dotnet run --project ISB.Shell -- -i ../examples/fibonacci.bas -c
复制代码
在Unity游戏里引入ISB的方法可以参加一个示例程序:
这个示例游戏使用Unity GUI组件输入代码,按按钮后就简单启动ISB引擎,解释并执行代码:
  1. public class Program : MonoBehaviour
  2. {
  3.     public Button uiButton;
  4.     public InputField uiInput;
  5.     public GameObject objBall;
  6.     void Start()
  7.     {
  8.         uiButton.onClick.AddListener(onButtonClick);
  9.     }
  10.     void Update()
  11.     {
  12.     }
  13.     void onButtonClick()
  14.     {
  15.         string code = uiInput.text;
  16.         Debug.Log(code);
  17.         Engine engine = new Engine("Unity", new Type[] { typeof(Game) });
  18.         if (engine.Compile(code, true) && engine.Run(true))
  19.         {
  20.             if (engine.StackCount > 0)
  21.             {
  22.                 string ret = engine.StackTop.ToDisplayString();
  23.                 Debug.Log(ret);
  24.             }
  25.         }
  26.         else
  27.         {
  28.             foreach (var content in engine.ErrorInfo.Contents)
  29.             {
  30.                 Debug.Log(content.ToDisplayString());
  31.             }
  32.         }
  33.     }
  34. }
复制代码
在这个示例游戏里,用Basic语言批量创建小球并看着小球弹跳的画面见下面的动图:
写在最后的善意提醒:不要拿这份代码当编译原理的学习参考。原因:这份代码里的很多逻辑继承自Microsoft Small Basic的源码——说实话,那份源码并不是一份高质量的编译器范本,顶多是几个熟练码农在20%时间做的非常工程化的实用项目。我新增的代码逻辑,又都是为了Unity的使用环境或实现方便做了很多trade-off的东西。
要学习编译原理,还是参考经典教材如龙书,经典课程如斯坦福CS143就好。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-5-11 09:13 | 显示全部楼层
这个必须赞!如果有时间,我都想在Unity里复刻一个80年代的Laser310了。不过似乎反射机制在ios是被禁止的,有没有试过水果机?
发表于 2021-5-11 09:17 | 显示全部楼层
Laser 310 的主意很棒呀~ 沿着这个主意往下想,用 C# 搞个 Z80 simulator不是啥难事,就差不多能完美复刻了~


Reflection 是另一件事。上面这坨代码,并没考虑 iOS,因为要在游戏里编程总要有方便一些的键盘输入,iOS 优先级比桌面稍低。


iOS 里不能用的 Reflection 似乎只是代码生成相关的部分,参见:
Limitations of Xamarin.iOS - Xamarin
我之前没详细测过。
发表于 2021-5-11 09:25 | 显示全部楼层
单纯反射是没有问题的
发表于 2021-5-11 09:30 | 显示全部楼层
暴露了年龄[害羞]
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-18 21:15 , Processed in 0.101268 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表