Files
novafarma/tools/generate_tiled_map.py
NovaFarma Dev a4d795c561 Tiled Map Setup: Ground tiles, ruins & automated asset processing
Features:
- Resized 4513 PNG assets to 40% for optimal Tiled performance
- Created comprehensive tileset library (grass, dirt, trees, flowers, ruins, walls)
- Generated 3 test maps: travnik_32x32, zapuscena_vas_48x48, travnik_s_objekti
- Added 9 different ruined building tilesets for TownRestorationSystem integration

 Tools Added:
- resize_assets_for_tiled.py: Batch resize all assets to 40%
- generate_tiled_map.py: Auto-generate maps with placed objects
- fix_tiled_map.py: Create proper tile-based maps

 Structure:
- Slike_za_Tiled/: 4513 resized assets ready for Tiled
- assets/tilesets/: 16 tileset definitions (.tsx files)
- assets/maps/: 3 ready-to-use Tiled maps (.tmx files)

 Documentation:
- docs/TILED_SETUP_GUIDE.md: Complete setup and usage guide

Ready for map design in Tiled Map Editor!
2025-12-24 03:41:40 +01:00

198 lines
6.1 KiB
Python

"""
Generate Tiled map with Collection of Images tileset
Automatically places dirt, trees, and Kai character
"""
import os
import random
import xml.etree.ElementTree as ET
from xml.dom import minidom
# Configurations
SLIKE_DIR = r"c:\novafarma\Slike_za_Tiled"
OUTPUT_MAP = r"c:\novafarma\assets\maps\auto_generated_map.tmx"
MAP_WIDTH = 32
MAP_HEIGHT = 32
TILE_WIDTH = 48
TILE_HEIGHT = 48
def find_assets():
"""Find required assets in Slike_za_Tiled folder"""
assets = {
'dirt': [],
'trees': [],
'kai': None
}
if not os.path.exists(SLIKE_DIR):
print(f"❌ Error: {SLIKE_DIR} does not exist!")
print(" Run resize_assets_for_tiled.py first!")
return None
for filename in os.listdir(SLIKE_DIR):
if not filename.endswith('.png'):
continue
lower_name = filename.lower()
filepath = os.path.join(SLIKE_DIR, filename)
# Find dirt/soil tiles
if 'dirt' in lower_name or 'soil' in lower_name or 'ground' in lower_name:
assets['dirt'].append(filepath)
# Find trees
if 'tree' in lower_name:
assets['trees'].append(filepath)
# Find Kai character
if 'kai' in lower_name or 'character' in lower_name or 'player' in lower_name:
if assets['kai'] is None: # Take first match
assets['kai'] = filepath
print(f"🔍 Found assets:")
print(f" - Dirt/Soil tiles: {len(assets['dirt'])}")
print(f" - Trees: {len(assets['trees'])}")
print(f" - Kai character: {'' if assets['kai'] else ''}")
return assets
def create_tiled_map():
"""Create Tiled map with auto-placed objects"""
# Find assets
assets = find_assets()
if not assets:
return
# Create map root
map_elem = ET.Element('map', {
'version': '1.10',
'tiledversion': '1.11.1',
'orientation': 'orthogonal',
'renderorder': 'right-down',
'width': str(MAP_WIDTH),
'height': str(MAP_HEIGHT),
'tilewidth': str(TILE_WIDTH),
'tileheight': str(TILE_HEIGHT),
'infinite': '0',
'nextlayerid': '3',
'nextobjectid': '20'
})
# Create object layer
objectgroup = ET.SubElement(map_elem, 'objectgroup', {
'id': '2',
'name': 'Objects'
})
obj_id = 1
# Place 8 dirt tiles in center (2x4 grid)
print("\n🌍 Placing 8 dirt tiles in center...")
center_x = MAP_WIDTH // 2 - 1
center_y = MAP_HEIGHT // 2 - 2
for i in range(8):
if assets['dirt']:
dirt_asset = random.choice(assets['dirt'])
x = (center_x + (i % 2)) * TILE_WIDTH
y = (center_y + (i // 2)) * TILE_HEIGHT
obj = ET.SubElement(objectgroup, 'object', {
'id': str(obj_id),
'name': f'dirt_{i+1}',
'x': str(x),
'y': str(y),
'width': str(TILE_WIDTH),
'height': str(TILE_HEIGHT)
})
ET.SubElement(obj, 'image', {
'source': os.path.relpath(dirt_asset, os.path.dirname(OUTPUT_MAP))
})
obj_id += 1
# Place 10 trees randomly around the dirt area
print("🌲 Placing 10 trees randomly...")
tree_positions = []
attempts = 0
max_attempts = 100
while len(tree_positions) < 10 and attempts < max_attempts:
attempts += 1
tree_x = random.randint(2, MAP_WIDTH - 3) * TILE_WIDTH
tree_y = random.randint(2, MAP_HEIGHT - 3) * TILE_HEIGHT
# Avoid center dirt area
if (center_x * TILE_WIDTH <= tree_x <= (center_x + 2) * TILE_WIDTH and
center_y * TILE_HEIGHT <= tree_y <= (center_y + 4) * TILE_HEIGHT):
continue
# Avoid placing trees too close together
too_close = False
for px, py in tree_positions:
if abs(tree_x - px) < TILE_WIDTH * 3 and abs(tree_y - py) < TILE_HEIGHT * 3:
too_close = True
break
if too_close:
continue
if assets['trees']:
tree_asset = random.choice(assets['trees'])
tree_positions.append((tree_x, tree_y))
obj = ET.SubElement(objectgroup, 'object', {
'id': str(obj_id),
'name': f'tree_{len(tree_positions)}',
'x': str(tree_x),
'y': str(tree_y),
'width': str(TILE_WIDTH * 2),
'height': str(TILE_HEIGHT * 2)
})
ET.SubElement(obj, 'image', {
'source': os.path.relpath(tree_asset, os.path.dirname(OUTPUT_MAP))
})
obj_id += 1
# Place Kai character near center
if assets['kai']:
print("🧑 Placing Kai character...")
kai_x = (center_x + 2) * TILE_WIDTH + 60
kai_y = center_y * TILE_HEIGHT + 80
obj = ET.SubElement(objectgroup, 'object', {
'id': str(obj_id),
'name': 'kai_player',
'x': str(kai_x),
'y': str(kai_y),
'width': str(TILE_WIDTH),
'height': str(TILE_HEIGHT)
})
ET.SubElement(obj, 'image', {
'source': os.path.relpath(assets['kai'], os.path.dirname(OUTPUT_MAP))
})
# Write XML to file
os.makedirs(os.path.dirname(OUTPUT_MAP), exist_ok=True)
# Pretty print XML
xml_str = ET.tostring(map_elem, encoding='unicode')
dom = minidom.parseString(xml_str)
pretty_xml = dom.toprettyxml(indent=' ', encoding='UTF-8')
with open(OUTPUT_MAP, 'wb') as f:
f.write(pretty_xml)
print(f"\n{'='*60}")
print(f"✨ TILED MAP CREATED!")
print(f"{'='*60}")
print(f"📁 Location: {OUTPUT_MAP}")
print(f"📏 Size: {MAP_WIDTH}x{MAP_HEIGHT} tiles")
print(f"🎮 Objects placed:")
print(f" - 8 dirt tiles (center)")
print(f" - {len(tree_positions)} trees (random)")
print(f" - 1 Kai character")
print(f"\n🚀 Open in Tiled Map Editor to continue editing!")
if __name__ == "__main__":
create_tiled_map()