vmenge.Godot.Garnet
0.0.5
dotnet add package vmenge.Godot.Garnet --version 0.0.5
NuGet\Install-Package vmenge.Godot.Garnet -Version 0.0.5
<PackageReference Include="vmenge.Godot.Garnet" Version="0.0.5" />
<PackageVersion Include="vmenge.Godot.Garnet" Version="0.0.5" />
<PackageReference Include="vmenge.Godot.Garnet" />
paket add vmenge.Godot.Garnet --version 0.0.5
#r "nuget: vmenge.Godot.Garnet, 0.0.5"
#:package vmenge.Godot.Garnet@0.0.5
#addin nuget:?package=vmenge.Godot.Garnet&version=0.0.5
#tool nuget:?package=vmenge.Godot.Garnet&version=0.0.5
Godot.Garnet
Very exprimental library meant to help write Godot games with almost all code driven completely from the F# side outside of a single glue C# script.
Main feature right now is importing scenes into a Container
from the Garnet ECS with minimal boilerplate and zero per‑frame allocations,
but as I work more with Godot and F# I will most likely add any generic relevant helpers here if deemed necessary.
Installation
dotnet add package vmenge.Godot.Garnet
How It Works
Godot's groups are used to tag nodes that should be converted into entities or Marker
or Link
components.
When you bring Godot.Garnet
into scope, an ImportScene
extension method is added to Garnet.Composition.Container
.
Container.ImportScene(this, sceneRoot)
walks the subtree rooted at sceneRoot and:
- Creates an ECS entity for every node in the
entity
group. - Adds all children Nodes directly as components to that entity.
Additionally, there are two Attributes added to make one's life easier:
[<Marker("markergroupname")>]
will create components for an entity if the Node in the"entity"
group or any of its children belongs tomarkergroupname
.// Marker attribute structs should **always** be empty. [<Marker("spawnPoint")>] type SpawnPoint = struct end
[<Link("linkgroupname")>]
will add the component tagged with theLink
attribute to its parent entity instead of the raw node.// Link attribute structs should **always** have a single // field for the `Node` it is linking to. [<Struct;Link("player")>] type Player = { Node: CharacterBody2D }
Both Link
and Marker
groups can be assigned both to the parent "entity"
node, or any of its children.
So the following Godot node structure
World (Node2D)
├─ Player (CharacterBody2D) [groups: entity, player]
│ └─ CollisionShape2D [no groups]
└─ SpawnPoint (Marker2D) [groups: entity, spawnPoint]
Using the Marker
and Link
attributes like so
[<Marker("spawnPoint")>]
type SpawnPoint = struct end
[<Struct;Link("player")>]
type Player = {
Node: CharacterBody2D
}
Upon importing the World
node with Container.ImportScene
, would result in the following entities with components:
ECS World
├─ Entity #1
│ ├─ Player ← link component (holds CharacterBody2D node)
│ └─ CollisionShape2D ← node component
└─ Entity #2
├─ SpawnPoint ← marker component
└─ Marker2D ← node component
One big difference between Marker
and Link
, is that Marker
components are added alongside the normal component import chain. Link
components
will always be added instead of the component it is linked to.
With the above structure, one could query the components through Garnet
let mySystem (c: Container) =
c.On<Ready>
<| fun e ->
for r in c.Query<SpawnPoint, Marker2D>() do
let marker = r.Value2
// do something
for r in c.Query<Player, CollisionShape2D>() do
let characterBody2d, collisionShape2d = r.Value1.Node, r.Value2
// do something
Quickstart example
Full project examples will be in the /examples
folder on the repo soon, but one should be able to get started with something as simple as the following:
On the F# project:
// Main.fs
module Main
open Godot
open Godot.Garnet
[<Struct>]
type Ready = { Root: Node }
[<Struct>]
type Process = { Root: Node; Dt: float }
type FWorld =
{ Container: Container
Disposable: IDisposable }
static member Make node =
let c = Container()
c.ImportScene node
{
Container = c
Disposable =
Disposable.Create [
c.On<Ready>
<| fun e -> GD.Print "root scene is ready!"
c.On<Process>
<| fun e ->
GD.Print $"hello from process! deltatime: {e.Dt}"
]
}
On the Godot C# project, a single World.cs
or equivalent is all that is needed, attached to the root node of a scene:
using Godot;
using static Main;
public partial class World : Node2D
{
FWorld world = null!;
public override void _Ready()
{
world = FWorld.Make(this);
world.Container.Run(new Ready(this));
}
public override void _Process(double delta)
{
world.Container.Run(new Process(this, delta));
}
}
From there, using the Marker
and Link
attributes to define structs that correspond to Nodes that belong to or are children of a "entity"
group Node and their
equivalent groups should be more than enough to run Garnet
queries as per its documentation.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- FSharp.Core (>= 8.0.102)
- Garnet (>= 0.5.3)
- Godot.SourceGenerators (>= 4.4.1)
- GodotSharp (>= 4.4.1)
- GodotSharpEditor (>= 4.4.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.