예제 #1
0
	def __init__(self, filename, screen_width, screen_height):
		object.__init__(self)
		filename = level_path(filename)
		self.player = Player((50, 50))
		self.camera = pygame.Rect((50,50), (screen_width, screen_height))
		self.world_map = tiledtmxloader.TileMapParser().parse_decode(filename)
		resources = ResourceLoaderPygame()
		resources.load(self.world_map)
		self.renderer = RendererPygame(resources)
		self.renderer.set_camera_position_and_size(0, 0, screen_width, screen_height)
		self.renderer.set_camera_margin(0, 0, 0, 0)
		self.screen_width = screen_width
		self.screen_height = screen_height
		self.jump_timer = JumpTimer()
		self.jump_wait_timer = None
		self.input_state = None
		self._img_cache = {}
		self._img_cache["hits"] = 0
예제 #2
0
class Level(object):
	'''This object is responsible for drawing the level and everything in it'''
	def __init__(self, filename, screen_width, screen_height):
		object.__init__(self)
		filename = level_path(filename)
		self.player = Player((50, 50))
		self.camera = pygame.Rect((50,50), (screen_width, screen_height))
		self.world_map = tiledtmxloader.TileMapParser().parse_decode(filename)
		resources = ResourceLoaderPygame()
		resources.load(self.world_map)
		self.renderer = RendererPygame(resources)
		self.renderer.set_camera_position_and_size(0, 0, screen_width, screen_height)
		self.renderer.set_camera_margin(0, 0, 0, 0)
		self.screen_width = screen_width
		self.screen_height = screen_height
		self.jump_timer = JumpTimer()
		self.jump_wait_timer = None
		self.input_state = None
		self._img_cache = {}
		self._img_cache["hits"] = 0

	def restart(self):
		self.player.restart()

	def tile_magic(self, tile, allow_break=True):
		'''Handle special tiles'''
		#debug(tile)
		for special_tile in ('grow', 'shrink', 'narrow', 'widen'):
			if config.getint('Tiles', special_tile) == tile:
				getattr(self.player, special_tile)()
				return

	def collide_walls(self, ms):
		grounded = False

		for layer in self.world_map.layers:
			if layer.is_object_group:
				continue

			floor_tile = None
			for pos in self.player.bottom_collide_pts:
				tile = self.get_tile(pos, layer)
				if tile:
					# Move above this tile.
					# This assumes we are not completely overlapping a tile.
					# This should never happen if we limit movement to < 16px per frame
					floor_tile = tile
					self.player.displace(0, -(self.player.collide_rect.bottom % 16))
					grounded = True
					break
			if floor_tile:
				self.tile_magic(floor_tile)

				if floor_tile == config.getint('Tiles', 'crack') and self.player.heavy:
					self.set_platform(pos, layer, config.getint('Tiles', 'break'))
				elif floor_tile == config.getint('Tiles', 'break') and self.player.heavy:
					self.set_platform(pos, layer, 0)

				# All floor tiles stop the players fall
				self.player.velocity = (self.player.velocity[0],0)

			top_points = self.player.top_collide_pts
			for pos in top_points:
				if grounded: break
				if self.get_tile(pos, layer):
					debug('collide top %s', pos)
					self.player.displace(0, 16) # move one tile down
					self.player.displace(0, -(self.player.collide_rect.top % 16)) # move to the top of the tile
					self.player.velocity = (self.player.velocity[0],0)
					break

			left_points = self.player.left_collide_pts
			for pos in left_points:
				if self.get_tile(pos, layer):
					debug('collide left %s', pos)
					self.player.displace(16, 0)
					self.player.displace(-(self.player.collide_rect.left % 16), 0)
					break

			right_points = self.player.right_collide_pts
			for pos in right_points:
				if self.get_tile(pos, layer):
					debug('collide right %s', pos)
					debug(self.get_tile(pos,layer))
					self.player.displace(-(self.player.collide_rect.right % 16), 0)
					break

		# Update the jump timer which determines if it's possible to jump
		if grounded:
			self.jump_timer.set()
		else:
			self.jump_timer.update(ms)

	def get_tile(self, pos, layer):
		x,y = pos
		if x < 0 or y < 0  or x >= layer.pixel_width or y >= layer.pixel_height:
			raise OutOfBounds()
		x /= 16
		y /= 16
		tile = layer.decoded_content[x + y*layer.width]
		return tile

	def set_tile(self, pos, layer, tile):
		x,y = pos
		if x < 0 or y < 0  or x >= layer.pixel_width or y >= layer.pixel_height:
			raise OutOfBounds()
		x /= 16
		y /= 16
		layer.decoded_content[x + y*layer.width] = tile
		layer._gen_2D()

	def set_platform(self, pos, layer, tile):
		'''Set tile and horizontal neighbours'''
		x,y = pos
		current_tile = self.get_tile(pos, layer)
		platform = [pos]
		if x>=16:
			platform.append((x-16,y))
		if x<layer.pixel_width-16:
			platform.append((x+16,y))
		for pos2 in platform:
			if self.get_tile(pos2, layer) == current_tile:
				self.set_tile(pos2, layer, tile)

	def input_changed(self, action, state):
		x = 0
		if state['left']:
			x = -1
		elif state['right']:
			x = 1
		self.player.set_direction(x)

		self.input_state = state

		if not state['up']:
			self.jump_wait_timer = None

	def tick(self, ms):
		self.player.move(ms)

		if self.player.collide_rect.left >= self.world_map.pixel_width - 16:
			debug('Level complete')
			return True

		# Handle collisions with walls/platforms
		try:
			self.collide_walls(ms)
		except OutOfBounds:
			debug('%s out of bounds', self.player.collide_rect)
			raise FellOffMap()

		# Check for jump every frame, in case user is holding down the button
		if not self.jump_wait_timer and self.input_state and self.input_state['up'] and self.jump_timer.jump_allowed():
			debug('jump')
			self.jump_timer.unset()
			self.jump_wait_timer = Timer(config.getint('Physics','jump_wait_time')) # wait a bit between jumps
			self.player.start_jump()
		elif self.jump_wait_timer:
			if self.jump_wait_timer.check(ms):
				self.jump_wait_timer = None

		# Center camera on player
		self.camera.center = self.player.rect.center

		# Constrain camera to the level
		self.camera.right = min(self.camera.right, self.world_map.pixel_width)
		self.camera.bottom = min(self.camera.bottom, self.world_map.pixel_height)
		self.camera.left = max(self.camera.left, 0)
		self.camera.top = max(self.camera.top, 0)
		self.renderer.set_camera_position(self.camera.centerx, self.camera.centery)
		self.renderer.set_camera_margin(0, 0, 0, 0) # something is resetting the margin to 16px each frame... grrr

	def debug(self):
		debug('camera %s %s', self.camera.topleft,self.camera.bottomright)
		sprite_layers = self.renderer.get_layers_from_map()
		for sprite_layer in sprite_layers:
			debug('layer %s: margin %s, cam rect %s, render cam rect %s, paralax factor %s,%s',
					id(sprite_layer),
					self.renderer._margin,
					self.renderer._cam_rect,
					self.renderer._render_cam_rect,
					sprite_layer.paralax_factor_x,
					sprite_layer.paralax_factor_y)

	def screen_coordinates(self, pos):
		'''Convert world coordinates into screen coordinates'''
		x,y = pos
		return (x-self.camera.left, y-self.camera.top)

	def draw(self, screen):
		screen.fill((255,255,255))
		sprite_layers = self.renderer.get_layers_from_map()
		for sprite_layer in sprite_layers:
			if sprite_layer.is_object_group:
				self._draw_obj_group(screen, sprite_layer, self.camera.left, self.camera.top)
			else:
				self.renderer.render_layer(screen, sprite_layer)

		screen.blit(self.player.image, self.player.rect.move((-self.camera.left, -self.camera.y)).topleft)

		if config.options.debug:
			pygame.draw.rect(screen, (255,0,0), self.player.collide_rect.move((-self.camera.left, -self.camera.y)), 1)

		pygame.display.flip()

	def _draw_obj_group(self, screen, obj_group, cam_world_pos_x, cam_world_pos_y, font=None):
		goffx = obj_group.x
		goffy = obj_group.y
		for map_obj in obj_group.objects:
			debug1('object at %d,%d', map_obj.x, map_obj.y)
			debug1('source %s, image %s', map_obj.image_source, map_obj.image)
			size = (map_obj.width, map_obj.height)
			if size == (0, 0):
				size = (16,16)
			if map_obj.image_source:
				surf = pygame.image.load(map_obj.image_source)
				surf = pygame.transform.scale(surf, size)
				screen.blit(surf, (goffx + map_obj.x - cam_world_pos_x, \
                          goffy + map_obj.y - cam_world_pos_y))
			else:
				r = pygame.Rect(\
					(goffx + map_obj.x - cam_world_pos_x, \
					goffy + map_obj.y - cam_world_pos_y),\
                   size)
				pygame.draw.rect(screen, (255, 255, 0), r, 1)