source: skaapsteker/level.py

Last change on this file was 623:65881746dc20, checked in by Jeremy Thurgood <firxen@…>, 12 years ago

More Sprite hierarchy work.

File size: 6.9 KB
Line 
1try:
2 import json
3except ImportError:
4 import simplejson as json
5
6from pygame import Rect, Surface, Color, mixer
7from pygame.sprite import LayeredUpdates
8
9from . import data
10from .constants import SCREEN, Layers
11from .sprites.base import TILE_SIZE, find_sprite, Geography
12from .widgets.text import Text
13from .utils import cmul, cdiv, cint, cneg
14
15
16
17class TileSet(object):
18 def __init__(self, dirname):
19 self.dirname = dirname
20 self.tile_factories = {
21 '.': lambda pos: None,
22 '?': lambda pos: None, # Object placement helper
23 '-': self.tile_factory('floor.png', True),
24 'X': self.tile_factory('wall.png', True, True),
25 '<': self.tile_factory('floor-end-l.png', True),
26 '>': self.tile_factory('floor-end-r.png', True),
27 '=': self.tile_factory('floor-start-l.png', True),
28 '+': self.tile_factory('floor-start-r.png', True),
29 '(': self.tile_factory('wall-end-l.png', True, True),
30 ')': self.tile_factory('wall-end-r.png', True, True),
31 'q': self.tile_factory('wall-end-tr.png', True, True),
32 'd': self.tile_factory('wall-end-br.png', True, True),
33 'p': self.tile_factory('wall-end-tl.png', True, True),
34 'b': self.tile_factory('wall-end-bl.png', True, True),
35 '{': self.tile_factory('arch-l.png'),
36 '}': self.tile_factory('arch-r.png'),
37 '|': self.tile_factory('bamboo.png', layer=Layers.BACKGROUND, dirname='common'),
38 'h': self.tile_factory('hanging-lantern.png', layer=Layers.IN_FRONT, dirname='common'),
39 's': self.tile_factory('standing-lantern.png', layer=Layers.IN_FRONT, dirname='common'),
40 '!': self.tile_factory('dangly-bits.png', layer=Layers.IN_FRONT, dirname='common'),
41 'k': self.tile_factory('skaapsteker.png', layer=Layers.SKAAPSTEKER, dirname='skaapsteker'),
42 }
43
44
45 def get_tile(self, tilechar, pos):
46 return self.tile_factories[tilechar](pos)
47
48
49 def tile_factory(self, image_name, floor=False, block=False, layer=Layers.BACKGROUND, dirname=None):
50 if not dirname:
51 dirname = self.dirname
52 image = data.load_image('tiles/' + dirname + '/' + image_name)
53 def _tilefac(pos):
54 tile = Geography(pos, image=image)
55 tile.block = block
56 tile.floor = floor
57 tile._layer = layer
58 if not (tile.block or tile.floor):
59 tile.collides_with = set()
60 return tile
61 return _tilefac
62
63
64
65class Level(object):
66 def __init__(self, leveldef, soundsystem):
67 self.name = leveldef
68 self.level_data = json.loads(data.load('levels/' + leveldef + '.json').read())
69 self.sprites = LayeredUpdates()
70 self._soundsystem = soundsystem
71 self.build_tiles()
72 self.build_backgrounds()
73 self.setup_enemies()
74 self.setup_doorways()
75 self._background_music = None
76 if 'music' in self.level_data:
77 # soundsystem will call data.filepath
78 self._background_music = 'music/' + self.level_data['music'].get('track', '')
79 self._background_volume = self.level_data['music'].get('volume', 1.0)
80
81 def build_backgrounds(self):
82 self.backgrounds = []
83 for i, background in enumerate(self.level_data['backgrounds']):
84 image = data.load_image('backgrounds/' + background)
85 clip_rect = Rect((0, 0), self.pixel_size)
86 if i == 0:
87 clip_rect = Rect((0, 0), (cint(cmul(self.pixel_size, 0.75))))
88 clip_rect = clip_rect.clip(image.get_rect())
89 clip_rect = clip_rect.union(Rect((0, 0), SCREEN))
90 clip_rect.midbottom = image.get_rect().midbottom
91 image = image.subsurface(clip_rect)
92 self.backgrounds.append(image)
93
94 def enter(self):
95 if self._background_music:
96 self._soundsystem.play_background_music(self._background_music, self._background_volume)
97
98 def leave(self):
99 pass
100
101 def build_tiles(self):
102 self.tileset = TileSet(self.level_data['tileset'])
103 self.tiles = LayeredUpdates()
104 tile_data = self.level_data['tiles']
105 self.tile_size = (len(tile_data[0]), len(tile_data))
106 self.pixel_size = cmul(self.tile_size, TILE_SIZE)
107 for y, row in enumerate(tile_data):
108 for x, char in enumerate(row):
109 tile = self.tileset.get_tile(char, (x, y))
110 if tile:
111 self.tiles.add(tile)
112 self.sprites.add(tile)
113
114
115 def setup_enemies(self):
116 self.enemies = LayeredUpdates()
117 for enemy_def in self.level_data['enemies']:
118 enemy = find_sprite(enemy_def, 'enemies')
119 self.enemies.add(enemy)
120 self.sprites.add(enemy)
121
122
123 def setup_doorways(self):
124 self.doorways = {}
125 for door_name, door_def in self.level_data['doorways'].items():
126 doorway = find_sprite(door_def, 'base')
127 self.doorways[door_name] = doorway
128 self.sprites.add(doorway)
129
130
131 def get_surface(self):
132 return Surface(self.pixel_size)
133
134
135 def get_background_pos(self, background, viewport):
136 bg_scalable = background.get_rect().inflate(cneg(viewport.size)).size
137 lev_scalable = Rect((0, 0), self.pixel_size).inflate(cneg(viewport.size)).size
138 return cdiv(cmul(viewport.topleft, bg_scalable), lev_scalable)
139
140
141 def draw_background(self, surface):
142 clip_rect = surface.get_clip()
143 for background in self.backgrounds:
144 bg_pos = self.get_background_pos(background, clip_rect)
145 surface.blit(background, clip_rect.topleft, Rect(bg_pos, clip_rect.size))
146
147
148 def draw_tiles(self, surface):
149 self.tiles.draw(surface)
150
151
152 def draw(self, surface):
153 self.draw_background(surface)
154
155
156
157class DebugLevel(Level):
158 """Used by level-editor"""
159 def build_tiles(self):
160 super(DebugLevel, self).build_tiles()
161 tile_data = self.level_data['tiles']
162 for y, row in enumerate(tile_data):
163 for x, char in enumerate(row):
164 if char == '?':
165 self.check_debug_tile(x, y)
166
167
168 def check_debug_tile(self, x, y):
169 objects = []
170 objects += self.level_data.get('enemies', [])
171 objects += self.level_data.get('sprites', [])
172 doorways = self.level_data.get('doorways', {})
173 objects += doorways.values()
174
175 for object_ in objects:
176 if [x, y] == object_['pos']:
177 break
178 else:
179 tile = self.get_debug_tile(x, y)
180 print "Debug tile at (%i, %i)" % (x, y)
181 self.tiles.add(tile)
182 self.sprites.add(tile)
183
184
185 def get_debug_tile(self, x, y):
186 surface = Surface((64, 64))
187 surface.fill(Color('black'))
188 text = Text("? Tile at\n(%i, %i)" % (x, y), (2, 2), size=14, color='white')
189 text.draw(surface)
190 return Geography((x, y), image=surface.convert_alpha())
Note: See TracBrowser for help on using the repository browser.