Interactions between lasers, targets and sources are prettier.

This commit is contained in:
Niels Serup 2012-08-13 21:42:46 +02:00
parent 7713fbaf98
commit c402c342b8
6 changed files with 151 additions and 62 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -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()

View File

@ -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

View File

@ -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)))

View File

@ -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

View File

@ -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)