Now correctly draws lasers behind and in front of mirrors. Phew.
This commit is contained in:
		
							parent
							
								
									a654540095
								
							
						
					
					
						commit
						7713fbaf98
					
				| @ -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) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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) | ||||||
|  |                     ) | ||||||
|  |          ) | ||||||
|  |         ) | ||||||
|  | |||||||
| @ -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)) | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
| @ -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)) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Niels Serup
						Niels Serup