diff --git a/resources/graphics/lasersource_right.png b/resources/graphics/lasersource_right.png index 0b406bd..5dc6fba 100644 Binary files a/resources/graphics/lasersource_right.png and b/resources/graphics/lasersource_right.png differ diff --git a/robotgame/block.py b/robotgame/block.py index 1d9f565..7e2e71d 100644 --- a/robotgame/block.py +++ b/robotgame/block.py @@ -25,6 +25,7 @@ A generic block. And other block derivatives. """ import pygame +import itertools import worldobject import copy @@ -32,7 +33,7 @@ import copy class Block(worldobject.WorldObject): def __init__(self, level, x, y, img_str='block1', movable=False, visible=True, - width=1, height=1): + width=1, height=1, blit_area=None): self.__dict__.update(locals()) worldobject.WorldObject.__init__(self, level, x, y, movable=movable, visible=visible) @@ -91,7 +92,7 @@ class Block(worldobject.WorldObject): if self.visible: window.blit(self.img, (self.x - 32 - self.level.camera_x, self.y - self.img.get_size()[1] + 24 - - self.level.camera_y)) + - self.level.camera_y), self.blit_area) class InvisBlock(Block): def __init__(self, level, x, y): @@ -286,3 +287,25 @@ class Door(Block): window.blit(self.img, (self.x - (32 + 64) - self.level.camera_x, self.y - self.img.get_size()[1] + 24 - self.level.camera_y)) + +class LaserSource(Block): + def __init__(self, level, x1, y1, source_direction): + self.__dict__.update(locals()) + Block.__init__(self, level, x1, y1, + 'lasersource_' + source_direction.to_str(), + movable=False) + +class LaserTarget(Block): + def __init__(self, level, x0, y0): + self.__dict__.update(locals()) + self.xd, self.yd = self.x0 * 64, (self.y0 + 4) * 48 + Block.__init__(self, level, self.xd, self.yd, + 'lasertarget', movable=False) + self.glows = False + + def new_playfield_update(self): + self.glows, self.img_str = (True, 'lasertarget_glow') \ + if (self.x0, self.y0) in itertools.chain(*self.level.lasers_orig) \ + else (False, 'lasertarget') + self.load() + diff --git a/robotgame/laser.py b/robotgame/laser.py index 4d6f463..cc68f85 100644 --- a/robotgame/laser.py +++ b/robotgame/laser.py @@ -27,22 +27,70 @@ A laser for drawing. import pygame import worldobject +import robotgame.logic.lasermirror as lm class Laser(worldobject.WorldObject): - def __init__(self, level, line): + def __init__(self, level, line, first_laser=False): self.__dict__.update(locals()) (self.x0, self.y0), (self.x1, self.y1) = line self.x0d, self.y0d, self.x1d, self.y1d \ = self.x0 * 64, (self.y0 + 4) * 48, self.x1 * 64, (self.y1 + 4) * 48 + if self.y0d > self.y1d: + self.y0d, self.y1d = self.y1d, self.y0d + if self.x0d > self.x1d: + self.x0d, self.x1d = self.x1d, self.x0d worldobject.WorldObject.__init__(self, level, self.x0d, max(self.y0d, self.y1d)) - def update(self, e, t, dt): + x0de = 31 + y0de = -48 + x1de = 31 + y1de = -48 + if self.x0 < 0: + x0de += 32 + if self.y0 < 0: + y0de += 24 + if self.x1d >= self.level.size[0]: + x1de -= 32 + if self.first_laser and self.y0 == 0 and self.y0 != self.y1: + y0de += 6 + if self.level.playfield.get((self.x0, self.y0)) is lm.Target and self.x0 < self.x1: + x0de += 20 + if self.level.playfield.get((self.x1, self.y1)) is lm.Target and self.x0 < self.x1: + x1de -= 20 + self.x0d += x0de + self.y0d += y0de + self.x1d += x1de + self.y1d += y1de + + self.start_dark = 0 + + def update(self, e, t, dt): + self.start_dark = (t % 200) / 100 worldobject.WorldObject.update(self, e, t, dt) def draw(self, window): - pygame.draw.line(window, (255, 0, 0), - (self.x0d - self.level.camera_x + 32, self.y0d - 46 - self.level.camera_y), - (self.x1d - self.level.camera_x + 32, self.y1d - 46 - self.level.camera_y), 2) - + colors = [(155, 0, 0), (255, 0, 0)] + c = self.start_dark + if self.x0d != self.x1d: + length = self.x1d - self.x0d + for i in range(0, length, 8): + x0d = self.x0d + i + pygame.draw.line(window, colors[c], + (x0d - self.level.camera_x, + self.y0d - self.level.camera_y), + (x0d + min(8, length - i) - self.level.camera_x, + self.y1d - self.level.camera_y), 2) + c ^= 1 + else: + length = self.y1d - self.y0d + for i in range(0, length, 8): + y0d = self.y0d + i + pygame.draw.line(window, colors[c], + (self.x0d - self.level.camera_x, + y0d - self.level.camera_y), + (self.x0d - self.level.camera_x, + y0d + min(8, length - i) - self.level.camera_y), 2) + c ^= 1 + diff --git a/robotgame/level.py b/robotgame/level.py index 2bed7b4..e952fc6 100644 --- a/robotgame/level.py +++ b/robotgame/level.py @@ -72,7 +72,6 @@ class Level(object): if self.player.is_moving: obj.update_alpha() - screen_size = self.game.window.get_size() self.camera_x = max(0, min(self.size[0] - screen_size[0], (self.player.x - screen_size[0] / 2 + 32))) diff --git a/robotgame/level4.py b/robotgame/level4.py index e2d89c7..ce90161 100644 --- a/robotgame/level4.py +++ b/robotgame/level4.py @@ -62,20 +62,12 @@ class Level4(level.Level): self.playfield = lm.generate_simple_playfield(16) - - # self.playfield = { - # (0, 0): lm.Source(Down), - # (0, 4): lm.MirrorRight, - # (4, 4): lm.MirrorLeft - # } - + self.target_blocks = [] for (x, y), t in self.playfield.items(): x1, y1 = 64 * x, 48 * (y + 4) if isinstance(t, lm.Source): - self.objects.append(block.Block( - self, x1, y1, - self.imgs['lasersource_' + t.direction.to_str()], - movable=False)) + self.objects.append( + block.LaserSource(self, x1, y1, t.direction)) continue def mir(b, x1, y1): def f(x, y): @@ -86,19 +78,23 @@ class Level4(level.Level): self.generate_lasers() return g return Mirror(self, x, y, b, links=[f(x, y)]) + def targ(): + b = block.LaserTarget(self, x, y) + self.target_blocks.append(b) + return b self.objects.append({ - lm.MirrorLeft: mir(True, x1, y1), - lm.MirrorRight: mir(False, x1, y1), - lm.Lever: lever.Lever( + lm.MirrorLeft: lambda: mir(True, x1, y1), + lm.MirrorRight: lambda: mir(False, x1, y1), + lm.Lever: lambda: lever.Lever( self, x1, y1, [lambda setting: self.generate_lasers], toggling=True, anim='lever_leftright' if x in (0, 15) else 'lever_updown'), - lm.Target: block.Block(self, x1, y1, self.imgs['lasertarget'], - movable=False), - lm.Blocker: block.Block(self, x1, y1, self.imgs['block1'], - movable=False) - }[t]) + lm.Target: targ, + lm.Blocker: lambda: block.Block(self, x1, y1, + self.imgs['block1'], + movable=False) + }[t]()) mirrors = list(filter(lambda obj: isinstance(obj, Mirror), self.objects)) levers = list(filter(lambda obj: isinstance(obj, lever.Lever), @@ -110,12 +106,14 @@ class Level4(level.Level): mirrors.remove(m) l.links.insert(0, (lambda m: lambda setting: m.rotate())(m)) - for i in range(self.size[0] / 64): + top = self.size[0] / 64 + for i in range(top): if not i % 3: - self.objects.append(block.Block(self, i * 64, - 48 * 3, - self.imgs['wall'], - width=3)) + self.objects.append(block.Block( + self, i * 64, 48 * 3, + self.imgs['wall'], + width=1 if i == top - 1 else 3, + blit_area=(0, 0, 96, 192) if i == top - 1 else None)) self.objects.append(block.InvisBlock(self, i * 64, self.size[1])) for i in range(self.size[1] / 48): @@ -129,14 +127,32 @@ class Level4(level.Level): self.player.set_pos(64 * 7, 48 * 5) self.player.set_init_pos() + def on_completion(self): + # End game here. + print('Well done.') + def restart(self): for obj in self.objects: obj.reset_pos() def generate_lasers(self): - self.lasers_orig = lm.generate_lasers(self.playfield) - self.lasers = [Laser(self, line) for line in self.lasers_orig] + lasers = lm.generate_lasers(self.playfield) + self.lasers_orig = list(itertools.chain(*lasers)) + self.lasers = [] + for laser in lasers: + laser = iter(laser) + self.lasers.append(Laser(self, next(laser), first_laser=True)) + self.lasers.extend(Laser(self, line) for line in laser) + for b in self.target_blocks: + b.new_playfield_update() + if all(b.glows for b in self.target_blocks): + self.on_completion() + def update(self, e, t, dt): + level.Level.update(self, e, t, dt) + for laser in self.lasers: + laser.update(e, t, dt) + def draw(self, window): self._blit_background(window) @@ -155,8 +171,8 @@ class Level4(level.Level): return n_objs def _after_sort_line(self, objs): - is_special = lambda obj: isinstance(obj, Mirror) \ - or isinstance(obj, Laser) + is_special = lambda obj: type(obj) in \ + (Mirror, Laser, block.LaserSource, block.LaserTarget) specials, nonspecials = (filter(is_special, objs), filter(lambda obj: not is_special(obj), objs)) return nonspecials + self._sort_line_specials(specials) @@ -164,31 +180,23 @@ class Level4(level.Level): def _sort_line_specials(self, objs): mirrors = filter(lambda obj: isinstance(obj, Mirror), objs) lasers = filter(lambda obj: isinstance(obj, Laser), objs) - # for m in mirrors: - # print(m.x0, m.y0) - # print() - # for l in lasers: - # print((l.x0, l.y0), (l.x1, l.y1)) - # print() + sources = filter(lambda obj: isinstance(obj, block.LaserSource), objs) + targets = filter(lambda obj: isinstance(obj, block.LaserTarget), objs) lasers_back = set(lasers) sep_ords = [] - for mirror in mirrors: + for obj in itertools.chain(mirrors, targets): before, after = [], [] - for laser in _hit_lasers(mirror, lasers): + for laser in _hit_lasers(obj, lasers): lasers_back.discard(laser) - if _mirror_is_behind_laser(mirror, laser): + if _obj_is_behind_laser(obj, laser): after.append(laser) else: before.append(laser) - # for b in before: - # print(b.x0, b.y0, b.x1, b.y1) - # print(after) - # print() - sep_ords.append(before + [mirror] + after) - mirror_ps = [(mirror.x0, mirror.y0) for mirror in mirrors] - for laser in filter(lambda laser: (laser.x0, laser.y0) in mirror_ps - and (laser.x1, laser.y1) in mirror_ps, lasers): + sep_ords.append(before + [obj] + after) + points = set((obj.x0, obj.y0) for obj in itertools.chain(mirrors, targets)) + for laser in filter(lambda laser: (laser.x0, laser.y0) in points + and (laser.x1, laser.y1) in points, lasers): # print(laser) xs, ys = filter(lambda sep_ord: laser in sep_ord, sep_ords) sep_ords.remove(xs) @@ -211,15 +219,20 @@ class Level4(level.Level): nobjs.extend(ys) sep_ords.append(nobjs) - objs = list(itertools.chain(*sep_ords)) + list(lasers_back) + objs = list(itertools.chain(*sep_ords)) + list(lasers_back) \ + + sources return objs -def _hit_lasers(mirror, lasers): - p = (mirror.x0, mirror.y0) +def _hit_lasers(obj, lasers): + p = (obj.x0, obj.y0) return filter(lambda laser: (laser.x0, laser.y0) == p or (laser.x1, laser.y1) == p, lasers) - +def _obj_is_behind_laser(obj, laser): + return (_mirror_is_behind_laser + if isinstance(obj, Mirror) + else _target_is_behind_laser)(obj, laser) + def _mirror_is_behind_laser(mirror, laser): return \ laser.y0 == laser.y1 \ @@ -240,3 +253,6 @@ def _mirror_is_behind_laser(mirror, laser): ) ) ) + +def _target_is_behind_laser(target, laser): + return laser.x0 != laser.x1 diff --git a/robotgame/logic/lasermirror.py b/robotgame/logic/lasermirror.py index c8ad524..a1ded74 100644 --- a/robotgame/logic/lasermirror.py +++ b/robotgame/logic/lasermirror.py @@ -160,13 +160,16 @@ def generate_lasers(playfield): sources = ((pos, obj.direction) for pos, obj in filter(lambda posobj: isinstance(posobj[1], Source), playfield.items())) - lasers = [] + lasers, lasers_flat = [], set() def add(start, end): t = (min(start, end), max(start, end)) - if not t in lasers: - lasers.append(t) + if not t in lasers_flat: + laser.append(t) + lasers_flat.add(t) for start, direc in sources: end = start + laser = [] + lasers.append(laser) while True: cur = playfield.get(end) if cur is Target: @@ -176,7 +179,7 @@ def generate_lasers(playfield): add(start, end) break if cur in (MirrorLeft, MirrorRight): - if (start, end) in ((start, end) for (start, end), direc in lasers): + if (start, end) in ((start, end) for (start, end), direc in lasers_flat): break add(start, end) direc = _mirror_new_direc(cur, direc)