197 lines
8.0 KiB
Python
197 lines
8.0 KiB
Python
import json
|
|
import os
|
|
|
|
PROJECT_ROOT = "/Users/davidkotnik/repos/novafarma"
|
|
LDTK_FILE = os.path.join(PROJECT_ROOT, "AutoLayers_2_stamps.ldtk")
|
|
|
|
def main():
|
|
# Load existing (or recreate structure if needed, but let's assume structure from previous step which was correct)
|
|
# Actually, we want to SWITCH to using the ATLAS.
|
|
|
|
# 1. DEFINE ATLAS TILESET
|
|
# Path: godot/phases/FAZA_1_FARMA/tilesets/TerrainAtlas.png
|
|
atlas_def = {
|
|
"__cWid": 16, # 512 / 32
|
|
"__cHei": 16, # 512 / 32
|
|
"identifier": "Terrain_Atlas",
|
|
"uid": 150,
|
|
"relPath": "godot/phases/FAZA_1_FARMA/tilesets/TerrainAtlas.png",
|
|
"embedAtlas": None,
|
|
"pxWid": 512,
|
|
"pxHei": 512,
|
|
"tileGridSize": 32,
|
|
"spacing": 0,
|
|
"padding": 0,
|
|
"tags": [],
|
|
"tagsSourceEnumUid": None,
|
|
"enumTags": [],
|
|
"customData": [],
|
|
"savedSelections": [],
|
|
"cachedPixelData": None
|
|
}
|
|
|
|
# 2. INTGRID LAYER (Control) - SAME AS BEFORE
|
|
intgrid_uid = 200
|
|
int_grid_def = {
|
|
"__type": "IntGrid",
|
|
"identifier": "Terrain_Control",
|
|
"type": "IntGrid",
|
|
"uid": intgrid_uid,
|
|
"gridSize": 32,
|
|
"displayOpacity": 1,
|
|
"pxOffsetX": 0,
|
|
"pxOffsetY": 0,
|
|
"intGridValues": [
|
|
{ "value": 1, "identifier": "Grass", "color": "#36BC29" },
|
|
{ "value": 2, "identifier": "Dirt", "color": "#8B5F2A" },
|
|
{ "value": 3, "identifier": "Water", "color": "#388BE7" },
|
|
{ "value": 4, "identifier": "Farm", "color": "#54301A" }
|
|
],
|
|
"autoRuleGroups": [],
|
|
"autoSourceLayerDefUid": None,
|
|
"tilesetDefUid": None,
|
|
"tilePivotX": 0,
|
|
"tilePivotY": 0
|
|
}
|
|
|
|
# 3. AUTO LAYERS (Visuals)
|
|
# Now we map to regions in the ATLAS!
|
|
# Grass: Top-Left (0,0) -> ID 0 (and onwards)
|
|
# Dirt: Top-Right (256,0) -> Column 8 -> ID 8
|
|
# Water: Bottom-Left (0,256) -> Row 8 -> ID 128
|
|
# Farm: Bottom-Right (256,256) -> Col 8, Row 8 -> ID 136
|
|
|
|
# Wait, simple tile arithmetic:
|
|
# 512 width = 16 tiles.
|
|
# Grass (0,0): Tile 0
|
|
# Dirt (256,0): 256/32 = 8th tile. ID = 8.
|
|
# Water (0,256): 256/32 = 8th row. 8 * 16 = 128. ID = 128.
|
|
# Farm (256,256): 8th col, 8th row. 128 + 8 = 136. ID = 136.
|
|
|
|
# We want RANDOM tiles from those 256x256 regions.
|
|
# Each region is 8x8 tiles = 64 tiles.
|
|
|
|
def get_region_ids(start_id, rows=8, cols=8, stride=16):
|
|
ids = []
|
|
for r in range(rows):
|
|
for c in range(cols):
|
|
ids.append(start_id + (r * stride) + c)
|
|
return ids
|
|
|
|
grass_ids = get_region_ids(0)
|
|
dirt_ids = get_region_ids(8)
|
|
water_ids = get_region_ids(128)
|
|
farm_ids = get_region_ids(136)
|
|
|
|
# We need just ONE AutoLayer "Visuals" that handles all rules!
|
|
# Or separate layers, but using the SAME tileset is more efficient.
|
|
# Let's make ONE "Terrain_Visuals" layer with 4 rule groups.
|
|
|
|
rule_uid = 5000
|
|
|
|
# Rules
|
|
rules_groups = []
|
|
|
|
# Helper for group
|
|
def make_group(name, int_val, tile_ids):
|
|
nonlocal rule_uid
|
|
g_uid = rule_uid; rule_uid += 1
|
|
r_uid = rule_uid; rule_uid += 1
|
|
return {
|
|
"uid": g_uid,
|
|
"name": name,
|
|
"active": True,
|
|
"isOptional": False,
|
|
"rules": [{
|
|
"uid": r_uid,
|
|
"active": True,
|
|
"size": 1,
|
|
"tileIds": tile_ids,
|
|
"alpha": 1,
|
|
"chance": 1,
|
|
"breakOnMatch": True,
|
|
"pattern": [int_val], # Match IntGrid value
|
|
"flipX": True, "flipY": True, "xModulo": 1, "yModulo": 1,
|
|
"checker": "None", "tileMode": "Random",
|
|
"pivotX": 0, "pivotY": 0, "outTileIds": [],
|
|
"perlinActive": False, "perlinSeed": 0, "perlinScale": 0.2, "perlinOctaves": 2
|
|
}]
|
|
}
|
|
|
|
rules_groups.append(make_group("Grass", 1, grass_ids))
|
|
rules_groups.append(make_group("Dirt", 2, dirt_ids))
|
|
rules_groups.append(make_group("Water", 3, water_ids))
|
|
rules_groups.append(make_group("Farm", 4, farm_ids))
|
|
|
|
visual_layer = {
|
|
"__type": "AutoLayer",
|
|
"identifier": "Terrain_Visuals",
|
|
"type": "AutoLayer",
|
|
"uid": 300,
|
|
"gridSize": 32,
|
|
"displayOpacity": 1,
|
|
"pxOffsetX": 0,
|
|
"pxOffsetY": 0,
|
|
"autoSourceLayerDefUid": intgrid_uid,
|
|
"tilesetDefUid": 150, # The Atlas
|
|
"tilePivotX": 0,
|
|
"tilePivotY": 0,
|
|
"autoRuleGroups": rules_groups
|
|
}
|
|
|
|
# Header & Setup
|
|
data = {
|
|
"__header__": { "fileType": "LDtk Project JSON", "app": "LDtk", "doc": "https://ldtk.io/json", "schema": "https://ldtk.io/files/JSON_SCHEMA.json", "appAuthor": "David via Antigravity", "appVersion": "1.5.3", "url": "https://ldtk.io" },
|
|
"iid": "6440c680-d380-11f0-b813-5db2a94f8a9c",
|
|
"jsonVersion": "1.5.3",
|
|
"appBuildId": 473703,
|
|
"nextUid": 10000,
|
|
"identifierStyle": "Capitalize",
|
|
"toc": [],
|
|
"worldLayout": "Free",
|
|
"worldGridWidth": 256, "worldGridHeight": 256,
|
|
"defaultLevelWidth": 512, "defaultLevelHeight": 512,
|
|
"defaultPivotX": 0, "defaultPivotY": 0,
|
|
"defaultGridSize": 16, "defaultEntityWidth": 16, "defaultEntityHeight": 16,
|
|
"bgColor": "#40465B", "defaultLevelBgColor": "#696A79",
|
|
"minifyJson": False, "externalLevels": False, "exportTiled": False, "simplifiedExport": False, "imageExportMode": "None", "exportLevelBg": True,
|
|
"pngFilePattern": None, "backupOnSave": False, "backupLimit": 10, "backupRelPath": None, "levelNamePattern": "Level_%idx",
|
|
"tutorialDesc": None, "customCommands": [], "flags": [],
|
|
"defs": {
|
|
"layers": [int_grid_def, visual_layer], # Control on BOTTOM in list = Rendered first? No. List index 0 = Topmost. We want Visuals on top? No, Control on top to see what we paint (transparently) or underneath? Usually Control is hidden or semi-transparent. Let's put Control first (Top).
|
|
"entities": [],
|
|
"tilesets": [atlas_def],
|
|
"enums": [], "externalEnums": [], "levelFields": []
|
|
},
|
|
"levels": [{
|
|
"identifier": "Level_0",
|
|
"iid": "level_0_iid",
|
|
"uid": 0,
|
|
"worldX": 0, "worldY": 0, "worldDepth": 0,
|
|
"pxWid": 1024, "pxHei": 1024,
|
|
"__bgColor": "#696A79", "bgColor": None, "useAutoIdentifier": True, "bgRelPath": None, "bgPos": None, "bgPivotX": 0.5, "bgPivotY": 0.5, "__smartColor": "#ADADB5", "__bgPos": None, "externalRelPath": None, "fieldInstances": [],
|
|
"layerInstances": [
|
|
{
|
|
"__identifier": "Terrain_Control",
|
|
"__type": "IntGrid",
|
|
"__cWid": 32, "__cHei": 32, "__gridSize": 32, "__opacity": 1, "__pxTotalOffsetX": 0, "__pxTotalOffsetY": 0, "__tilesetDefUid": None, "__tilesetRelPath": None, "iid": "inst_200", "levelId": 0, "layerDefUid": 200, "pxOffsetX": 0, "pxOffsetY": 0, "visible": True, "optionalRules": [], "intGridCsv": [0]*1024, "autoLayerTiles": [], "seed": 0, "overrideTilesetUid": None, "gridTiles": [], "entityInstances": []
|
|
},
|
|
{
|
|
"__identifier": "Terrain_Visuals",
|
|
"__type": "AutoLayer",
|
|
"__cWid": 32, "__cHei": 32, "__gridSize": 32, "__opacity": 1, "__pxTotalOffsetX": 0, "__pxTotalOffsetY": 0, "__tilesetDefUid": 150, "__tilesetRelPath": None, "iid": "inst_300", "levelId": 0, "layerDefUid": 300, "pxOffsetX": 0, "pxOffsetY": 0, "visible": True, "optionalRules": [], "intGridCsv": [], "autoLayerTiles": [], "seed": 0, "overrideTilesetUid": None, "gridTiles": [], "entityInstances": []
|
|
}
|
|
],
|
|
"__neighbours": []
|
|
}],
|
|
"worlds": [],
|
|
"dummyWorldIid": "6440c681-d380-11f0-b813-a103d476f7a1"
|
|
}
|
|
|
|
with open(LDTK_FILE, 'w') as f:
|
|
json.dump(data, f, indent=2)
|
|
print("LDtk project updated to connect Atlas with IntGrid!")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|