-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsvg_renderer.py
More file actions
135 lines (112 loc) · 5.13 KB
/
svg_renderer.py
File metadata and controls
135 lines (112 loc) · 5.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import os
import xml.etree.ElementTree as ET
from troop_animator import TroopAnimator
from health_bar_animator import HealthBarAnimator
from arrow_animator import ArrowAnimator
class SVGRenderer:
"""Handles SVG animation generation for battlefield"""
def __init__(self, battlefield):
self.battlefield = battlefield
self.troop_animator = TroopAnimator(battlefield)
self.health_bar_animator = HealthBarAnimator(battlefield)
self.arrow_animator = ArrowAnimator(battlefield)
def create_animated_svg(self, scale=20, frame_duration=0.5):
"""Create an animated SVG from the battlefield data"""
if not self.battlefield.animation_frames:
print("No animation frames captured.")
return None
# Check if output folder exists
if not hasattr(self.battlefield.png_renderer, 'output_folder') or not self.battlefield.png_renderer.output_folder:
print("No output folder found.")
return None
# Calculate SVG dimensions
width = self.battlefield.width * scale
height = self.battlefield.height * scale
# Create SVG root element
svg = ET.Element('svg', {
'width': str(width),
'height': str(height),
'xmlns': 'http://www.w3.org/2000/svg',
'viewBox': f'0 0 {width} {height}'
})
# Add background
ET.SubElement(svg, 'rect', {
'width': str(width),
'height': str(height),
'fill': '#8B4513' # Brown background
})
# Get all unique troop IDs that ever existed
all_troop_ids = self._get_all_troop_ids()
# Add troop elements and animations
for troop_id in all_troop_ids:
self._add_troop_elements(svg, troop_id, scale, frame_duration)
# Add arrow animations
self.arrow_animator.add_arrow_animations(svg, scale, frame_duration)
# Save to file
svg_path = os.path.join(self.battlefield.png_renderer.output_folder, "battle_animation.svg")
svg_content = self._svg_to_string(svg)
with open(svg_path, 'w', encoding='utf-8') as f:
f.write(svg_content)
print(f"Animated SVG saved to {svg_path}")
return svg_path
def _get_all_troop_ids(self):
"""Get all unique troop IDs that ever existed in any frame"""
all_troop_ids = set()
for frame in self.battlefield.animation_frames:
for troop in frame['troops']:
all_troop_ids.add(troop['id'])
return all_troop_ids
def _add_troop_elements(self, svg, troop_id, scale, frame_duration):
"""Add troop shape, health bar, and animations for a specific troop"""
# Get troop info from first frame where it appears
troop_info = self._get_troop_info(troop_id)
if not troop_info:
return
size = int(scale * 0.7)
# Create troop shape based on type
if troop_info['type'] == 'barbarian':
# Create circle for barbarian
shape = ET.SubElement(svg, 'circle', {
'r': str(size // 2),
'fill': troop_info['color'],
'stroke': 'black',
'stroke-width': '2',
'opacity': '1'
})
shape_type = 'circle'
else: # archer
# Create square for archer (offset to center it properly)
rect_size = size # Make it a proper square
shape = ET.SubElement(svg, 'rect', {
'width': str(rect_size),
'height': str(rect_size),
'x': str(-rect_size // 2), # Center horizontally
'y': str(-rect_size // 2), # Center vertically
'fill': troop_info['color'],
'stroke': 'black',
'stroke-width': '2',
'opacity': '1'
})
shape_type = 'rect'
# Add animations to troop
self.troop_animator.add_position_animation(shape, troop_id, shape_type, scale, frame_duration)
self.troop_animator.add_visibility_animation(shape, troop_id, frame_duration)
# Add health bar
self.health_bar_animator.add_health_bar(svg, troop_id, shape_type, scale, frame_duration)
def _get_troop_info(self, troop_id):
"""Get basic troop information from first appearance"""
for frame in self.battlefield.animation_frames:
for troop in frame['troops']:
if troop['id'] == troop_id:
return {
'color': '#0080FF' if troop['team'] == 0 else '#FF4040',
'type': troop['type']
}
return None
def _svg_to_string(self, svg):
"""Convert SVG element to formatted string"""
# Convert to string with proper formatting
rough_string = ET.tostring(svg, encoding='unicode')
# Add XML declaration
formatted_svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + rough_string
return formatted_svg