Now correctly draws lasers behind and in front of mirrors. Phew.

This commit is contained in:
Niels Serup 2012-08-13 16:20:45 +02:00
parent a654540095
commit 7713fbaf98
5 changed files with 127 additions and 45 deletions

View File

@ -29,17 +29,20 @@ import pygame
import worldobject import worldobject
class Laser(worldobject.WorldObject): class Laser(worldobject.WorldObject):
def __init__(self, level, p0, p1, laser_direction): def __init__(self, level, line):
self.__dict__.update(locals()) 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): def update(self, e, t, dt):
worldobject.WorldObject.update(self, e, t, dt) worldobject.WorldObject.update(self, e, t, dt)
def draw(self, window): def draw(self, window):
(x0, y0), (x1, y1) = self.p0, self.p1
pygame.draw.line(window, (255, 0, 0), pygame.draw.line(window, (255, 0, 0),
(x0 - self.level.camera_x + 32, y0 + 4 - self.level.camera_y), (self.x0d - self.level.camera_x + 32, self.y0d - 46 - self.level.camera_y),
(x1 - self.level.camera_x + 32, y1 + 4 - self.level.camera_y), 4) (self.x1d - self.level.camera_x + 32, self.y1d - 46 - self.level.camera_y), 2)

View File

@ -24,6 +24,8 @@
The fourth level. The fourth level.
""" """
from __future__ import print_function
import os import os
import pygame import pygame
import random import random
@ -35,8 +37,8 @@ import player
import tile import tile
import block import block
import lever import lever
import mirror from mirror import Mirror
import laser from laser import Laser
import misc import misc
import worldobject import worldobject
@ -60,12 +62,19 @@ class Level4(level.Level):
self.playfield = lm.generate_simple_playfield(16) 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(): for (x, y), t in self.playfield.items():
x1, y1 = 64 * x, 48 * (y + 4) x1, y1 = 64 * x, 48 * (y + 4)
if isinstance(t, lm.Source): if isinstance(t, lm.Source):
self.objects.append(block.Block( self.objects.append(block.Block(
self, x1, y1, self, x1, y1,
self.imgs['lasersource_' + t.direction.to_str().lower()], self.imgs['lasersource_' + t.direction.to_str()],
movable=False)) movable=False))
continue continue
def mir(b, x1, y1): def mir(b, x1, y1):
@ -76,7 +85,7 @@ class Level4(level.Level):
else lm.MirrorRight else lm.MirrorRight
self.generate_lasers() self.generate_lasers()
return g 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({ self.objects.append({
lm.MirrorLeft: mir(True, x1, y1), lm.MirrorLeft: mir(True, x1, y1),
lm.MirrorRight: mir(False, 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'], lm.Blocker: block.Block(self, x1, y1, self.imgs['block1'],
movable=False) movable=False)
}[t]) }[t])
mirrors = list(filter(lambda obj: isinstance(obj, mirror.Mirror), mirrors = list(filter(lambda obj: isinstance(obj, Mirror),
self.objects)) self.objects))
levers = list(filter(lambda obj: isinstance(obj, lever.Lever), levers = list(filter(lambda obj: isinstance(obj, lever.Lever),
self.objects)) self.objects))
@ -126,17 +135,14 @@ class Level4(level.Level):
def generate_lasers(self): def generate_lasers(self):
self.lasers_orig = lm.generate_lasers(self.playfield) self.lasers_orig = lm.generate_lasers(self.playfield)
self.lasers = [] self.lasers = [Laser(self, line) for line in self.lasers_orig]
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))
def draw(self, window): def draw(self, window):
self._blit_background(window) self._blit_background(window)
objs = self._sorted_objs(self.objects + self.lasers) 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: for obj in objs:
obj.draw(window) obj.draw(window)
@ -149,23 +155,88 @@ class Level4(level.Level):
return n_objs return n_objs
def _after_sort_line(self, objs): def _after_sort_line(self, objs):
is_special = lambda obj: isinstance(obj, mirror.Mirror) or isinstance(obj, laser.Laser) is_special = lambda obj: isinstance(obj, Mirror) \
specials, nonspecials = filter(is_special, objs), filter(lambda obj: not is_special(obj), objs) 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) return nonspecials + self._sort_line_specials(specials)
def _sort_line_specials(self, objs): def _sort_line_specials(self, objs):
mirrors = filter(lambda obj: isinstance(obj, mirror.Mirror), objs) mirrors = filter(lambda obj: isinstance(obj, Mirror), objs)
lasers = filter(lambda obj: isinstance(obj, laser.Laser), objs) lasers = filter(lambda obj: isinstance(obj, Laser), objs)
return mirrors + lasers # for m in mirrors:
# print(m.x0, m.y0)
def _is_laser_behind_mirror(mirror_direc, laser_direc): # print()
return { # for l in lasers:
(Left, Up): True, # print((l.x0, l.y0), (l.x1, l.y1))
(Left, Left): True, # print()
(Left, Down): False,
(Left, Right): False, lasers_back = set(lasers)
(Right, Up): True, sep_ords = []
(Right, Right): True, for mirror in mirrors:
(Right, Down): False, before, after = [], []
(Right, Left): False for laser in _hit_lasers(mirror, lasers):
}[(mirror_direc, laser_direc)] 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)
)
)
)

View File

@ -52,7 +52,8 @@ class Loader(object):
self.directory, 'tiles', 'indoor', 'ground%02d.png' % o)) self.directory, 'tiles', 'indoor', 'ground%02d.png' % o))
l = ['block1', 'block1_lifted', 'block3', '../lasertarget', l = ['block1', 'block1_lifted', 'block3', '../lasertarget',
'../lasersource_up', '../lasersource_down', '../lasersource_right'] '../lasersource_up', '../lasersource_down', '../lasersource_right',
'../lasertarget_glow']
for o in l: for o in l:
self.imgs[os.path.basename(o)] = pygame.image.load(os.path.join( self.imgs[os.path.basename(o)] = pygame.image.load(os.path.join(
self.directory, 'blocks', '%s.png' % o)) self.directory, 'blocks', '%s.png' % o))

View File

@ -157,28 +157,34 @@ def generate_lasers(playfield):
Return [((x, y), direction), ...] Return [((x, y), direction), ...]
""" """
width, height = 16, 16 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 = [] 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: for start, direc in sources:
end = start end = start
while True: while True:
cur = playfield.get(end) cur = playfield.get(end)
if cur is Target: if cur is Target:
lasers.append(((start, end), direc)) add(start, end)
break break
if cur is Blocker: if cur is Blocker:
lasers.append(((start, end), direc)) add(start, end)
break break
if cur in (MirrorLeft, MirrorRight): 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):
break break
lasers.append(((start, end), direc)) add(start, end)
direc = _mirror_new_direc(cur, direc) direc = _mirror_new_direc(cur, direc)
start = end start = end
new_end = direc.next_pos(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 new_end[0] < 0 or new_end[1] < 0 or \
if (start, end) not in lasers: new_end[0] >= width or new_end[1] >= height:
lasers.append(((start, new_end), direc)) add(start, new_end)
break break
end = new_end end = new_end
return lasers return lasers

View File

@ -29,9 +29,10 @@ import pygame
import worldobject import worldobject
class Mirror(worldobject.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()) 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.in_rotation = False
self.left_up_aim = self.left_up self.left_up_aim = self.left_up
@ -62,6 +63,6 @@ class Mirror(worldobject.WorldObject):
def draw(self, window): def draw(self, window):
fn = self.frame + 1 if not self.left_up_aim else self.frame + self._half_anim_len 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)] self.img = self.level.imgs['mirror'][int(fn)]
window.blit(self.img, (self.x - 32 - self.level.camera_x, window.blit(self.img, (self.xd - 32 - self.level.camera_x,
self.y - self.img.get_size()[1] + 24 self.yd - self.img.get_size()[1] + 24
- self.level.camera_y)) - self.level.camera_y))