informa
5 min read
article

Scripting with C++

This blog attempts to showcase the potential of C++ as a scripting language.

Disclaimer: This is purely Windows based and has some programming :(.. Sorry!

C++ Scripting

Scripting is almost a requirement for game engines these days. The idea behind scripting is to distance the game programmer from engine code. The benefits to providing scripting is the end user employs an “easier” language to code with and avoid complex systems that could potentially confuse or cause problems for the game programmer. 

There has been many avenues taken to provide scripting, Unity’s C# and Java based scripting, embedded LUA is a common scripting language, some programmers even create their own language to help interface with their engine. An overlooked scenario is C++ as a scripting language.

I know what you are thinking; C++ is too hard and requires proficiency in concepts such as object oriented programming, memory management, and polymorphism. C++ scripts will also require an absurd amount of code to get it working! The truth is you are right, but there is some tricks and tips that can be utilized to simplify the scripting experience and as it turns out, it does not require a large code base to implement.

Pros and cons of Embedded LUA

Pros

Cons

Light weight

Slow performance compared to compiled code

Fast code implementation

Exposing engine code to LUA

Easy language syntax and behavior

Backwards compatibility (is difficult)

No memory management

 

 

Pros and cons of C++ Scripting

Pros

Cons

Performance(After Dll is loaded)

Complicated language and syntax

Exposed completely to the engine

Exposed completely to the engine

 

Memory management

 

 

 

 

 

                Given the pros and cons list it is rather evident that LUA wins by a landslide, however there might be cases where C++ might be a better scripting stream -- cases where the end user has knowledge of C++ and needs the performance and power of the language. Another benefit for C++ scripting is that you eliminate having to expose engine code to the scripting language, which can potentially save oodles of time. Anyone familiar with embedding LUA knows the hassle of trying to interface C++ code with LUA.

 

 

Code

  

	class Script
	{
	public:
		Script() {};
		virtual void Update() = 0;
		virtual void Start() = 0;
		virtual void OnCollisionEnter() {};
		std::string ScriptPath;
	};

 

Here is a simple yet powerful base class that all scripts will inherit. Similar to Unity’s format the Update and Start functions must be implemented for every script.  I use the variable ScriptPath as a key to a hash map, which holds constructors for each script.  Essentially ScriptPath is how I establish what “type” the script is.

Script Implementation

#include "Script.h"
#include 

class TestScriptClass : public DI::Script
{
	public:
		TestScriptClass(){};
		~TestScriptClass(){};
		void Update()
		{
			printf("Update");
		};
		void Start()
		{
			printf("Start");
		};
};


	extern "C"
{
	__declspec(dllexport) DI::Script *CreateScript()
	{
		return new TestScriptClass();
	}
}

Here is a script that on Update prints a string “Update” to the console window and the function Start prints “Start”. Here is where the time saved is evident, instead of constantly exposing your engine code to whatever scripting language you are using, the user can just include whichever header is necessary from the engine and work from there. The script above is a standard print script; the key part to focus on is the CreateScript function at the bottom. The CreateScript function is in extern C to avoid name mangling on compilation to a DLL. Whenever CreateScript is invoked, it returns a pointer to a new TestScript on the heap; this is how the engine will create new scripts of this particular type.

 

Compilation

The next step in the process is compiling the TestScript into a DLL, if you are on windows I would recommend integrating the developer console into your program to automate script compilation, if your engine is cross platform I would look at C-make. For now, we will compile the scripts manually into DLLs. This step will require some effort to fully integrate a compiler into your engine and handle the script directories automatically.

 

Loading DLLs

This is where the magic happens, now that the script is compiled into a DLL we can dynamically link to it during runtime using Window’s functions GetProcAddress and LoadLibraryA.

#include "ScriptManager.h"
#include 
#include 
#include "Script.h"

void ScriptManager::LoadDll(std::string s)
{
	//typedef DI::Script* (__stdcall *scriptPtr)();

	std::string tempScriptPath = "./Dependencies/" + s;
	HINSTANCE hGetProcIDDLL = LoadLibraryA((tempScriptPath.c_str()));

	if (!hGetProcIDDLL) {
		std::cout << "could not load the dynamic library" << std::endl;
	}

	//# resolve function address here
	scriptPtr CreateScript = (scriptPtr)GetProcAddress(hGetProcIDDLL, "CreateScript");

	if (!CreateScript) {
		std::cout << "could not locate the function" << std::endl;
	}

	DI::Script *f_s = CreateScript();
	ScriptMap[tempScriptPath] = CreateScript;
}

LoadLibraryA is the function that loads the DLL into memory so we can use it for our program. Once the DLL is loaded in we need to access the CreateScript function, this can be done using GetProcAddress. In this function, we pass the Instance of our LoadLibraryA call and specify the name of the function we are trying to find. GetProcAddress returns a pointer to the function so we assign a function pointer that we can use later to create more scripts of that “type”.

Conclusion

Some recap, the benefits of C++ scripting is the performance of the language; the favorable time saved not exposing C++ to whichever scripting language is being used and the power of C++. I hope that this blog has provided some insight into the potential of C++ scripts. Feel free to leave a comment, question, critique, optimization, or a friendly hello :).

Latest Jobs

Treyarch

Playa Vista, California
6.20.22
Audio Engineer

Digital Extremes

London, Ontario, Canada
6.20.22
Communications Director

High Moon Studios

Carlsbad, California
6.20.22
Senior Producer

Build a Rocket Boy Games

Edinburgh, Scotland
6.20.22
Lead UI Programmer
More Jobs   

CONNECT WITH US

Register for a
Subscribe to
Follow us

Game Developer Account

Game Developer Newsletter

@gamedevdotcom

Register for a

Game Developer Account

Gain full access to resources (events, white paper, webinars, reports, etc)
Single sign-on to all Informa products

Register
Subscribe to

Game Developer Newsletter

Get daily Game Developer top stories every morning straight into your inbox

Subscribe
Follow us

@gamedevdotcom

Follow us @gamedevdotcom to stay up-to-date with the latest news & insider information about events & more