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!
This commit is contained in:
2025-12-24 03:41:40 +01:00
parent 639dec504c
commit a4d795c561
4539 changed files with 929 additions and 0 deletions

197
tools/generate_tiled_map.py Normal file
View File

@@ -0,0 +1,197 @@
"""
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()