80

我有一个用 C# 编写的小游戏。它使用数据库作为后端。这是一个集换式卡牌游戏,我想将卡牌的功能实现为脚本。

我的意思是我本质上有一个接口 ,ICard它是一个卡片类实现的 ( public class Card056: ICard) 并且它包含一个由游戏调用的函数。

现在,为了使事物可维护/可修改,我希望将每张卡的类作为数据库中的源代码,并在首次使用时对其进行编译。因此,当我必须添加/更改卡片时,我只需将其添加到数据库并告诉我的应用程序刷新,而不需要任何程序集部署(特别是因为我们将讨论每张卡片 1 个程序集,这意味着数百个程序集) .

那可能吗?从源文件注册一个类,然后实例化它,等等。

ICard Cards[current] = new MyGame.CardLibrary.Card056();
Cards[current].OnEnterPlay(ref currentGameState);

该语言是 C#,但如果可以使用任何 .NET 语言编写脚本,则额外奖励。

4

9 回答 9

42

Oleg Shilo 的 C# Script 解决方案(在 The Code Project 中)确实是在您的应用程序中提供脚本功能的一个很好的介绍。

另一种方法是考虑专门为脚本构建的语言,例如IronRubyIronPythonLua

IronPython 和 IronRuby 现在都可以使用。

有关嵌入 IronPython 的指南,请阅读 如何通过 10 个简单步骤在现有应用程序中嵌入 IronPython 脚本支持

Lua 是游戏中常用的脚本语言。有一个用于 .NET 的 Lua 编译器,可从 CodePlex 获得——http: //www.codeplex.com/Nua

如果您想了解如何在 .NET 中构建编译器,那么该代码库非常适合阅读。

完全不同的角度是尝试PowerShell。有许多将 PowerShell 嵌入应用程序的示例——这里有一个关于该主题的完整项目: Powershell Tunnel

于 2008-08-02T01:49:46.220 回答
8

您也许可以为此使用 IronRuby。

否则,我建议您有一个放置预编译程序集的目录。然后,您可以在数据库中引用程序集和类,并使用反射在运行时加载正确的程序集。

如果你真的想在运行时编译你可以使用 CodeDOM,那么你可以使用反射来加载动态程序集。可能有帮助的 Microsoft 文档文章

于 2008-08-02T04:18:15.517 回答
7

如果您不想使用 DLR,您可以使用 Boo(它有一个解释器),或者您可以考虑CodePlex 上的 Script.NET (S#) 项目。使用 Boo 解决方案,您可以在编译脚本或使用解释器之间进行选择,Boo 是一种很好的脚本语言,具有灵活的语法和通过其开放编译器架构可扩展的语言。不过,Script.NET 看起来也不错,您可以轻松地扩展该语言及其开源项目,并使用非常友好的编译器生成器 ( Irony.net )。

于 2008-08-06T16:28:19.783 回答
6

您可以使用任何 DLR 语言,这些语言提供了一种非常轻松地托管您自己的脚本平台的方法。但是,您不必为此使用脚本语言。您可以使用 C# 并使用 C# 代码提供程序对其进行编译。只要你在它自己的AppDomain中加载它,你就可以随心所欲地加载和卸载它。

于 2008-08-02T06:16:23.967 回答
5

我建议使用LuaInterface,因为它已经完全实现了 Lua,但看起来 Nua 并不完整,并且可能没有实现一些非常有用的功能(协程等)。

如果你想使用一些外部预打包的 Lua 模块,我建议使用 1.5.x 中的一些东西,而不是 2.x 系列,它构建完全托管的代码并且不能公开必要的 C API。

于 2008-09-17T01:41:29.067 回答
5

我将 LuaInterface1.3 + Lua 5.0 用于 NET 1.1 应用程序。

Boo 的问题在于,每次您动态解析/编译/评估代码时,它都会创建一组 boo 类,因此您会遇到内存泄漏。

另一方面,Lua 不这样做,所以它非常稳定并且工作得很好(我可以将对象从 C# 传递到 Lua 并向后传递)。

到目前为止,我还没有把它放在 PROD 中,但看起来很有希望。

我确实在使用 LuaInterface + Lua 5.0 的 PROD 中遇到了内存泄漏问题,因此我使用了 Lua 5.2 并使用 DllImport 直接链接到 C#。内存泄漏在 LuaInterface 库中。

Lua 5.2:来自http://luabinaries.sourceforge.nethttp://sourceforge.net/projects/luabinaries/files/5.2/Windows%20Libraries/Dynamic/lua-5.2_Win32_dll7_lib.zip/download

一旦我这样做了,我所有的内存泄漏都消失了,应用程序非常稳定。

于 2012-07-17T17:08:51.790 回答
4

是的,我考虑过这一点,但我很快发现另一种领域特定语言 (DSL) 会有点过分。

从本质上讲,他们需要以可能无法预测的方式与我的游戏状态进行交互。例如,一张牌可以有一条规则“当这张牌进场时,你所有的不死随从对飞行敌人的攻击力+3,除非敌人受到祝福”。由于集换式卡牌游戏是基于回合的,GameState 管理器将触发 OnStageX 事件并让卡牌以卡牌需要的任何方式修改其他卡牌或 GameState。

如果我尝试创建一个 DSL,我必须实现一个相当大的功能集,并且可能会不断更新它,这会将维护工作转移到另一部分,而不会实际删除它。

这就是为什么我想继续使用“真正的”.NET 语言,以便基本上能够触发事件并让卡以任何方式(在代码访问安全性的限制内)操纵游戏状态。

于 2008-08-01T23:49:57.103 回答
4

我的部门销售的主要应用程序做了非常相似的事情来提供客户定制(这意味着我不能发布任何来源)。我们有一个加载动态 VB.NET 脚本的 C# 应用程序(尽管可以轻松支持任何 .NET 语言 - 选择 V​​B 是因为定制团队来自 ASP 背景)。

使用 .NET 的 CodeDom,我们使用 VB 从数据库编译脚本CodeDomProvider(令人讨厌的是,它默认为 .NET 2,如果您想支持 3.5 功能,您需要将带有“CompilerVersion”=“v3.5”的字典传递给它的构造函数)。使用CodeDomProvider.CompileAssemblyFromSource方法编译它(你可以通过设置强制它只在内存中编译。

这将导致内存中有数百个程序集,但是您可以将所有动态类的代码放在一个程序集中,并在发生任何更改时重新编译整个代码。这样做的好处是您可以在测试时添加一个标志以使用PDB在磁盘上编译,从而允许您通过动态代码进行调试。

于 2008-08-10T15:24:23.553 回答
3

.NET 的下一个版本(5.0?)有很多关于打开“编译器即服务”的讨论,这将使诸如直接脚本评估之类的事情成为可能。

于 2010-11-27T02:12:59.443 回答