Now that you have followed Introduction to Creating Extensions in GMS2 you understand how to use the extension editor and make simple GML-based extensions.
In this guide we will now extend that knowledge to show how you can create a Visual Studio 2017 project and from that project make yourself a basic .dll ("dynamic linked library") that can be used with GMS2 to provide an alternative means of detecting a collision between two instances.
There is a pre-made project available for download at the bottom of this page, but we would strongly recommend you follow along with the guide and only use the supplied copy as a sanity-check if things aren't working correctly in your own attempt.
Important note: This guide assumes a little knowledge of programming in C/C++ and a basic familiarity with Visual Studio 2017. It is not a C/C++ tutorial, nor is it a guide to navigating Visual Studio's UI.
Note 2: Although other versions of Visual Studio can be used to do this just as well, 2017 is our recommendation as you can see from the Required SDKs FAQ that this is currently the most widely-supported version of VS by the targets in GMS2, and so is also hopefully the one you have installed already.
Why Create DLL Extensions?
When making Windows games you may sometimes need to create entirely new functionality that GML cannot provide - for which you will need to write C/C++ code outside GMS2 and create a more advanced form of extension.
(While GMS2 does already provide a good collection of collision methods, it is conceivable to have extra requirements for your game that are not available in GMS2 itself, so this is a nice little sample project we chose to make for this guide.)
Create Your Visual Studio Project
To begin, create an empty C++ project from the File > New dialog inside Visual Studio:
Ensure to select a suitable name and save location for the project, then proceed with saving the new project. You can see that we called our project "DLLExtension", so this is the value used in the rest of this guide - if you called yours something else, bear this in mind!
Once the project has been created it will be necessary to change the settings to make it so the output of this project whenever we build it will be a .dll file. This is done in the project's properties, which can be found in the right-click menu of the project within the Solution Explorer, as shown here:
You will then be presented with the application settings window. To change to a DLL output select the "Configuration Type" drop-down and select Dynamic Library (.dll):
After applying the change/pressing OK we will now add the source file that will contain our code.
You can do this from the Solution Explorer by right-clicking on the Source Files folder and selecting Add > New Item. From this dialog you can select "c++ file (.cpp)" and give it a name. We called ours "Collisions.cpp".
You will now have an empty code file ready for the next step of coding the actual functions we want to bring to GMS2.
Code Your DLL
Within your empty .cpp file it is now time to start adding the code that will be part of the DLL. But first, adding the following line should make things a little easier to read and write our code:
#define func extern "C" __declspec(dllexport)
This line looks pretty complicated, but here's a breakdown to show what is going on:
"#define func" will replace all instances of func in the code with the text that comes after.
'extern "C"' is a compiler flag that makes it use C-style compilation for the function. This is done because C++ may add extra information to function declarations, which we don't want.
"__declspec(dllexport)" will flag that this function is to be part of the DLL and allows it to be exposed so that GMS2 can use the function later on.
This one line is added first so that each time we declare a new function we just have to use the keyword "func" as shown in the snippet below (this is just an example, don't add this to your own code):
func double TestFunction() {
return 1;
}
Now that we have added that one line and explained what it's for, we can get to work properly...
The idea behind this library will be to provide collision detection functions, so let's start with a simple test for "Is a point inside a circle?". The code would be:
func double IsPointInCircle(double xx, double yy, double cx, double cy, double cr) {
//xx,yy is the point, cx,cy is center of circle, cr is circle radius
// x^2 + y^2 < r^2 - distance betwen point and center compared to radius
// if its less that radius the point is inside so returns 1, else it will return 0
return ((xx - cx)*(xx - cx) + ((yy - cy) * (yy - cy)) < cr*cr);
}
You can see the explanation of the maths in the comments in the above code, so we won't repeat that, but the important part for our DLL is the use of the defined "func" to declare the function and the type being a double. GMS2 will only accept types of double or string from extensions and as we are here intending on passing a number back from the extension we must say we will use a double.
Now you have some code, go ahead and build the Visual Studio project, if you are on version 2022.8.0.34 or later then you need to make sure you build 64bit(there will be a selector at the top, see the "What If I Want To Make A 64bit DLL?" section below) and when the build has finished, look at the output window (you may need to open this from the View dropdown). There will be a line that tells you where your new DLL file has been saved. Assuming you haven't changed anything about the project configuration it will likely be in a "Debug" folder, something like:
C:\[WhereverYouToldVS2017ToSaveTheProject]\DLLExtension\Debug\DLLExtension.dll <-32bit
C:\[WhereverYouToldVS2017ToSaveTheProject]\DLLExtension\x64\Debug\DLLExtension.dll <-64bit
Now move that file to a more easy-to-access location.
Create Your Extension Asset
Inside GMS2, create an Extension asset. (For a reminder of this process see the Introduction to Extensions guide again.)
In our example there are 5 arguments and they all need to be Double. Be aware that DLL extensions require that all arguments are the same value type and due to this requirement you will likely see a warning when you start changing these values, but this is expected.
Below is how you need to configure this extension in order to work with the example C++ code we wrote earlier in this guide:
Use Your New Extension In Your Game Code
We can now use this function to create a test to check if the mouse has "collided" with the instance.
Obviously, GMS2 has an existing "Mouse Enter" event which does much the same as this, but limits you to the collision data of the current object's sprite and it may be you wish to have collisions happen without a sprite or happen well outside the sprite's area, so hence our extension.
Inside the project, create an Object and a Sprite. The sprite needs to have some content of your choice and then be assigned to Object1.
Add Object1 to the instance layer within Room1 and then just close the room editor again.
Back in the workspace, give Object1 a new Step event. Now simply type the code required to setup your game values and call your extension function:
xx =mouse_x;
yy =mouse_y;
cx = x;
cy = y;
r = 100;
if(IsPointInCircle(xx,yy,cx,cy,r)){
instance_destroy();
}
Because our function returns 1 or 0 depending on if the given point (xx,yy) is within a circle centred at (cx,cy) and having radius (r), when the mouse moves within that radius a collision response can be activated. In this example we then destroy the object.
Once that code is typed out, run your game. Move your mouse towards your instance of Object1 and you will see when it gets close to the centre of its sprite (exactly how close depends on the size of Sprite you created) the instance will be destroyed.
It works! (No point in us adding a screenshot of an empty game window here, but you should of course prove it to yourself.)
You Made A DLL Extension
That's it for DLL extensions! You now know how to add further functions into your .cpp file, add them into the Extension Function editor, and call them in your code.
Remember that DLLs can only be used for Windows platforms. Other desktop platforms' native extension types, plus cross-platform GML extensions, are covered in other guides here on the Helpdesk, so you're welcome to follow those also.
What If I Want To Make A 64bit DLL?
Note that this section is only for GMS2 2.3.1 and above, as older versions only support 32bit Windows packages. However, we would encourage you to support 64bit extensions as much as you can, especially when making Marketplace assets, as 32bit support will eventually be phased-out.
The information above all remains the same, apart from that you need to have selected a 64bit output ("x64") type in this drop-down within Visual Studio:
Once it is built, you will need to rename your extension correctly so that GMS2 knows it's a 64bit package.
Acceptable naming conventions are:
Windows 32bit Runtime | <Name>.dll, lib<Name>.dll |
Windows 64bit Runtime | <Name>_x64.dll, lib<Name>_x64.dll |
So, for our example further up in this guide we would rename the file "DLLExtension_x64.dll".
This is then added to GMS2 as a second extension as we did above, or you can add it as a proxy file so you don't have to repeat the process of adding your functions. If you are on version 2022.8.0.34 or later 64bit must be used as the default dll.
Speaking of which...
Proxy Files: Same Code, Different Platform
If you have already completed (or plan to complete next) the guide for creating a macOS DyLib extension, you will realise that we used essentially the same code for both extensions but they are added to your GMS2 project as separate extensions and so you needed to repeat the Extension Editor steps twice. Obviously, if you have many functions in your extension this is undesirable, as it would take a substantial amount of time.
The solution here is to include the other file (seeing as we're in the DLL guide, that would be the DyLib) as a Proxy File within our existing extension.
It is important to be aware that proxy files follow a strict naming convention: they must share the same base filename and may require a suffix depending on the target, so you may need to rename your .dll/.dylib files before adding them.
To add a proxy file, simply click the + icon on the extension file properties:
Select the other library file and select OK.
Ensure that the Target option is set to the correct platform for the type of library package you just added and now it's ready for use.
If you had any issues with your own attempt when following the main part of this guide (before everything to do with 64bit support or Proxy Files), please see this working copy (versions of GM 2022.8.0.34 and later should only use 64bit) and compare it to what you did: