In this section we are gonna walk through the process of creating a very simple scene where we are gonna attach a NativeScript made with Go using autoclass registration and compiled as a C shared library.
In order to build the example described in this page you need the following packages to be present in your computer:
Windows users please refer to the Godot documentation to check which options do you have in order to compile godot and use the same compiler to compile NativeScript libraries
First we need to create a new Godot project, as it is shown in the screenshot below:
you can click the Create Directory
button and Godot will create the target directory for your new project automagically
Now create two directories in the root of the project called bin
and src
. When done create a new scene of type control. Set its anchor to full rect
.
Add a button child node and move it to the center of the 2D canvas, set its size to x:246, y:56
under Rect
property in the Inspector panel.
Add new child label to the control node give it the same size than the button in the previous step and move it below the button.
After completing these steps you shall have something like the screenshot below
Create a new Go file with your preferred text editor in the src
directory, we recommend Visual Studio Code with the Go and Godot Tools extensions installed but you can use whatever you feel comfortable with.
you can not edit Go files within the integrated GDScript Godot editor even if you can create the file from Godot UI itself, Godot has no clue what a .go
file is
Copy and paste the block of code below into simple.go
and save the file
package main
import (
"fmt"
"gitlab.com/pimpam-games-studio/gdnative-go/gdnative"
)
// Ignored is ignored by gdnativego compiler
type Ignored struct{} //nolint:deadcode,unused
// SimpleClass is a structure that we can register with Godot.
//godot::register as SIMPLE
type SimpleClass struct {
Hit gdnative.Signal
HP gdnative.Int `hint:"range" hint_string:"The player's Hit Points" usage:"Default"`
Mana, Blood gdnative.Int `hint:"range" hint_string:"The player points to cast spells"`
Position gdnative.Vector2 `hint:"none" hint_string:"The player position"`
// IgnoreMe property will be ignored
IgnoreMe gdnative.Float `-` //nolint
}
// New creates a new SimpleClass value and returns a pointer to it
//godot::constructor(SimpleClass)
func New() *SimpleClass {
sc := SimpleClass{
HP: 100,
// signals need to be defined as literals (sorry about that)
Hit: gdnative.Signal{
Name: "hit",
NumArgs: gdnative.Int(1),
NumDefaultArgs: gdnative.Int(1),
Args: []gdnative.SignalArgument{
{
Name: gdnative.String("power"),
Type: gdnative.Int(gdnative.VariantTypeInt),
Hint: gdnative.PropertyHintRange,
HintString: "Hit power value",
Usage: gdnative.PropertyUsageDefault,
DefaultValue: gdnative.NewVariantInt(gdnative.Int64T(0)),
},
},
DefaultArgs: []gdnative.Variant{
gdnative.NewVariantInt(gdnative.Int64T(0)),
},
},
}
return &sc
}
// GetData is automatically registered to SimpleClass on Godot
//godot::export as get_data
func (sc *SimpleClass) GetData() gdnative.Variant {
gdnative.Log.Println("SIMPLE.get_data() called!")
data := gdnative.NewStringWithWideString(fmt.Sprintf("Hello World from gdnative-go instance! HP value: %d", sc.HP))
return gdnative.NewVariantWithString(data)
}
// This never gets called, but it necessary to export as a shared library.
func main() {
}
the code is fully commented, take some time to walk through it
As you can see we didn’t needed that much code compared with the manual approach and we added properties and signals to expand our previous SimpleClass
Create a simple Makefile in the root of the project with the following contents (Linux version)
all: generate build
generate:
${GOPATH}/bin/gogdc generate --path="./src"
build:
go build -v -buildmode=c-shared -o ./bin/libsimple.so ./src/*.go
clean:
go clean
rm ./bin/libsimple.so
rm ./src/*_registrable.gen.go
.PHONY: all
on Mac OS X you should change the building line to:
go build -v buildmode=c-shared -o ./bin/libsimple.dylib ./src/*.go
on Windows you should change the building line to:
go build -v buildmode=c-shared -o ./bin/libsimple.dll ./src/*.go
if you use Windows check how to compile NativeScript libraries on your Windoes version in the official Godot documentation
As before we can compile the library using make
command in the root of the project, if everything goes as expected you will end with a shared library file inside the bin
directory. The process is pretty similar to the one in the previous section where we were creating all of our handlers manually and registering them into Godot’s NativeScript, the main difference is that gogdc
will generate all the needed files to autoregister our classes for us.
if you get an error saying cannot find package "github.com/vitaminwater/cgo.wchar"
that means that for some reason the needed cgo.wchar
package wasn’t auto installed in your system by go get, proceed to just get them in order to fix it with go get github.com/vitaminwater/cgo.wchar
and try make again
We need to create a new GDNativeLibrary script to load our newly compiled library into Godot, to do so you have several options
Click the icon in the properties Inspector on Godot interface and write GDNativeLibrary
in the search window, that will create a new GDNativeLibrary on memory and its properties editor will automatically open in the botton panel on Godot’s gui. Ignore the edition panel for now and click on the icon, select Save as...
in the contextual menu that appears, select the bin
directory if is not already selected and save the file as simple.gdnlib
.
Put your mouse over the bin
directory we created at the very beginning and click with the right (or secondary) button, on the contextual menu that appears select New Resource
, write GDNativeLibrary
in the search window (it should autocomplete for you), in the saving window that will appear, save the new resource file as simple.gdnlib
and press enter.
Click on the two arrow icon at the bottom right corner of the bottom panel, just right to the Godot’s version, you will be presented with the GDNativeLibrary edition GUI maximized, in case that you don’t have the GDNativeLibrary panel opened at the bottom, go to the simple.gdnlib
file in the resource explorer and double click on it.
you can expand any bottom panel to make it use all the window height using that double up arrow icon, to turn it back to its original shape you just have to click on it again and it will shrink to its original size in the bottom of the central panel
In the editor you will find configuration for many platforms, you should provide a binary shared library for each platform that you want to support in your games, for the sake of simplicity we just set Linux/X11
on this example.
Click on icon of the Dynamic Library
column on the 64 bits row (or in the 32 if your system is 32 bits) and select the libsimple.so
file in the file dialog. You will end with something like the screen below.
if you are working in other platform use the right architecture and bits size for your system
Make sure the Load Once
checkbox is check on the properties Inspector, click on the icon and select Save
in the contextual menu to save our changes.
Now that Godot knows how to load our code we have to tell it about our SIMPLE
class. In order to do it, we need to create a new NativeScript resource file. As before, we also have two options to create it.
Click the icon in the properties Inspector on Godot interface and write NativeScript
in the search window, that will create a new NativeScript on memory and we should be able to edit its properties in the property Inspector. Click on the Library
[empty] select menu and the in the icon, go to the bin
directory in the file dialog and select our simple.gdnlib
. Fill the ClassName
value with our class name SIMPLE
, click on the save icon and save the file in the bin
directory as simple.gdns
.
Put your mouse over the bin
directory we created at the very beginning and click with the right (or secondary) button, on the contextual menu that appears select New Resource
, write NativeScript
in the search window (it should autocomplete for you), in the saving window that will appear, save the new resource file as simple.gdns
and press enter. In the property Inspector. Click on the Library
[empty] select menu and the in the icon, go to the bin
directory in the file dialog and select our simple.gdnlib
. Fill the ClassName
value with our class name SIMPLE
and click on the save icon to save our resource.
Now that we are in position to load and refer to our SIMPLE class we can open our main scene and attach a new script to it, on language select GDScript
, leave the inheritance as it is, choose empty template and save it as main.gd
in the root of the project. Copy and paste the following GDScript code into it and save it.
extends Control
# load the SIMPLE library
const SIMPLE = preload("res://bin/simple.gdns")
var data = SIMPLE.new()
func _on_Button_pressed():
# data comes directly from the Go context
$Label.text = "Data = " + data.get_data()
# update HP by adding one
data.HP += 1
# print current Blood and add one to it
print("data.Blood is ", data.Blood)
data.Blood += 1
The final step is to run the project, click on the play icon at the top right of the screen or simply press the F5
key, a dialog indicating that we don’t have set up a main scene yet will popup, click on Select
and select the main.tscn
You will get something similar to the screenshot above when you click the button
Congratulations! you created you first functional autoregistered classes GDNative-Go Godot application.