Spaces:
Sleeping
Sleeping
File size: 8,485 Bytes
82fa936 |
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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
"""
Sprite Generation - Shared utilities and resource/building sprites
Character sprites are generated by separate pipeline classes
"""
import numpy as np
from PIL import Image, ImageDraw
from dataclasses import dataclass
from typing import List
@dataclass
class Sprite:
frames: List[np.ndarray]
current_frame: int = 0
frame_speed: int = 5
tick_counter: int = 0
def next_frame(self) -> np.ndarray:
self.tick_counter += 1
if self.tick_counter >= self.frame_speed:
self.tick_counter = 0
self.current_frame = (self.current_frame + 1) % len(self.frames)
return self.frames[self.current_frame]
def get_current_frame(self) -> np.ndarray:
return self.frames[self.current_frame]
def reset(self):
self.current_frame = 0
self.tick_counter = 0
class SpriteGenerator:
"""Shared sprite generation utilities for resources and buildings"""
# ========================================================================
# RESOURCE SPRITES
# ========================================================================
@staticmethod
def generate_mushroom_sprite() -> Sprite:
img = Image.new('RGBA', (32, 32), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Stem
draw.rectangle([13, 16, 19, 28], fill=(240, 230, 210))
# Cap
draw.ellipse([8, 10, 24, 22], fill=(200, 50, 50))
# White spots
draw.ellipse([11, 13, 15, 17], fill=(255, 255, 255))
draw.ellipse([17, 12, 20, 15], fill=(255, 255, 255))
return Sprite(frames=[np.array(img)])
@staticmethod
def generate_berry_sprite() -> Sprite:
img = Image.new('RGBA', (32, 32), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Bush
draw.ellipse([6, 12, 26, 28], fill=(34, 139, 34))
# Berries
draw.ellipse([10, 15, 14, 19], fill=(200, 0, 0))
draw.ellipse([18, 14, 22, 18], fill=(200, 0, 0))
draw.ellipse([14, 20, 18, 24], fill=(200, 0, 0))
return Sprite(frames=[np.array(img)])
@staticmethod
def generate_wood_sprite() -> Sprite:
img = Image.new('RGBA', (32, 32), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Log pile
draw.rectangle([8, 18, 24, 24], fill=(101, 67, 33))
draw.rectangle([10, 12, 22, 18], fill=(139, 90, 43))
draw.rectangle([12, 6, 20, 12], fill=(101, 67, 33))
# Wood rings
draw.ellipse([14, 8, 18, 10], fill=(80, 50, 20))
return Sprite(frames=[np.array(img)])
# ========================================================================
# BUILDING SPRITES (IMPROVED MUSHROOM HOUSES!)
# ========================================================================
@staticmethod
def generate_house_sprite(level: int = 1) -> Sprite:
"""Beautiful mushroom house!"""
size = 64 + (level - 1) * 8
img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Stem (house base)
stem_color = (240, 230, 210) if level == 1 else (250, 240, 220)
draw.rectangle([size//4, size//2, size*3//4, size-4], fill=stem_color)
# Add texture to stem
for i in range(3):
y = size//2 + 10 + i*8
draw.line([(size//4+2, y), (size*3//4-2, y)], fill=(220, 210, 190), width=1)
# Mushroom cap (red with white spots)
cap_color = (200, 50, 50) if level == 1 else (220, 70, 70)
draw.ellipse([4, size//4, size-4, size//2+10], fill=cap_color)
# White spots on cap
spot_positions = [
(size//4, size//3),
(size//2 - 4, size//4 + 4),
(size*3//4 - 8, size//3 + 2)
]
if level > 1:
spot_positions.extend([
(size//3 - 4, size//2 - 2),
(size*2//3, size//2 - 4)
])
for x, y in spot_positions:
spot_size = 6 if level == 1 else 8
draw.ellipse([x, y, x+spot_size, y+spot_size], fill=(255, 255, 255))
# Door
door_width = 12 if level == 1 else 14
door_x = size//2 - door_width//2
draw.rectangle([door_x, size-18, door_x+door_width, size-4], fill=(101, 67, 33))
# Door knob
draw.ellipse([door_x+door_width-4, size-12, door_x+door_width-2, size-10], fill=(255, 215, 0))
# Windows (cute round windows)
if level > 1:
window_size = 8
# Left window
draw.ellipse([size//4-4, size//2+8, size//4+4, size//2+16], fill=(135, 206, 250))
draw.line([(size//4, size//2+8), (size//4, size//2+16)], fill=(100, 150, 200), width=1)
# Right window
draw.ellipse([size*3//4-4, size//2+8, size*3//4+4, size//2+16], fill=(135, 206, 250))
draw.line([(size*3//4, size//2+8), (size*3//4, size//2+16)], fill=(100, 150, 200), width=1)
if level > 2:
# Chimney
draw.rectangle([size*3//4-4, size//4-4, size*3//4+4, size//4+8], fill=(120, 80, 50))
# Smoke puffs
draw.ellipse([size*3//4-2, size//4-8, size*3//4+2, size//4-4], fill=(200, 200, 200))
return Sprite(frames=[np.array(img)])
@staticmethod
def generate_storage_sprite(level: int = 1) -> Sprite:
size = 64
img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Barn/warehouse style
draw.rectangle([8, 20, size-8, size-4], fill=(139, 90, 43))
draw.polygon([(8, 20), (size//2, 8), (size-8, 20)], fill=(120, 80, 50))
# Capacity bars
for i in range(level):
y = size - 12 - i*8
draw.rectangle([12, y, size-12, y+6], fill=(200, 180, 140))
# Door
draw.rectangle([size//2-8, size-16, size//2+8, size-4], fill=(80, 50, 30))
return Sprite(frames=[np.array(img)])
@staticmethod
def generate_workshop_sprite(level: int = 1) -> Sprite:
size = 64
img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Workshop building
draw.rectangle([8, 24, size-8, size-4], fill=(120, 100, 80))
draw.polygon([(8, 24), (size//2, 12), (size-8, 24)], fill=(100, 80, 60))
# Chimney with smoke
draw.rectangle([size-16, 8, size-12, 24], fill=(80, 60, 40))
draw.ellipse([size-18, 4, size-10, 10], fill=(180, 180, 180))
# Tool rack visual
draw.line([(12, 32), (size-12, 32)], fill=(60, 40, 20), width=2)
return Sprite(frames=[np.array(img)])
@staticmethod
def generate_townhall_sprite(level: int = 1) -> Sprite:
size = 80
img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Grand mushroom building
draw.rectangle([10, 30, size-10, size-4], fill=(180, 100, 60))
draw.ellipse([5, 10, size-5, 35], fill=(220, 80, 80))
# Multiple white spots
spots = [(15, 18), (30, 15), (45, 17), (60, 19)]
for x, y in spots:
draw.ellipse([x, y, x+8, y+8], fill=(255, 255, 255))
# Flag on top
draw.rectangle([size//2-2, 4, size//2+2, 20], fill=(101, 67, 33))
draw.polygon([(size//2+2, 8), (size//2+2, 16), (size//2+14, 12)], fill=(255, 0, 0))
# Large entrance
draw.rectangle([size//2-10, size-24, size//2+10, size-4], fill=(101, 67, 33))
# Star emblem
draw.text((size//2-6, size//2+4), "★", fill=(255, 215, 0))
return Sprite(frames=[np.array(img)])
@staticmethod
def generate_grave_sprite() -> Sprite:
img = Image.new('RGBA', (32, 32), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Tombstone
draw.rectangle([10, 12, 22, 28], fill=(100, 100, 100))
draw.ellipse([10, 8, 22, 16], fill=(100, 100, 100))
# Cross engraving
draw.line([(16, 14), (16, 20)], fill=(80, 80, 80), width=2)
draw.line([(13, 17), (19, 17)], fill=(80, 80, 80), width=2)
# Flowers
draw.ellipse([8, 26, 11, 29], fill=(255, 100, 100))
draw.ellipse([21, 26, 24, 29], fill=(255, 200, 100))
return Sprite(frames=[np.array(img)])
|