add LdtkFieldInstance and LdtkEntityMap classes; update LdtkSceneBuilder to support entity mapping
This commit is contained in:
11
addons/csharp_ldtk_importer/LdtkEntityMap.cs
Normal file
11
addons/csharp_ldtk_importer/LdtkEntityMap.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using Godot;
|
||||||
|
using Godot.Collections;
|
||||||
|
|
||||||
|
namespace CSharpLdtkImporter;
|
||||||
|
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class LdtkEntityMap : Resource
|
||||||
|
{
|
||||||
|
[Export] public Dictionary<string, PackedScene> EntitySceneMap { get; set; } = new();
|
||||||
|
}
|
1
addons/csharp_ldtk_importer/LdtkEntityMap.cs.uid
Normal file
1
addons/csharp_ldtk_importer/LdtkEntityMap.cs.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://c5wadsimbi1re
|
@@ -45,8 +45,10 @@ public partial class LdtkResourceImporter : EditorImportPlugin
|
|||||||
return Error.Failed;
|
return Error.Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var entityMap = options.TryGetValue("entity_map", out var map) ? map.As<LdtkEntityMap>() : null;
|
||||||
|
|
||||||
// 3. Use the Scene Builder to generate the Godot scene
|
// 3. Use the Scene Builder to generate the Godot scene
|
||||||
var builder = new LdtkSceneBuilder(ldtkData, sourceFile);
|
var builder = new LdtkSceneBuilder(ldtkData, sourceFile, entityMap);
|
||||||
var rootNode = builder.BuildLdtkProjectRoot();
|
var rootNode = builder.BuildLdtkProjectRoot();
|
||||||
|
|
||||||
var scene = new PackedScene();
|
var scene = new PackedScene();
|
||||||
@@ -78,6 +80,13 @@ public partial class LdtkResourceImporter : EditorImportPlugin
|
|||||||
{ "name", "import_tilemaps" },
|
{ "name", "import_tilemaps" },
|
||||||
{ "default_value", true },
|
{ "default_value", true },
|
||||||
{ "usage", (int)(PropertyUsageFlags.Default | PropertyUsageFlags.UpdateAllIfModified) }
|
{ "usage", (int)(PropertyUsageFlags.Default | PropertyUsageFlags.UpdateAllIfModified) }
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ "name", "entity_map" },
|
||||||
|
{ "default_value", new LdtkEntityMap() },
|
||||||
|
{ "property_hint", (int)PropertyHint.ResourceType },
|
||||||
|
{ "hint_string", "LdtkEntityMap" },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
using CSharpLdtkImporter.Models;
|
using CSharpLdtkImporter.Models;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
@@ -8,12 +10,14 @@ public class LdtkSceneBuilder
|
|||||||
{
|
{
|
||||||
private readonly LdtkData _ldtkData;
|
private readonly LdtkData _ldtkData;
|
||||||
private readonly string _basePath;
|
private readonly string _basePath;
|
||||||
|
private readonly LdtkEntityMap _entityMap;
|
||||||
private readonly Godot.Collections.Dictionary<int, TileSet> _tileSetCache = new();
|
private readonly Godot.Collections.Dictionary<int, TileSet> _tileSetCache = new();
|
||||||
|
|
||||||
public LdtkSceneBuilder(LdtkData ldtkData, string sourceFile)
|
public LdtkSceneBuilder(LdtkData ldtkData, string sourceFile, LdtkEntityMap entityMap)
|
||||||
{
|
{
|
||||||
_ldtkData = ldtkData;
|
_ldtkData = ldtkData;
|
||||||
_basePath = sourceFile.GetBaseDir();
|
_basePath = sourceFile.GetBaseDir();
|
||||||
|
_entityMap = entityMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node2D BuildLdtkProjectRoot()
|
public Node2D BuildLdtkProjectRoot()
|
||||||
@@ -94,18 +98,58 @@ public class LdtkSceneBuilder
|
|||||||
private Node2D BuildEntityLayer(LdtkLayerInstance layer)
|
private Node2D BuildEntityLayer(LdtkLayerInstance layer)
|
||||||
{
|
{
|
||||||
var entityLayerRoot = new Node2D { Name = layer.Identifier };
|
var entityLayerRoot = new Node2D { Name = layer.Identifier };
|
||||||
|
|
||||||
foreach (var entity in layer.EntityInstances)
|
foreach (var entity in layer.EntityInstances)
|
||||||
{
|
{
|
||||||
var marker = new Marker2D
|
Node2D instance = null;
|
||||||
|
|
||||||
|
GD.Print($"EntityMap keys: {string.Join(", ", _entityMap?.EntitySceneMap.Keys ?? Array.Empty<string>())}");
|
||||||
|
GD.Print($"Entity Identifier: {entity.Identifier}");
|
||||||
|
GD.Print($"Is Entity Mapped: {_entityMap?.EntitySceneMap.ContainsKey(entity.Identifier)}");
|
||||||
|
|
||||||
|
if (_entityMap?.EntitySceneMap.TryGetValue(entity.Identifier, out var packedScene) == true &&
|
||||||
|
packedScene != null)
|
||||||
{
|
{
|
||||||
Name = entity.Identifier,
|
GD.Print($"Instantiating entity '{entity.Identifier}' from mapped scene.");
|
||||||
Position = new Vector2(entity.Px[0], entity.Px[1])
|
instance = packedScene.Instantiate<Node2D>();
|
||||||
};
|
}
|
||||||
entityLayerRoot.AddChild(marker);
|
else
|
||||||
|
{
|
||||||
|
GD.Print($"Defaulting to Marker2D for unmapped entity '{entity.Identifier}'.");
|
||||||
|
instance = new Marker2D();
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.Name = entity.Identifier;
|
||||||
|
instance.Position = new Vector2(entity.Px[0], entity.Px[1]);
|
||||||
|
|
||||||
|
foreach (var field in entity.FieldInstances)
|
||||||
|
{
|
||||||
|
instance.SetMeta(field.Identifier, ConvertJsonElementToVariant(field.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
entityLayerRoot.AddChild(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entityLayerRoot;
|
return entityLayerRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Variant ConvertJsonElementToVariant(JsonElement element)
|
||||||
|
{
|
||||||
|
return element.ValueKind switch
|
||||||
|
{
|
||||||
|
JsonValueKind.String => element.GetString(),
|
||||||
|
JsonValueKind.Number => element.GetDouble(),
|
||||||
|
JsonValueKind.True => true,
|
||||||
|
JsonValueKind.False => false,
|
||||||
|
JsonValueKind.Null => default,
|
||||||
|
// For LDTK points (which are objects) or arrays, we can serialize them back to a JSON string.
|
||||||
|
// A more advanced implementation could convert these to Vector2 or Array types.
|
||||||
|
JsonValueKind.Object => Json.Stringify(Json.ParseString(element.GetRawText())),
|
||||||
|
JsonValueKind.Array => Json.Stringify(Json.ParseString(element.GetRawText())),
|
||||||
|
_ => default
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private TileSet GetOrCreateTileSet(int tilesetDefUid)
|
private TileSet GetOrCreateTileSet(int tilesetDefUid)
|
||||||
{
|
{
|
||||||
if (_tileSetCache.TryGetValue(tilesetDefUid, out var cachedTileSet)) return cachedTileSet;
|
if (_tileSetCache.TryGetValue(tilesetDefUid, out var cachedTileSet)) return cachedTileSet;
|
||||||
|
@@ -9,4 +9,7 @@ public class LdtkEntityInstance
|
|||||||
|
|
||||||
[JsonPropertyName("px")]
|
[JsonPropertyName("px")]
|
||||||
public int[] Px { get; set; }
|
public int[] Px { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("fieldInstances")]
|
||||||
|
public LdtkFieldInstance[] FieldInstances { get; set; }
|
||||||
}
|
}
|
16
addons/csharp_ldtk_importer/Models/LdtkFieldInstance.cs
Normal file
16
addons/csharp_ldtk_importer/Models/LdtkFieldInstance.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace CSharpLdtkImporter.Models;
|
||||||
|
|
||||||
|
public class LdtkFieldInstance
|
||||||
|
{
|
||||||
|
[JsonPropertyName("__identifier")]
|
||||||
|
public string Identifier { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("__type")]
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("__value")]
|
||||||
|
public JsonElement Value { get; set; }
|
||||||
|
}
|
@@ -0,0 +1 @@
|
|||||||
|
uid://dgwt3rdvkdypq
|
11
assets/MyEntityMap.tres
Normal file
11
assets/MyEntityMap.tres
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[gd_resource type="Resource" script_class="LdtkEntityMap" load_steps=3 format=3 uid="uid://cqu47e7mrbwfr"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://c5wadsimbi1re" path="res://addons/csharp_ldtk_importer/LdtkEntityMap.cs" id="1_0e1w3"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bmtfa3t0gbg3e" path="res://assets/square.tscn" id="1_1cxp4"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1_0e1w3")
|
||||||
|
EntitySceneMap = Dictionary[String, PackedScene]({
|
||||||
|
"Player": ExtResource("1_1cxp4")
|
||||||
|
})
|
||||||
|
metadata/_custom_type_script = "uid://c5wadsimbi1re"
|
8
assets/square.tscn
Normal file
8
assets/square.tscn
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://bmtfa3t0gbg3e"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://dmrfe4r8rw46w" path="res://icon.svg" id="1_a73l4"]
|
||||||
|
|
||||||
|
[node name="Square" type="Node2D"]
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
texture = ExtResource("1_a73l4")
|
167
assets/test.ldtk
167
assets/test.ldtk
@@ -11,7 +11,7 @@
|
|||||||
"iid": "2c2f2ff0-8560-11f0-9745-f307d35f41a0",
|
"iid": "2c2f2ff0-8560-11f0-9745-f307d35f41a0",
|
||||||
"jsonVersion": "1.5.3",
|
"jsonVersion": "1.5.3",
|
||||||
"appBuildId": 488493,
|
"appBuildId": 488493,
|
||||||
"nextUid": 25,
|
"nextUid": 27,
|
||||||
"identifierStyle": "Capitalize",
|
"identifierStyle": "Capitalize",
|
||||||
"toc": [],
|
"toc": [],
|
||||||
"worldLayout": "Free",
|
"worldLayout": "Free",
|
||||||
@@ -41,6 +41,41 @@
|
|||||||
"customCommands": [],
|
"customCommands": [],
|
||||||
"flags": [],
|
"flags": [],
|
||||||
"defs": { "layers": [
|
"defs": { "layers": [
|
||||||
|
{
|
||||||
|
"__type": "Entities",
|
||||||
|
"identifier": "Entities",
|
||||||
|
"type": "Entities",
|
||||||
|
"uid": 26,
|
||||||
|
"doc": null,
|
||||||
|
"uiColor": null,
|
||||||
|
"gridSize": 16,
|
||||||
|
"guideGridWid": 0,
|
||||||
|
"guideGridHei": 0,
|
||||||
|
"displayOpacity": 1,
|
||||||
|
"inactiveOpacity": 0.6,
|
||||||
|
"hideInList": false,
|
||||||
|
"hideFieldsWhenInactive": true,
|
||||||
|
"canSelectWhenInactive": true,
|
||||||
|
"renderInWorldView": true,
|
||||||
|
"pxOffsetX": 0,
|
||||||
|
"pxOffsetY": 0,
|
||||||
|
"parallaxFactorX": 0,
|
||||||
|
"parallaxFactorY": 0,
|
||||||
|
"parallaxScaling": true,
|
||||||
|
"requiredTags": [],
|
||||||
|
"excludedTags": [],
|
||||||
|
"autoTilesKilledByOtherLayerUid": null,
|
||||||
|
"uiFilterTags": [],
|
||||||
|
"useAsyncRender": false,
|
||||||
|
"intGridValues": [],
|
||||||
|
"intGridValuesGroups": [],
|
||||||
|
"autoRuleGroups": [],
|
||||||
|
"autoSourceLayerDefUid": null,
|
||||||
|
"tilesetDefUid": null,
|
||||||
|
"tilePivotX": 0,
|
||||||
|
"tilePivotY": 0,
|
||||||
|
"biomeFieldUid": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__type": "IntGrid",
|
"__type": "IntGrid",
|
||||||
"identifier": "IntGrid",
|
"identifier": "IntGrid",
|
||||||
@@ -669,7 +704,43 @@
|
|||||||
"tilePivotY": 0,
|
"tilePivotY": 0,
|
||||||
"biomeFieldUid": null
|
"biomeFieldUid": null
|
||||||
}
|
}
|
||||||
], "entities": [], "tilesets": [
|
], "entities": [
|
||||||
|
{
|
||||||
|
"identifier": "Player",
|
||||||
|
"uid": 25,
|
||||||
|
"tags": [],
|
||||||
|
"exportToToc": false,
|
||||||
|
"allowOutOfBounds": false,
|
||||||
|
"doc": null,
|
||||||
|
"width": 16,
|
||||||
|
"height": 16,
|
||||||
|
"resizableX": false,
|
||||||
|
"resizableY": false,
|
||||||
|
"minWidth": null,
|
||||||
|
"maxWidth": null,
|
||||||
|
"minHeight": null,
|
||||||
|
"maxHeight": null,
|
||||||
|
"keepAspectRatio": false,
|
||||||
|
"tileOpacity": 1,
|
||||||
|
"fillOpacity": 1,
|
||||||
|
"lineOpacity": 1,
|
||||||
|
"hollow": false,
|
||||||
|
"color": "#BE4A2F",
|
||||||
|
"renderMode": "Rectangle",
|
||||||
|
"showName": true,
|
||||||
|
"tilesetId": null,
|
||||||
|
"tileRenderMode": "FitInside",
|
||||||
|
"tileRect": null,
|
||||||
|
"uiTileRect": null,
|
||||||
|
"nineSliceBorders": [],
|
||||||
|
"maxCount": 0,
|
||||||
|
"limitScope": "PerLevel",
|
||||||
|
"limitBehavior": "MoveLastOne",
|
||||||
|
"pivotX": 0,
|
||||||
|
"pivotY": 0,
|
||||||
|
"fieldDefs": []
|
||||||
|
}
|
||||||
|
], "tilesets": [
|
||||||
{
|
{
|
||||||
"__cWid": 16,
|
"__cWid": 16,
|
||||||
"__cHei": 12,
|
"__cHei": 12,
|
||||||
@@ -715,6 +786,48 @@
|
|||||||
"externalRelPath": null,
|
"externalRelPath": null,
|
||||||
"fieldInstances": [],
|
"fieldInstances": [],
|
||||||
"layerInstances": [
|
"layerInstances": [
|
||||||
|
{
|
||||||
|
"__identifier": "Entities",
|
||||||
|
"__type": "Entities",
|
||||||
|
"__cWid": 16,
|
||||||
|
"__cHei": 16,
|
||||||
|
"__gridSize": 16,
|
||||||
|
"__opacity": 1,
|
||||||
|
"__pxTotalOffsetX": 0,
|
||||||
|
"__pxTotalOffsetY": 0,
|
||||||
|
"__tilesetDefUid": null,
|
||||||
|
"__tilesetRelPath": null,
|
||||||
|
"iid": "332d3780-8560-11f0-9745-0103de4db213",
|
||||||
|
"levelId": 0,
|
||||||
|
"layerDefUid": 26,
|
||||||
|
"pxOffsetX": 0,
|
||||||
|
"pxOffsetY": 0,
|
||||||
|
"visible": true,
|
||||||
|
"optionalRules": [],
|
||||||
|
"intGridCsv": [],
|
||||||
|
"autoLayerTiles": [],
|
||||||
|
"seed": 4277998,
|
||||||
|
"overrideTilesetUid": null,
|
||||||
|
"gridTiles": [],
|
||||||
|
"entityInstances": [
|
||||||
|
{
|
||||||
|
"__identifier": "Player",
|
||||||
|
"__grid": [7,8],
|
||||||
|
"__pivot": [0,0],
|
||||||
|
"__tags": [],
|
||||||
|
"__tile": null,
|
||||||
|
"__smartColor": "#BE4A2F",
|
||||||
|
"iid": "3a675850-8560-11f0-9745-41d5f1b372f4",
|
||||||
|
"width": 16,
|
||||||
|
"height": 16,
|
||||||
|
"defUid": 25,
|
||||||
|
"px": [112,128],
|
||||||
|
"fieldInstances": [],
|
||||||
|
"__worldX": 112,
|
||||||
|
"__worldY": 128
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__identifier": "IntGrid",
|
"__identifier": "IntGrid",
|
||||||
"__type": "IntGrid",
|
"__type": "IntGrid",
|
||||||
@@ -915,6 +1028,31 @@
|
|||||||
"externalRelPath": null,
|
"externalRelPath": null,
|
||||||
"fieldInstances": [],
|
"fieldInstances": [],
|
||||||
"layerInstances": [
|
"layerInstances": [
|
||||||
|
{
|
||||||
|
"__identifier": "Entities",
|
||||||
|
"__type": "Entities",
|
||||||
|
"__cWid": 16,
|
||||||
|
"__cHei": 16,
|
||||||
|
"__gridSize": 16,
|
||||||
|
"__opacity": 1,
|
||||||
|
"__pxTotalOffsetX": 0,
|
||||||
|
"__pxTotalOffsetY": 0,
|
||||||
|
"__tilesetDefUid": null,
|
||||||
|
"__tilesetRelPath": null,
|
||||||
|
"iid": "332d5e90-8560-11f0-9745-d935367db062",
|
||||||
|
"levelId": 23,
|
||||||
|
"layerDefUid": 26,
|
||||||
|
"pxOffsetX": 0,
|
||||||
|
"pxOffsetY": 0,
|
||||||
|
"visible": true,
|
||||||
|
"optionalRules": [],
|
||||||
|
"intGridCsv": [],
|
||||||
|
"autoLayerTiles": [],
|
||||||
|
"seed": 8641114,
|
||||||
|
"overrideTilesetUid": null,
|
||||||
|
"gridTiles": [],
|
||||||
|
"entityInstances": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__identifier": "IntGrid",
|
"__identifier": "IntGrid",
|
||||||
"__type": "IntGrid",
|
"__type": "IntGrid",
|
||||||
@@ -1100,6 +1238,31 @@
|
|||||||
"externalRelPath": null,
|
"externalRelPath": null,
|
||||||
"fieldInstances": [],
|
"fieldInstances": [],
|
||||||
"layerInstances": [
|
"layerInstances": [
|
||||||
|
{
|
||||||
|
"__identifier": "Entities",
|
||||||
|
"__type": "Entities",
|
||||||
|
"__cWid": 16,
|
||||||
|
"__cHei": 16,
|
||||||
|
"__gridSize": 16,
|
||||||
|
"__opacity": 1,
|
||||||
|
"__pxTotalOffsetX": 0,
|
||||||
|
"__pxTotalOffsetY": 0,
|
||||||
|
"__tilesetDefUid": null,
|
||||||
|
"__tilesetRelPath": null,
|
||||||
|
"iid": "332d5e91-8560-11f0-9745-af9a0227805e",
|
||||||
|
"levelId": 24,
|
||||||
|
"layerDefUid": 26,
|
||||||
|
"pxOffsetX": 0,
|
||||||
|
"pxOffsetY": 0,
|
||||||
|
"visible": true,
|
||||||
|
"optionalRules": [],
|
||||||
|
"intGridCsv": [],
|
||||||
|
"autoLayerTiles": [],
|
||||||
|
"seed": 4469038,
|
||||||
|
"overrideTilesetUid": null,
|
||||||
|
"gridTiles": [],
|
||||||
|
"entityInstances": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__identifier": "IntGrid",
|
"__identifier": "IntGrid",
|
||||||
"__type": "IntGrid",
|
"__type": "IntGrid",
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
importer="ldtk.importer"
|
importer="ldtk.importer"
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://c4xhtpmir26ah"
|
uid="uid://ckbephcqvg24h"
|
||||||
path="res://.godot/imported/test.ldtk-5da58debf60b2ac4adee332e85c3c4bc.tscn"
|
path="res://.godot/imported/test.ldtk-5da58debf60b2ac4adee332e85c3c4bc.tscn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
@@ -14,3 +14,4 @@ dest_files=["res://.godot/imported/test.ldtk-5da58debf60b2ac4adee332e85c3c4bc.ts
|
|||||||
|
|
||||||
import_entities=true
|
import_entities=true
|
||||||
import_tilemaps=true
|
import_tilemaps=true
|
||||||
|
entity_map=Resource("uid://cqu47e7mrbwfr", "res://assets/MyEntityMap.tres")
|
||||||
|
Reference in New Issue
Block a user