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 pygame
import itertools
import worldobject import worldobject
import copy import copy
@ -32,7 +33,7 @@ import copy
class Block(worldobject.WorldObject): class Block(worldobject.WorldObject):
def __init__(self, level, x, y, img_str='block1', def __init__(self, level, x, y, img_str='block1',
movable=False, visible=True, movable=False, visible=True,
width=1, height=1): width=1, height=1, blit_area=None):
self.__dict__.update(locals()) self.__dict__.update(locals())
worldobject.WorldObject.__init__(self, level, x, y, worldobject.WorldObject.__init__(self, level, x, y,
movable=movable, visible=visible) movable=movable, visible=visible)
@ -91,7 +92,7 @@ class Block(worldobject.WorldObject):
if self.visible: if self.visible:
window.blit(self.img, (self.x - 32 - self.level.camera_x, window.blit(self.img, (self.x - 32 - self.level.camera_x,
self.y - self.img.get_size()[1] + 24 self.y - self.img.get_size()[1] + 24
- self.level.camera_y)) - self.level.camera_y), self.blit_area)
class InvisBlock(Block): class InvisBlock(Block):
def __init__(self, level, x, y): 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, window.blit(self.img, (self.x - (32 + 64) - self.level.camera_x,
self.y - self.img.get_size()[1] + 24 self.y - self.img.get_size()[1] + 24
- self.level.camera_y)) - 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 pygame
import worldobject import worldobject
import robotgame.logic.lasermirror as lm
class Laser(worldobject.WorldObject): class Laser(worldobject.WorldObject):
def __init__(self, level, line): def __init__(self, level, line, first_laser=False):
self.__dict__.update(locals()) self.__dict__.update(locals())
(self.x0, self.y0), (self.x1, self.y1) = line (self.x0, self.y0), (self.x1, self.y1) = line
self.x0d, self.y0d, self.x1d, self.y1d \ self.x0d, self.y0d, self.x1d, self.y1d \
= self.x0 * 64, (self.y0 + 4) * 48, self.x1 * 64, (self.y1 + 4) * 48 = 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, worldobject.WorldObject.__init__(self, level, self.x0d,
max(self.y0d, self.y1d)) 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) worldobject.WorldObject.update(self, e, t, dt)
def draw(self, window): def draw(self, window):
pygame.draw.line(window, (255, 0, 0), colors = [(155, 0, 0), (255, 0, 0)]
(self.x0d - self.level.camera_x + 32, self.y0d - 46 - self.level.camera_y), c = self.start_dark
(self.x1d - self.level.camera_x + 32, self.y1d - 46 - self.level.camera_y), 2) 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: if self.player.is_moving:
obj.update_alpha() obj.update_alpha()
screen_size = self.game.window.get_size() screen_size = self.game.window.get_size()
self.camera_x = max(0, min(self.size[0] - screen_size[0], self.camera_x = max(0, min(self.size[0] - screen_size[0],
(self.player.x - screen_size[0] / 2 + 32))) (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 = lm.generate_simple_playfield(16)
self.target_blocks = []
# 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(
self, x1, y1, block.LaserSource(self, x1, y1, t.direction))
self.imgs['lasersource_' + t.direction.to_str()],
movable=False))
continue continue
def mir(b, x1, y1): def mir(b, x1, y1):
def f(x, y): def f(x, y):
@ -86,19 +78,23 @@ class Level4(level.Level):
self.generate_lasers() self.generate_lasers()
return g return g
return Mirror(self, x, y, b, links=[f(x, y)]) 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({ self.objects.append({
lm.MirrorLeft: mir(True, x1, y1), lm.MirrorLeft: lambda: mir(True, x1, y1),
lm.MirrorRight: mir(False, x1, y1), lm.MirrorRight: lambda: mir(False, x1, y1),
lm.Lever: lever.Lever( lm.Lever: lambda: lever.Lever(
self, x1, y1, [lambda setting: self.generate_lasers], self, x1, y1, [lambda setting: self.generate_lasers],
toggling=True, toggling=True,
anim='lever_leftright' if x in (0, 15) anim='lever_leftright' if x in (0, 15)
else 'lever_updown'), else 'lever_updown'),
lm.Target: block.Block(self, x1, y1, self.imgs['lasertarget'], lm.Target: targ,
movable=False), lm.Blocker: lambda: block.Block(self, x1, y1,
lm.Blocker: block.Block(self, x1, y1, self.imgs['block1'], self.imgs['block1'],
movable=False) movable=False)
}[t]) }[t]())
mirrors = list(filter(lambda obj: isinstance(obj, 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),
@ -110,12 +106,14 @@ class Level4(level.Level):
mirrors.remove(m) mirrors.remove(m)
l.links.insert(0, (lambda m: lambda setting: m.rotate())(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: if not i % 3:
self.objects.append(block.Block(self, i * 64, self.objects.append(block.Block(
48 * 3, self, i * 64, 48 * 3,
self.imgs['wall'], self.imgs['wall'],
width=3)) 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.objects.append(block.InvisBlock(self, i * 64,
self.size[1])) self.size[1]))
for i in range(self.size[1] / 48): 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_pos(64 * 7, 48 * 5)
self.player.set_init_pos() self.player.set_init_pos()
def on_completion(self):
# End game here.
print('Well done.')
def restart(self): def restart(self):
for obj in self.objects: for obj in self.objects:
obj.reset_pos() obj.reset_pos()
def generate_lasers(self): def generate_lasers(self):
self.lasers_orig = lm.generate_lasers(self.playfield) lasers = lm.generate_lasers(self.playfield)
self.lasers = [Laser(self, line) for line in self.lasers_orig] 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): def draw(self, window):
self._blit_background(window) self._blit_background(window)
@ -155,8 +171,8 @@ 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) \ is_special = lambda obj: type(obj) in \
or isinstance(obj, Laser) (Mirror, Laser, block.LaserSource, block.LaserTarget)
specials, nonspecials = (filter(is_special, objs), specials, nonspecials = (filter(is_special, objs),
filter(lambda obj: not is_special(obj), objs)) filter(lambda obj: not is_special(obj), objs))
return nonspecials + self._sort_line_specials(specials) return nonspecials + self._sort_line_specials(specials)
@ -164,31 +180,23 @@ class Level4(level.Level):
def _sort_line_specials(self, objs): def _sort_line_specials(self, objs):
mirrors = filter(lambda obj: isinstance(obj, Mirror), objs) mirrors = filter(lambda obj: isinstance(obj, Mirror), objs)
lasers = filter(lambda obj: isinstance(obj, Laser), objs) lasers = filter(lambda obj: isinstance(obj, Laser), objs)
# for m in mirrors: sources = filter(lambda obj: isinstance(obj, block.LaserSource), objs)
# print(m.x0, m.y0) targets = filter(lambda obj: isinstance(obj, block.LaserTarget), objs)
# print()
# for l in lasers:
# print((l.x0, l.y0), (l.x1, l.y1))
# print()
lasers_back = set(lasers) lasers_back = set(lasers)
sep_ords = [] sep_ords = []
for mirror in mirrors: for obj in itertools.chain(mirrors, targets):
before, after = [], [] before, after = [], []
for laser in _hit_lasers(mirror, lasers): for laser in _hit_lasers(obj, lasers):
lasers_back.discard(laser) lasers_back.discard(laser)
if _mirror_is_behind_laser(mirror, laser): if _obj_is_behind_laser(obj, laser):
after.append(laser) after.append(laser)
else: else:
before.append(laser) before.append(laser)
# for b in before: sep_ords.append(before + [obj] + after)
# print(b.x0, b.y0, b.x1, b.y1) points = set((obj.x0, obj.y0) for obj in itertools.chain(mirrors, targets))
# print(after) for laser in filter(lambda laser: (laser.x0, laser.y0) in points
# print() and (laser.x1, laser.y1) in points, lasers):
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) # print(laser)
xs, ys = filter(lambda sep_ord: laser in sep_ord, sep_ords) xs, ys = filter(lambda sep_ord: laser in sep_ord, sep_ords)
sep_ords.remove(xs) sep_ords.remove(xs)
@ -211,15 +219,20 @@ class Level4(level.Level):
nobjs.extend(ys) nobjs.extend(ys)
sep_ords.append(nobjs) 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 return objs
def _hit_lasers(mirror, lasers): def _hit_lasers(obj, lasers):
p = (mirror.x0, mirror.y0) p = (obj.x0, obj.y0)
return filter(lambda laser: (laser.x0, laser.y0) == p return filter(lambda laser: (laser.x0, laser.y0) == p
or (laser.x1, laser.y1) == p, lasers) 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): def _mirror_is_behind_laser(mirror, laser):
return \ return \
laser.y0 == laser.y1 \ 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 sources = ((pos, obj.direction) for pos, obj
in filter(lambda posobj: isinstance(posobj[1], Source), in filter(lambda posobj: isinstance(posobj[1], Source),
playfield.items())) playfield.items()))
lasers = [] lasers, lasers_flat = [], set()
def add(start, end): def add(start, end):
t = (min(start, end), max(start, end)) t = (min(start, end), max(start, end))
if not t in lasers: if not t in lasers_flat:
lasers.append(t) laser.append(t)
lasers_flat.add(t)
for start, direc in sources: for start, direc in sources:
end = start end = start
laser = []
lasers.append(laser)
while True: while True:
cur = playfield.get(end) cur = playfield.get(end)
if cur is Target: if cur is Target:
@ -176,7 +179,7 @@ def generate_lasers(playfield):
add(start, end) 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_flat):
break break
add(start, end) add(start, end)
direc = _mirror_new_direc(cur, direc) direc = _mirror_new_direc(cur, direc)