Skip to content

fuzzybinary/godot_dart

main
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
src
 
 
 
 
 
 
 
 

GodotDart

An attempt to be able to use Dart as a scripting language for Godot.

Because I like Dart.

And I want to use it in Godot.

Current State

Currently, Dart can be initialized as a language usable as a GDExtension, but not as a scripting language. This means you can create Dart classes and Nodes and add them to you scene tree, and they will execute both in editor and in game.

Here's a list of planned features and work still to be done ( βœ… - Seems to be working, 🟨 - Partially working, ❌ - Not working)

Feature Support Note
Dart as a Godot Extension Language 🟨
Ref counted object support βœ… Through Ref<T>
Dart Debugging Extension βœ… Attach to http://127.0.0.1:5858
Dart Available as a Scripting Language 🟨 Very early implementation
Hot Reload ❌
Simplified Binding using build_runner ❌
Dart native Variants ❌ Needed for performance reasons
Memory efficiency / Leak prevention ❌

Some notes about the current state:

  • The binding is likely leaking both Dart objects and native allocations. I intend on making a pass through to make sure all of that is cleaned up at some point and correctly utilize native finalizers.
  • Right now Godot will crash on exit because the binding isn't cleaning up after itself and it tried to free Dart objects after Dart has aready been shut down.

Using

I have only tested this on Windows. I know for certain it will only work on 'float_64' builds of Godot.

Things you will need

  • A clone of this repo.
  • Dart (2.19 Current Stable, not tested with 3.0)
  • Godot 4.0.2 or a custom build compatible with 4.0.2
  • A build of the Dart Shared Library. Windows x64 .dlls for Dart 2.19 are provided in src/dart_dll/bin/win64.
  • A way to build src/cpp. A Visual Studio solution is provided if you have Visual Studio. If not, use your favorite tool to build the provided files.

Current Setup

To use the extension, you need to:

  • Copy both your dart_dll dynamic library and the godot_dart dynamic library to your project directory.
  • Copy simple/example.gdextension to your project directory (note this is only configured for windows.64 builds and will need to be modified for any other OS).
  • Create a src directory in your project directory to hold your Dart code. This should be a proper Dart package, complete with a pubspec.yaml file. Add a main.dart to this directory.
  • Run the Binding Generator
# From tools/binding_generator
dart ./bin/binding_generator.dart
  • Add a reference to the godot_dart package that is defined in src/dart. You will need to use a path dependency for this for now.
  • Add a main function to your main.dart. This is where you will register your Godot classes

You should now be able to write Dart code for Godot!

Note there are two ways to use Dart with Godot: as an extension language and as a Script language. Both are only partially implemented

General Requirements

There are requirements for any Godot accessible Dart class. Here's the Simple example class in simple/src/simple.dart

class Simple extends Sprite2D {
  // It's best to statically create a TypeInfo for your class:
  static late TypeInfo sTypeInfo = TypeInfo(
    StringName.fromString('Simple'),
    parentClass: StringName.fromString('Sprite2D'),
  );
  // a vTable getter is required for classes that will be used from extensions.
  // If you are not adding any virtual functions, just return the base class's vTable.
  // If the class is only used from scripts, this is likely not necessary.
  static Map<String, Pointer<GodotVirtualFunction>> get vTable =>
      Sprite2D.vTable;

  // An override of [typeInfo] is required. This is how
  // the bindings understand the what types it's looking at.
  @override
  TypeInfo get typeInfo => sTypeInfo;

  double _timePassed = 0.0;

  // Constructor is required and MUST call [postInitialize] for all classes usable
  // from an extension.
  Simple() : super() {
    postInitialize();
  }
  // Classes that are Scripts must have a named constructor

  // All virtual functions from Godot should be available, and start
  // with a v instead of an underscore.
  @override
  void vProcess(double delta) {
    _timePassed += delta;

    final x = 10.0 + (10.0 * sin(_timePassed * 2.0));
    final y = 10.0 + (10.0 * cos(_timePassed * 2.0));
    final newPosition = Vector2.fromXY(x, y);
    print('vProcess - $x, $y, ${newPosition.x}, ${newPosition.y}');
    setPosition(newPosition);
  }

  // The simplest way to bind your class it to create a static function to
  // bind it to Godot. The name doesn't matter
  static void bind() {
    gde.dartBindings.bindClass(Simple, Simple.typeInfo);  
  }
}

Dart classes as Extensions

Dart classes used as an Extension will appear as creatable in the "Create New Node" interface, but aren't editable or attachable to existing nodes. At the moment, you will need to restart the editor for your new classes to appear.

These classes need to be registered to Godot in main.dart:

void main() {
  Simple.bind();
}

Dart classes as Scripts

Scripts require a little bit more setup, but can then be attached to exiting nodes, just like any other GDScript. You should be able to create a Dart script by using the "Attach Script" command in the editor. This will create the necessary boilerplate for a Dart Script.

The two new sections of note are:

  // The method table tells the scripting system which methods we implement and how to 
  // call them. If you override a method or implement a method that Godot needs to "see", you
  // need to add it here. 
  static final Map<String, MethodInfo> _methodTable = {
    '_ready': MethodInfo(
      methodName: '_ready',
      dartMethodName: 'vReady',
      arguments: [],
    ),
    '_process': MethodInfo(
      methodName: '_process',
      dartMethodName: 'vProcess',
      arguments: [],
    ),
  };

  // Other functions...

  // getMethodInfo is the method that will be called to get the method info. This default implementation is
  // fine.
  @override
  MethodInfo? getMethodInfo(String methodName) {
    return _methodTable[methodName];
  }

You also have to register the class to the implementing file in your main function like so:

void main() {
  // ... other bindings
  DartScriptLanguage.singleton.addScript('res://src/player.dart', Player);
}

Notes

I know this is a very complicated setup. I'll be looking to simplify it using code generation and build_runner in the future, once more features are working.

More Info

This utilizes my custom built Dart shared library for embedding Dart, the source for which is available here. I've included the win64 prebuilt binaries in this repo for simplicity.

About

Using Dart as a scripting language for Godot

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published