From 7713fbaf988af77dd7da782e8a51c16ca5f5b058 Mon Sep 17 00:00:00 2001 From: Niels Serup Date: Mon, 13 Aug 2012 16:20:45 +0200 Subject: [PATCH] Now correctly draws lasers behind and in front of mirrors. Phew. --- robotgame/laser.py | 13 ++-- robotgame/level4.py | 127 +++++++++++++++++++++++++-------- robotgame/loader.py | 3 +- robotgame/logic/lasermirror.py | 20 ++++-- robotgame/mirror.py | 9 +-- 5 files changed, 127 insertions(+), 45 deletions(-) diff --git a/robotgame/laser.py b/robotgame/laser.py index 4d8484a..4d6f463 100644 --- a/robotgame/laser.py +++ b/robotgame/laser.py @@ -29,17 +29,20 @@ import pygame import worldobject class Laser(worldobject.WorldObject): - def __init__(self, level, p0, p1, laser_direction): + def __init__(self, level, line): self.__dict__.update(locals()) - worldobject.WorldObject.__init__(self, level, p0[0], max(p0[1], p1[1]) + 48) + (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 + worldobject.WorldObject.__init__(self, level, self.x0d, + max(self.y0d, self.y1d)) def update(self, e, t, dt): worldobject.WorldObject.update(self, e, t, dt) def draw(self, window): - (x0, y0), (x1, y1) = self.p0, self.p1 pygame.draw.line(window, (255, 0, 0), - (x0 - self.level.camera_x + 32, y0 + 4 - self.level.camera_y), - (x1 - self.level.camera_x + 32, y1 + 4 - self.level.camera_y), 4) + (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) diff --git a/robotgame/level4.py b/robotgame/level4.py index 0aa1ad0..e2d89c7 100644 --- a/robotgame/level4.py +++ b/robotgame/level4.py @@ -24,6 +24,8 @@ The fourth level. """ +from __future__ import print_function + import os import pygame import random @@ -35,8 +37,8 @@ import player import tile import block import lever -import mirror -import laser +from mirror import Mirror +from laser import Laser import misc import worldobject @@ -60,12 +62,19 @@ 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 + # } + 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().lower()], + self.imgs['lasersource_' + t.direction.to_str()], movable=False)) continue def mir(b, x1, y1): @@ -76,7 +85,7 @@ class Level4(level.Level): else lm.MirrorRight self.generate_lasers() return g - return mirror.Mirror(self, x1, y1, b, links=[f(x, y)]) + return Mirror(self, x, y, b, links=[f(x, y)]) self.objects.append({ lm.MirrorLeft: mir(True, x1, y1), lm.MirrorRight: mir(False, x1, y1), @@ -90,7 +99,7 @@ class Level4(level.Level): lm.Blocker: block.Block(self, x1, y1, self.imgs['block1'], movable=False) }[t]) - mirrors = list(filter(lambda obj: isinstance(obj, mirror.Mirror), + mirrors = list(filter(lambda obj: isinstance(obj, Mirror), self.objects)) levers = list(filter(lambda obj: isinstance(obj, lever.Lever), self.objects)) @@ -126,17 +135,14 @@ class Level4(level.Level): def generate_lasers(self): self.lasers_orig = lm.generate_lasers(self.playfield) - self.lasers = [] - for ((x0, y0), (x1, y1)), direc in self.lasers_orig: - self.lasers.append(laser.Laser( - self, (x0 * 64, y0 * 48), - (x1 * 64, y1 * 48), direc)) + self.lasers = [Laser(self, line) for line in self.lasers_orig] def draw(self, window): self._blit_background(window) objs = self._sorted_objs(self.objects + self.lasers) - objs = self._after_sort(itertools.groupby(objs, lambda obj: obj.y + obj.z)) + objs = self._after_sort(itertools.groupby( + objs, lambda obj: obj.y + obj.z)) for obj in objs: obj.draw(window) @@ -149,23 +155,88 @@ class Level4(level.Level): return n_objs def _after_sort_line(self, objs): - is_special = lambda obj: isinstance(obj, mirror.Mirror) or isinstance(obj, laser.Laser) - specials, nonspecials = filter(is_special, objs), filter(lambda obj: not is_special(obj), objs) + is_special = lambda obj: isinstance(obj, Mirror) \ + or isinstance(obj, Laser) + specials, nonspecials = (filter(is_special, objs), + filter(lambda obj: not is_special(obj), objs)) return nonspecials + self._sort_line_specials(specials) def _sort_line_specials(self, objs): - mirrors = filter(lambda obj: isinstance(obj, mirror.Mirror), objs) - lasers = filter(lambda obj: isinstance(obj, laser.Laser), objs) - return mirrors + lasers - -def _is_laser_behind_mirror(mirror_direc, laser_direc): - return { - (Left, Up): True, - (Left, Left): True, - (Left, Down): False, - (Left, Right): False, - (Right, Up): True, - (Right, Right): True, - (Right, Down): False, - (Right, Left): False - }[(mirror_direc, laser_direc)] + 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() + + lasers_back = set(lasers) + sep_ords = [] + for mirror in mirrors: + before, after = [], [] + for laser in _hit_lasers(mirror, lasers): + lasers_back.discard(laser) + if _mirror_is_behind_laser(mirror, 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): + # print(laser) + xs, ys = filter(lambda sep_ord: laser in sep_ord, sep_ords) + sep_ords.remove(xs) + sep_ords.remove(ys) + + xs, ys, nobjs = iter(xs), iter(ys), [] + while True: + x = next(xs) + if x is laser: + break + nobjs.append(x) + while True: + x = next(ys) + if x is laser: + break + nobjs.append(x) + + nobjs.append(laser) + nobjs.extend(xs) + nobjs.extend(ys) + sep_ords.append(nobjs) + + objs = list(itertools.chain(*sep_ords)) + list(lasers_back) + return objs + +def _hit_lasers(mirror, lasers): + p = (mirror.x0, mirror.y0) + return filter(lambda laser: (laser.x0, laser.y0) == p + or (laser.x1, laser.y1) == p, lasers) + + +def _mirror_is_behind_laser(mirror, laser): + return \ + laser.y0 == laser.y1 \ + and ( + (mirror.left_up + and ( + (laser.x0 == mirror.x0 and laser.x1 > mirror.x0) + or + (laser.x1 == mirror.x0 and laser.x0 > mirror.x0) + ) + ) \ + or \ + (not mirror.left_up + and ( + (laser.x0 == mirror.x0 and laser.x1 < mirror.x0) + or + (laser.x1 == mirror.x0 and laser.x0 < mirror.x0) + ) + ) + ) diff --git a/robotgame/loader.py b/robotgame/loader.py index 8d9d3c1..8189918 100644 --- a/robotgame/loader.py +++ b/robotgame/loader.py @@ -52,7 +52,8 @@ class Loader(object): self.directory, 'tiles', 'indoor', 'ground%02d.png' % o)) l = ['block1', 'block1_lifted', 'block3', '../lasertarget', - '../lasersource_up', '../lasersource_down', '../lasersource_right'] + '../lasersource_up', '../lasersource_down', '../lasersource_right', + '../lasertarget_glow'] for o in l: self.imgs[os.path.basename(o)] = pygame.image.load(os.path.join( self.directory, 'blocks', '%s.png' % o)) diff --git a/robotgame/logic/lasermirror.py b/robotgame/logic/lasermirror.py index 5735108..c8ad524 100644 --- a/robotgame/logic/lasermirror.py +++ b/robotgame/logic/lasermirror.py @@ -157,28 +157,34 @@ def generate_lasers(playfield): Return [((x, y), direction), ...] """ width, height = 16, 16 - sources = ((pos, obj.direction) for pos, obj in filter(lambda posobj: isinstance(posobj[1], Source), playfield.items())) + sources = ((pos, obj.direction) for pos, obj + in filter(lambda posobj: isinstance(posobj[1], Source), + playfield.items())) lasers = [] + def add(start, end): + t = (min(start, end), max(start, end)) + if not t in lasers: + lasers.append(t) for start, direc in sources: end = start while True: cur = playfield.get(end) if cur is Target: - lasers.append(((start, end), direc)) + add(start, end) break if cur is Blocker: - lasers.append(((start, end), direc)) + add(start, end) break if cur in (MirrorLeft, MirrorRight): if (start, end) in ((start, end) for (start, end), direc in lasers): break - lasers.append(((start, end), direc)) + add(start, end) direc = _mirror_new_direc(cur, direc) start = end new_end = direc.next_pos(end) - if new_end[0] < 0 or new_end[1] < 0 or new_end[0] >= width or new_end[1] >= height: - if (start, end) not in lasers: - lasers.append(((start, new_end), direc)) + if new_end[0] < 0 or new_end[1] < 0 or \ + new_end[0] >= width or new_end[1] >= height: + add(start, new_end) break end = new_end return lasers diff --git a/robotgame/mirror.py b/robotgame/mirror.py index 40ecce1..6bcc232 100644 --- a/robotgame/mirror.py +++ b/robotgame/mirror.py @@ -29,9 +29,10 @@ import pygame import worldobject class Mirror(worldobject.WorldObject): - def __init__(self, level, x, y, left_up=True, links=[]): + def __init__(self, level, x0, y0, left_up=True, links=[]): self.__dict__.update(locals()) - worldobject.WorldObject.__init__(self, level, x, y) + self.xd, self.yd = self.x0 * 64, (self.y0 + 4) * 48 + worldobject.WorldObject.__init__(self, level, self.xd, self.yd) self.in_rotation = False self.left_up_aim = self.left_up @@ -62,6 +63,6 @@ class Mirror(worldobject.WorldObject): def draw(self, window): fn = self.frame + 1 if not self.left_up_aim else self.frame + self._half_anim_len self.img = self.level.imgs['mirror'][int(fn)] - window.blit(self.img, (self.x - 32 - self.level.camera_x, - self.y - self.img.get_size()[1] + 24 + window.blit(self.img, (self.xd - 32 - self.level.camera_x, + self.yd - self.img.get_size()[1] + 24 - self.level.camera_y))