{"id":240,"date":"2009-10-29T07:37:59","date_gmt":"2009-10-28T21:37:59","guid":{"rendered":"http:\/\/www.doolwind.com\/blog\/?p=240"},"modified":"2009-10-29T07:37:59","modified_gmt":"2009-10-28T21:37:59","slug":"why-you-should-use-csharp-for-your-scripting-language","status":"publish","type":"post","link":"https:\/\/www.doolwind.com\/blog\/why-you-should-use-csharp-for-your-scripting-language\/","title":{"rendered":"Why You Should Use C# For Your Scripting Language"},"content":{"rendered":"<p><a href=\"http:\/\/www.doolwind.com\/images\/blog\/csharp.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright\" title=\"C#\" src=\"http:\/\/www.doolwind.com\/images\/blog\/csharp.jpg\" alt=\"\" width=\"154\" height=\"96\" \/><\/a>I&#8217;ve\u00a0used a lot of scripting languages over the years when developing games.\u00a0 For my latest engine, I decided I\u2019d use C# as the scripting language.\u00a0 I\u2019ve been amazed by how well C# works as a scripting language so I thought I\u2019d share my experiences.\u00a0 The technique I\u2019m about to discuss gives game designers access to a fully-featured language and IDE with compile-time checking all while allowing run-time changes. \u00a0I use run-time compilation to achieve the\u00a0flexibility\u00a0of a scripting language combined with the power of a .NET language.<\/p>\n<p><strong>Advantages<\/strong><\/p>\n<p>There are a number of key advantages to using C# as a scripting language in your game engine.\u00a0 I\u2019ll list these first then describe how I achieve them.<\/p>\n<ul>\n<li><strong>Designers use Visual Studio.<\/strong> Most designers are stuck using notepad (or similar) when writing      their scripts.\u00a0 With my technique,      designers can use Visual Studio, gaining the full power of the IDE.\u00a0 Including:<strong> <\/strong>\n<ul>\n<li><strong>Intellisense<\/strong>. Letting them know what functions exist on all       of the objects you\u2019ve exposed, as well as documentation you\u2019ve provided       in code.<strong> <\/strong><\/li>\n<li><strong>Compilation<\/strong>.<strong> <\/strong>Designers can compile their scripts       while making changes to catch any compile-time problems.<strong> <\/strong><\/li>\n<li><strong>Full Debugging Support. <\/strong>Another       area lacking in most scripting languages is the debugging support.\u00a0 Designers have access to all of Visual       Studios debugging functionality to help them find and fix issues with       their code.<strong> <\/strong><\/li>\n<\/ul>\n<\/li>\n<li><strong>Run-Time Changes.<\/strong> Designers still have complete control to change their scripts at      run-time.\u00a0 Scripts can be reloaded      automatically when files are changed, or (more likely) a \u201creset\u201d button      can be exposed in the game engine that allows them to reset the level and reload      all scripts.<strong><\/strong><\/li>\n<li><strong>Compile scripts into the executable for release.<\/strong> You have the option to use the scripts      compiled into the executable if you prefer, protecting your files.<strong><\/strong><\/li>\n<li><strong>Complete Access to game objects, or whatever you want designers to      access.<\/strong> Designers are working      in the same language you are developing in.\u00a0 They have full access to the game      objects or to a subset you decide on.\u00a0      I use an interface and expose what I want them to use.<strong><\/strong><\/li>\n<li><strong>FAST Run-time performance. <\/strong> The C# code is compiled not interpreted      meaning the run-time performance is as good as the rest of the engine.\u00a0 The slight performance bottleneck of      reflecting the function can be removed by compiling scripts into      executable if required.<strong><\/strong><\/li>\n<li><strong>No Binding Required.<\/strong> Binding is automatic between the game engine and the script.\u00a0 You don\u2019t need to write any plumbing and      exposing a new function is as easy as adding it to the engine.<strong><\/strong><\/li>\n<\/ul>\n<p><strong>How It Works<\/strong><\/p>\n<p>The setup is surprisingly easy, designers follow these steps and their up and running:<\/p>\n<ol>\n<li>Add the script file to the      Visual Studio project (preferably in its own directory)<\/li>\n<li>Create an Init() function      in the script class which will automatically be called by the engine<\/li>\n<li>Create callbacks for events      and implement the game logic<\/li>\n<li>Run the game and make      changes to scripts in real-time as needed<\/li>\n<\/ol>\n<p>I use the run-time compilation functionality of the .NET framework to compile and run the code on- the-fly.\u00a0 This has a small performance hit during compilation however the run-time performance is excellent.<\/p>\n<p><strong>Some Examples<\/strong><\/p>\n<p>Below are a few examples I put together today to show the power of the system.<\/p>\n<p>The first script below creates an entity at the beginning of the game and then sets up a callback that will fire every 5 seconds.\u00a0 The TestScript object\u2019s lifetime is until the scripting system is reset allowing stateful object creation.<\/p>\n<pre class=\"csharpcode\"><span class=\"csharp05\">public<\/span><span class=\"csharp00\"> <\/span><span class=\"csharp05\">class<\/span><span class=\"csharp00\"> <\/span>TestScript<span class=\"csharp00\"> <\/span><span class=\"csharp10\">:<\/span><span class=\"csharp00\"> <\/span>BaseScript<span class=\"csharp00\">\n<\/span><span class=\"csharp10\">{<\/span><span class=\"csharp00\">\n    <\/span><span class=\"csharp05\">int<\/span><span class=\"csharp00\"> <\/span>team<span class=\"csharp00\"> <\/span><span class=\"csharp10\">=<\/span><span class=\"csharp00\"> <\/span><span class=\"csharp04\">1<\/span><span class=\"csharp10\">;<\/span><span class=\"csharp00\">\n    <\/span><span class=\"csharp05\">int<\/span><span class=\"csharp00\"> <\/span>xPos<span class=\"csharp00\"> <\/span><span class=\"csharp10\">=<\/span><span class=\"csharp00\"> <\/span><span class=\"csharp04\">15<\/span><span class=\"csharp10\">;<\/span><span class=\"csharp00\">\n    <\/span><span class=\"csharp05\">int<\/span><span class=\"csharp00\"> <\/span>yPos<span class=\"csharp00\"> <\/span><span class=\"csharp10\">=<\/span><span class=\"csharp00\"> <\/span><span class=\"csharp04\">2<\/span><span class=\"csharp10\">;<\/span><span class=\"csharp00\">\n\n    <\/span><span class=\"csharp05\">public<\/span><span class=\"csharp00\"> <\/span><span class=\"csharp05\">void<\/span><span class=\"csharp00\"> <\/span>Init<span class=\"csharp10\">()<\/span><span class=\"csharp00\">\n    <\/span><span class=\"csharp10\">{<\/span><span class=\"csharp00\">\n        <\/span>script<span class=\"csharp10\">.<\/span>CreateEntity<span class=\"csharp10\">(<\/span><span class=\"csharp06\">\"Healer\"<\/span><span class=\"csharp10\">,<\/span><span class=\"csharp00\"> <\/span>team<span class=\"csharp10\">,<\/span><span class=\"csharp00\"> <\/span>xPos<span class=\"csharp10\">,<\/span><span class=\"csharp00\"> <\/span>yPos<span class=\"csharp10\">);<\/span><span class=\"csharp00\">\n        <\/span>script<span class=\"csharp10\">.<\/span>CallEveryXSeconds<span class=\"csharp10\">(<\/span>MyCallback<span class=\"csharp10\">,<\/span><span class=\"csharp00\"> <\/span><span class=\"csharp04\">5<\/span><span class=\"csharp10\">);<\/span><span class=\"csharp00\">\n    <\/span><span class=\"csharp10\">}<\/span><span class=\"csharp00\">\n\n    <\/span><span class=\"csharp05\">public<\/span><span class=\"csharp00\"> <\/span><span class=\"csharp05\">void<\/span><span class=\"csharp00\"> <\/span>MyCallback<span class=\"csharp10\">()<\/span><span class=\"csharp00\">\n    <\/span><span class=\"csharp10\">{<\/span><span class=\"csharp00\">\n        <\/span>script<span class=\"csharp10\">.<\/span>CreateEntity<span class=\"csharp10\">(<\/span><span class=\"csharp06\">\"Tank\"<\/span><span class=\"csharp10\">,<\/span><span class=\"csharp00\"> <\/span>team<span class=\"csharp10\">,<\/span><span class=\"csharp00\"> <\/span>xPos<span class=\"csharp10\">,<\/span><span class=\"csharp00\"> <\/span>yPos<span class=\"csharp10\">++);<\/span><span class=\"csharp00\">\n    <\/span><span class=\"csharp10\">}<\/span><span class=\"csharp00\">\n<\/span><span class=\"csharp10\">}<\/span><span class=\"csharp00\">\n<\/span><\/pre>\n<p>The next script shows how simple customizing a game entity can be.\u00a0 Whenever an effect is added or removed from a game entity, the following two functions are called allowing designers complete control over gameplay.\u00a0 Notice the designer is given access only to what they need while still having complete control to change any settings or values of the entity.\u00a0 An interface could be used to restrict what operations can be performed on entities as required.<\/p>\n<pre class=\"csharpcode\"><span class=\"csharp05\">class<\/span><span class=\"csharp00\"> <\/span>SpeedUpEffect<span class=\"csharp00\">\n<\/span><span class=\"csharp10\">{<\/span><span class=\"csharp00\">\n    <\/span><span class=\"csharp05\">public<\/span><span class=\"csharp00\"> <\/span><span class=\"csharp05\">void<\/span><span class=\"csharp00\"> <\/span>AddEffect<span class=\"csharp10\">(<\/span>GameEntity<span class=\"csharp00\"> <\/span>entity<span class=\"csharp10\">)<\/span><span class=\"csharp00\">\n    <\/span><span class=\"csharp10\">{<\/span><span class=\"csharp00\">\n        <\/span>entity<span class=\"csharp10\">.<\/span>Speed<span class=\"csharp00\"> <\/span><span class=\"csharp10\">+=<\/span><span class=\"csharp00\"> <\/span><span class=\"csharp04\">1<\/span><span class=\"csharp10\">;<\/span><span class=\"csharp00\">\n    <\/span><span class=\"csharp10\">}<\/span><span class=\"csharp00\">\n\n    <\/span><span class=\"csharp05\">public<\/span><span class=\"csharp00\"> <\/span><span class=\"csharp05\">void<\/span><span class=\"csharp00\"> <\/span>RemoveEffect<span class=\"csharp10\">(<\/span>GameEntity<span class=\"csharp00\"> <\/span>entity<span class=\"csharp10\">)<\/span><span class=\"csharp00\">\n    <\/span><span class=\"csharp10\">{<\/span><span class=\"csharp00\">\n        <\/span>entity<span class=\"csharp10\">.<\/span>Speed<span class=\"csharp00\"> <\/span><span class=\"csharp10\">-=<\/span><span class=\"csharp00\"> <\/span><span class=\"csharp04\">1<\/span><span class=\"csharp10\">;<\/span><span class=\"csharp00\">\n    <\/span><span class=\"csharp10\">}<\/span><span class=\"csharp00\">\n<\/span><span class=\"csharp10\">}<\/span><span class=\"csharp00\">\n<\/span><\/pre>\n<p><strong>Conclusion<\/strong><\/p>\n<p>As I said, I was amazed both at how simple all of this was to set up (only a few hours) and how powerful the system is.\u00a0 If anyone is interested I\u2019d be happy to share the source code for how I achieved this.\u00a0 As I continue development of my engine I will be experimenting more with this scripting system and will release more information as I develop it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve\u00a0used a lot of scripting languages over the years when developing games.\u00a0 For my latest engine, I decided I\u2019d use C# as the scripting language.\u00a0 I\u2019ve been amazed by how well C# works as a scripting language so I thought I\u2019d share my experiences.\u00a0 The technique I\u2019m about to discuss gives game designers access to <a class=\"more-link\" href=\"https:\/\/www.doolwind.com\/blog\/why-you-should-use-csharp-for-your-scripting-language\/\">Read More<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"enabled":false},"version":2}},"categories":[33],"tags":[19,35,63,64],"class_list":["post-240","post","type-post","status-publish","format-standard","hentry","category-game-development","tag-c","tag-game-engine","tag-scripting","tag-scripting-language"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pgEc5-3S","_links":{"self":[{"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/posts\/240","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/comments?post=240"}],"version-history":[{"count":0,"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/posts\/240\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/media?parent=240"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/categories?post=240"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/tags?post=240"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}