Source code for Mind.Orientation

from xml.etree.ElementTree import ElementTree as Tree
import base64 as b64
import zlib
import math
from os import path

import pygame


[docs]class MapError(Exception): """Exception for points outside the map.* """ def __init__(self, x, y, max_x, max_y): self.x = x self.y = y self.max_x = max_x self.max_y = max_y def __str__(self): self.fin = '' if self.x > self.max_x: self.fin += 'x should be reduced by ' + str(self.x - self.max_x) if self.y > self.max_y: self.fin += ', ' if self.y > self.max_y: self.fin += 'y should be reduced by ' + str(self.y - self.max_y) return self.fin
[docs]class MAP: """Basic map class. """ def __init__(self, width, height): self.width = width self.height = height self.objects = [] def __repr__(self): if self.objects: self.fin = 'Map ' + str(self.width) + "x" + str(self.height) +\ ":\n" self.count = 1 for obj in self.objects: self.fin += str(self.count) + '. ' + str(obj) + '\n' self.count += 1 return self.fin[:-1] else: return "Empty Map " + str(self.width) + "x" + str(self.height)\ + ":" def __contains__(self, item): self.item = item return self.item in self.objects def __bool__(self): return bool(self.objects)
[docs] def add_obj(self, obj): """Function that adds object(point, rect...) to map. """ self.obj = obj if type(self.obj) == point: if self.obj.x > self.width or self.obj.y > self.height: raise MapError(obj.x, obj.y, self.width, self.height) self.objects.append(self.obj)
[docs] def at(self, x, y): """Return generator of all items in map on x, y coordinates. """ self.x = x self.y = y for obj in self.objects: if type(obj) == point: if obj.x == self.x and obj.y == self.y: yield obj elif type(obj) == group_of_points: self.T = False for POINT in obj.at(self.x, self.y): yield POINT self.T = True if self.T: yield obj elif type(obj) == rect: if obj.at(self.x, self.y): yield obj
[docs]class point: """Basic point class. """ def __init__(self, x, y, Map, description='Unknown', quiet=False): self.x = x self.y = y self.Map = Map self.description = description if not quiet: self.Map.add_obj(self) self.name = self.description def __str__(self): return self.description + ' @ ' + str(self.x) + ', ' + str(self.y) __repr__ = __str__
[docs] def distance(self, other): """Calculates distance between this and given point. """ self.other = other return math.sqrt((self.x - other.x) ** 2 + (self.y - other.y) ** 2)
[docs] def get_xy(self): """Returns point's x and y. """ return (self.x, self.y)
[docs]class line: """Basic line class. """ def __init__(self, points, Map, description='Unknown', quiet=False, from_line_seg=False): self.points = points if from_line_seg: self.segment = from_line_seg else: self.segment = line_seg(self.points, Map, quiet=True, from_line=self) self.Map = Map self.name = self.description = description if not quiet: self.Map.add_obj(self) self.dif = self.x_dif, self.y_dif = self.points[1].x -\ self.points[0].x, self.points[1].y - self.points[0].y self.a = self.y_dif / self.x_dif self.b = self.points[0].y - self.a * self.points[0].x self.fnc = lambda x: self.a * x + self.b def __str__(self): return self.description + ' line (' + str(self.points[0]) + ', ' +\ str(self.points[1]) + ')' __repr__ = __str__ def __contains__(self, other): self.other = other if type(self.other) == point: return self.fnc(self.other.x) == self.other.y elif type(self.other) == group_of_points: for P in self.other.points: if not P in self: return False return True elif type(self.other) == rect: if self.points[0] in self.other or self.points[1] in \ self.other: return True self.lines = [] for p in self.other.points(): self.lines.append(line((self.points[0], p), self.Map, quiet=True)) self.angles = [] for l in self.lines: self.angles.append(l.get_f_angle(0) + 360) if min(self.angles) <= self.get_f_angle(0) + 360 <=\ max(self.angles): return True return False
[docs] def get_angle(self): """Returns line smallest angle (0-90).* """ return self.segment.get_angle()
[docs] def get_f_angle(self, p_index): """Returns full line angle (0-360). """ return self.segment.get_f_angle(p_index)
[docs] def perpend(self, point, quiet=False): """Returns perpendicular that goes through given point. """ self.d = direction(point, (self.get_f_angle(0) + 90) % 360, self.Map, quiet=quiet) return self.d.line(quiet)
[docs] def collide(self, L): """Returns point of intersection of lines. """ self.L = L x = -(self.b - self.L.b)/(self.a - self.L.a) y = self.fnc(x) return (x, y)
[docs]class line_seg: """Basic line segment class. """ def __init__(self, points, Map, description='Unknown', quiet=False, from_line=False): self.points = points self.Map = Map self.description = description if not quiet: self.Map.add_obj(self) self.name = self.description self.dif = self.x_dif, self.y_dif = (abs(self.points[0].x - self.points[1].x), abs(self.points[0].y - self.points[1].y)) if self.y_dif == 0: self.cof = "horizontal" else: self.cof = self.x_dif / self.y_dif if from_line: self.line = from_line else: self.line = line(self.points, self.Map, quiet=True, from_line_seg=self) def __len__(self): return int(self.points[0].distance(self.points[1])) def __str__(self): return self.description + ' line segment (' + str(self.points[0]) +\ ', ' + str(self.points[1]) + ')' __repr__ = __str__ def __contains__(self, other): self.other = other if type(self.other) == point: if self.other in self.points: return True self.l = line((self.points[0], self.other), Map, quiet=True) if self.l.cof == self.cof: if self.cof == "horizontal": if self.points[0].y > self.points[1].y: if self.points[0].y > self.other.y >\ self.points[1].y: return True else: if self.points[0].y < self.other.y <\ self.points[1].y: return True else: if (self.points[0].y > self.other.y > self.points[1].y or self.points[0].y < self.other.y < self.points[1].y) and (self.points[0].x > self.other.x > self.points[1].x or self.points[0].x < self.other.x < self.points[1].x): return True elif type(self.other) == group_of_points: for P in self.other.points: if not P in self: return False return True elif type(self.other) == rect: if self.other in self.line: if ((self.points[0].x >= self.points[1].x and self.other.x <= self.points[0].x) or (self.points[1].x > self.points[0].x and self.other.x <= self.points[1].x))\ and (self.points[0].y >= self.points[1].y and self.other.y <= self.points[0].y) or (self.points[1].y > self.points[0].y and self.other.y <= self.points[1].y): return True return False
[docs] def get_angle(self): """Returns line smallest angle(0-90).* """ if self.cof == "horizontal": return 90.0 return math.degrees(math.atan(self.x_dif / self.y_dif))
[docs] def get_f_angle(self, p_index): """Returns full line angle (0-360). """ self.a = self.get_angle() self.x1, self.y1 = self.points[p_index].get_xy() self.x2, self.y2 = self.points[not p_index].get_xy() if self.x1 > self.x2: if self.y1 > self.y2: self.a = 180 - self.a else: if self.y1 > self.y2: self.a += 180 else: self.a = 360 - self.a self.a %= 360 return self.a
[docs]def q_points(x1, y1, x2, y2, Map): """Returns points for line and line_seg. """ p1 = point(x1, y1, Map, quiet=True) p2 = point(x2, y2, Map, quiet=True) return (p1, p2)
[docs]class ray: """Basic ray class. """ def __init__(self, start_p, some_p, Map, description='Unknown', quiet=False): self.start_p = start_p self.some_p = some_p self.line = line((self.start_p, self.some_p), Map, quiet=True, from_line_seg=True) self.line_seg = self.line.segment self.Map = Map if not quiet: self.Map.add_obj(self) self.description = description self.name = self.description self.dif = self.x_dif, self.y_dif = (abs(self.start_p.x - self.some_p.x), abs(self.start_p.y - self.some_p.y)) if self.y_dif == 0: self.cof = "horizontal" else: self.cof = self.x_dif / self.y_dif def __contains__(self, other): self.other = other if type(self.other) == point: if self.other == self.start_p: return True self.l = line((self.start_p, self.other), Map, quiet=True) if self.l.cof == self.cof: if self.cof == "horizontal": if self.start_p.y > self.some_p.y: if self.start_p.y > self.other.y: return True else: if self.start_p.y < self.other.y: return True else: if ((self.start_p.y > self.other.y and self.start_p > self.some_p) or (self.start_p.y < self.other.y and self.start_p.y < self.some_p.y)) and ((self.start_p.x > self.other.x and self.start_p > self.some_p) or (self.start_p.x < self.other.x and self.start_p > self.some_p)): return True elif type(self.other) == group_of_points: for P in self.other.points: if not P in self: return False return True return False
[docs]class direction: """Basic direction class. """ def __init__(self, point, angle, Map, description='Unknown', quiet=False): self.angle = angle self.rd = math.radians(self.angle) self.point = point self.description = description self.Map = Map if not quiet: self.Map.add_obj(self) def __str__(self): return self.description + " direction @" + str(self.point.x) +\ ", " + str(self.point.y) + "; angle: " + str(self.angle) __repr__ = __str__
[docs] def get_pos(self, distance): """Gets point of direction with given distance. """ self.distance = distance if self.angle == 0: return point(self.point.x, self.point.y - self.distance, self.Map, quiet=True) else: self.x = math.sin(self.rd) * self.distance self.y = math.cos(self.rd) * self.distance return point(self.point.x + self.x, self.point.y - self.y, self.Map, quiet=True)
[docs] def move(self, distance): """'Moves' directions point. """ self.point.x, self.point.y = self.get_pos(distance).get_xy()
[docs] def set_angle(self, angle): """Sets new angle. """ self.angle = angle self.rd = math.radians(self.angle)
[docs] def get_angle(self): """Returns direction angle. """ return self.angle
[docs] def ch_angle(self, change): """Changes angle for given value. """ self.angle += change self.rd = math.radians(self.angle)
[docs] def line(self, quiet=False): """Returns direction's line. """ return line((self.point, self.get_pos(10)), self.Map, self.description, quiet)
[docs]class group_of_points: """Class for group of points. """ def __init__(self, Map, description='Unknown', *points, quiet=False): self.Map = Map self.description = description self.points = points self.counter = 0 if not quiet: self.Map.add_obj(self) self.name = self.description def __str__(self): self.fin = self.description + ' group [' for Point in self.points: self.fin += str(Point) + '; ' self.fin = self.fin[:-2] + ']' return self.fin __repr__ = __str__
[docs] def at(self, x, y): """Return generator of all items in group on x, y coordinates. """ self.x = x self.y = y for Point in self.points: if Point.x == self.x and Point.y == self.y: yield Point
[docs]class rect: """Basic map rect class. """ def __init__(self, x, y, width, height, Map, description='Unknown', quiet=False): self.x = x self.y = y self.width = width self.height = height self.Map = Map if not quiet: self.Map.add_obj(self) self.description = description self.name = self.description def __str__(self): return self.description + ' rect ' + str(self.width) + 'X' +\ str(self.height) + ' @ ' + str(self.x) + ', ' + str(self.y) __repr__ = __str__ def __contains__(self, item): self.item = item if type(self.item) == point: if self.at(self.item.x, self.item.y): return True elif type(self.item) == group_of_points: for p in self.item.points: if not p in self: return False return True elif type(self.item) == rect: if self.x <= self.item.x and self.y <= self.item.y and self.x\ + self.width >= self.item.x + self.item.width and self.y +\ self.height >= self.item.y + self.item.height: return True return False else: raise TypeError("'in <rect>' doesn't support " + repr(self.item))
[docs] def at(self, x, y): """Test if point is in rect.* """ return self.x + self.width >= x >= self.x and self.y +\ self.height >= y >= self.y
[docs] def collide(self, other): """Tests colliding with given rect. """ self.fin = [0, 0, 0, 0] if self.y + self.height > other.y and self.y < other.y +\ other.height: if other.x + other.width > self.x + self.width > other.x: self.fin[0] = self.x + self.width - other.x if self.x + self.width > other.x + other.width > self.x: self.fin[2] = other.x + other.width - self.x if self.x + self.width > other.x and self.x < other.x +\ other.width: if other.y + other.height > self.y + self.height > other.y: self.fin[1] = self.y + self.height - other.y if self.y + self.height > other.y + other.height > self.y: self.fin[3] = other.y + other.height - self.y return self.fin
[docs] def touch(self, other): """Tests touching with other rect. """ self.fin = [False, False, False, False] if self.y + self.height > other.y and self.y < other.y +\ other.height: if self.x + self.width == other.x: self.fin[0] = True if other.x + other.width == self.x: self.fin[2] = True if self.x + self.width > other.x and self.x < other.x +\ other.width: if self.y + self.height == other.y: self.fin[1] = True if other.y + other.height == self.y: self.fin[3] = True return self.fin
[docs] def points(self, quiet=True): """Returns rect's points. """ yield point(self.x, self.y, self.Map, quiet=quiet) yield point(self.x + self.width, self.y, self.Map, quiet=quiet) yield point(self.x, self.y + self.height, self.Map, quiet=quiet) yield point(self.x + self.width, self.y + self.height, self.Map, quiet=quiet)
[docs] def get_xy(self): """Returns rect's coordinates. """ return (self.x, self.y)
[docs]class circle: """Basic circle class. """ def __init__(self, centre, radius, Map, description='Unknown', quiet=False): self.centre = centre self.x, self.y = self.centre.get_xy() self.radius = radius self.Map = Map if not quiet: self.Map.add_obj(self) self.description = description def __repr__(self): return 'circle ' + self.description + ' @' + str(self.x) + ', ' +\ str(self.y) + '; r=' + str(self.radius) __str__ = __repr__ def __contains__(self, p): return self.centre.distance(p) <= self.radius
[docs] def distance(self, l): """Returns distance between centre and line. """ self.l = l self.p = self.l.collide(self.l.perpend(self.centre)) return self.centre.distance(self.p)
[docs]class element: """Basic tilemap element class.* """ def __init__(self, name, props, Map): self.name = name self.Map = Map self.props = props self.opts = [] for prop in dict(self.props): self.opts.append(prop) if not self.props[prop]: del self.props[prop] @classmethod def __tmx_init__(cls, obj, Map): name = "" if "name" in obj.attrib: name = obj.attrib["name"] properties = {} if obj.find("properties"): for prop in obj.find("properties"): properties[prop.attrib["name"]] = prop.attrib["value"] if cls.__tmx_init__.__func__ == element.__tmx_init__.__func__: return cls(name, properties, Map) else: cls.name = name cls.properties = properties
[docs]class layer(element): """Basic tilemap layer (Tile Layer) class.* """ def __init__(self, name, props, mapping, Map): super().__init__(name, props, Map) self.mapping = mapping self.Map = Map self.screen = self.Map.screen self.screen_w, self.screen_h = self.screen.get_size() self.tiles = self.Map.images self.tile_width, self.tile_height = self.Map.tile_size self.x = self.y = 0 self.d = {} for t in self.tiles: for x in range(t.size): self.d[t.first + x] = (t, x) @classmethod def __tmx_init__(cls, obj, Map): super().__tmx_init__(obj, Map) BIN = zlib.decompress(b64.b64decode(obj.find("data").text[4:-3])) mapping = [[] for x in range(int(Map.t_height))] for p, x in enumerate(BIN): if not p % 4: mapping[int(p/4/Map.t_width)].append(int(x)) if cls.__tmx_init__.__func__ == layer.__tmx_init__.__func__: return cls(cls.name, cls.properties, mapping, Map) else: cls.mapping = mapping
[docs] def set_pos(self, x, y): """Sets position of layer.* """ self.x = x self.y = y
def get_tiles(self): x_s = int(self.x / self.tile_width) x_o = self.x % self.tile_width x_e = int(x_s + self.screen_w / self.tile_width + bool(x_o)) y_s = int(self.y / self.tile_height) y_o = self.y % self.tile_height y_e = int(y_s + self.screen_h / self.tile_height + bool(y_o)) return (x_s, x_o, x_e, y_s, y_o, y_e)
[docs] def blit(self): """Blits layer.* """ pos = self.get_tiles() for p_y, y in enumerate(self.mapping[pos[3]:pos[5]]): for p_x, x in enumerate(y[pos[0]:pos[2]]): if x: self.d[x][0].blit((p_x * self.tile_width - pos[1], p_y * self.tile_height - pos[4]), self.d[x][1])
[docs]class Object(element): """Basic tilemap object class.* """ def __init__(self, name, Type, props, Map, obj): super().__init__(name, props, Map) self.type = Type self.obj = obj self.Map.objects.append(self) self.Map.in_map.add_obj(self) @classmethod def __tmx_init__(cls, obj, Map): super().__tmx_init__(obj, Map) Type = "" x = int(obj.attrib["x"]) y = int(obj.attrib["y"]) width = height = 0 if "type" in obj.attrib: Type = obj.attrib["type"] if "width" in obj.attrib: width = int(obj.attrib["width"]) if "height" in obj.attrib: height = int(obj.attrib["height"]) if (not (width or height)) and Map.gid_point: Obj = point(x, y, Map.in_map, cls.name, True) elif (not width and height) and Map.gid_line: Obj = line(q_points(x, y, x + width, y + height, Map.in_map), Map.in_map, cls.name, True) else: Obj = rect(x, y, width, height, Map.in_map, cls.name, True) if cls.__tmx_init__.__func__ == Object.__tmx_init__.__func__: return cls(cls.name, Type, cls.properties, Map, Obj) else: cls.type = Type cls.x, cls.y = x, y cls.width, cls.height = width, height cls.obj = Obj def __str__(self): self.fin = "object " + str(self.obj) if self.opts: self.fin += '; [' for opt in self.opts: self.fin += str(opt) self.fin += ', ' self.fin = self.fin[:-2] self.fin += ']' if self.props: self.fin += '; {' for prop in self.props: self.fin += str(prop) self.fin += ': ' self.fin += str(self.props[prop]) self.fin += ', ' self.fin = self.fin[:-2] self.fin += '}' return self.fin __repr__ = __str__
[docs]class map_obj(Object): """Blitable tilemap object class. """ def __init__(self, name, Type, props, picture, Map, obj): super().__init__(name, Type, props, Map, obj) self.picture = picture self.x, self.y = self.obj.get_xy() @classmethod def __tmx_init__(cls, obj, Map): super().__tmx_init__(obj, Map) if cls.__tmx_init__.__func__ == map_obj.__tmx_init__.__func__: return cls(cls.name, cls.type, cls.properties, None, Map, cls.obj)
[docs] def blit(self): """Blits object.* """ if self.picture: self.Map.screen.blit(self.picture, self.get_blit())
[docs] def get_blit(self): """Returns where object should be blitted.* """ return (self.x - self.Map.x, self.y - self.Map.y)
[docs] def set_position(self, x, y): """Sets object position. """ self.x = x self.y = y
[docs] def move(self, x, y): """Moves object. """ self.x += x self.y += y
[docs]class Subject(map_obj): """Basic centre tilemap object class (subclass of :py:class:`map_obj`). """ def __init__(self, name, Type, props, picture, Map, obj): super().__init__(name, Type, props, picture, Map, obj) self.Map.set_camera_pos(self.x, self.y)
[docs] def set_position(self, x, y): """Sets object position. """ super().set_position(x, y) self.Map.set_camera_pos(self.x, self.y)
[docs] def move(self, x, y): """Moves object. """ super().move(x, y) self.Map.set_camera_pos(self.x, self.y)
[docs]class objectgroup(element): """Basic tilemap objectgroup (Object Layer) class. """ def __init__(self, name, props, objects, Map): super().__init__(name, props, Map) self.objects = objects def __iter__(self): for o in self.objects: yield o @classmethod def __tmx_init__(cls, obj, Map): super().__tmx_init__(obj, Map) objects = [] for P in obj: if P.tag == "object": if "type" in P.attrib and P.attrib["type"] in\ Map.decode[2]: objects.append(Map.decode[2][P.attrib["type"]].\ __tmx_init__(P, Map)) else: objects.append(Map.default[2].__tmx_init__(P, Map)) if cls.__tmx_init__.__func__ == objectgroup.__tmx_init__.__func__: return cls(cls.name, cls.properties, objects, Map) else: cls.objects = objects
[docs] def blit(self): """Blits all objects in objectgroup.* """ for o in self: if "blit" in dir(o) and not getattr(o, "no_blit", False): o.blit()
[docs]class image: """Basic tileset class.* """ def __init__(self, name, tile_x, tile_y, first, screen): self.name = name self.image = pygame.image.load(name).convert() self.tile_size = self.tile_x, self.tile_y = (tile_x, tile_y) self.images = [] self.size = self.x, self.y = self.image.get_size() self.xt = self.x // self.tile_x self.yt = self.y // self.tile_y for y in range(self.yt): for x in range(self.xt): self.images.append(pygame.Rect(x * tile_x, y * tile_y, tile_x, tile_y)) self.size = self.xt * self.yt self.first = first self.screen = screen
[docs] def Index(self, index): """Returns firstindex if index is in tileset else 0.* """ return (self.first <= index < self.first + self.size) * self.first
[docs] def blit(self, pos, index): """Blits image on index at position pos.* """ self.screen.blit(self.image, pos, self.images[index])
[docs]class visual_map: """Basic class for game map. :param int x: width of map :param int y: height of map :param bool layers: does map have layers :param str path: path to all map images :param decode: decoding; first dict is for layers, second for\ objectgroup and third for object :type decode: list of dicts :param tuple tilesize: size of each tile (needed only if *layers* are used) :param dict images: dictionary containing images paths and their nickname (used in ``write_on``) :param list else_: default decoding; first for layer, second for\ objectgroup, third for object :param bool gid_point: if ``True`` object's obj will be point if rect\ doesn't have width **and** height :param bool gid_line: if ``True`` object's obj will be line if rect\ doesn't have width **or** height :param bool size_in_tiles: is ``x`` and ``y`` measured in tiles """ def __init__(self, x, y, layers=True, path="", decode=[{}, {}, {}], tilesize=(), images={}, else_=[layer, objectgroup, Object], gid_point=True, gid_line=True, size_in_tiles=False): self.path = path self.screen = pygame.display.get_surface() if self.screen: self.screen_w, self.screen_h = self.screen.get_size() self.size = self.width, self.height = self.edge_width, self.edge_height = x, y self.x = self.y = self.edge_x = self.edge_y = 0 self.decode = decode self.default = else_ self.layers = layers if self.layers: if not tilesize: raise ValueError("If layers are ON, tilesize should be defined") self.images = [] self.layers = [] self.translate = {None: 0} self.tile_size = self.tile_width, self.tile_height = tilesize if size_in_tiles: self.tiles = self.t_width, self.t_height = self.width, self.height self.width *= self.tile_width self.height *= self.tile_height self.size = self.edge_width, self.edge_height = self.width, self.height else: self.tiles = self.t_width, self.t_height = self.width //\ self.tile_width, self.height // self.tile_height self.next_id = 1 for im, nm in images.items(): self.create_tileset(im, nm) self.objects = [] self.objectgroups = [] self.in_map = MAP(self.width, self.height) self.gid_point = gid_point self.gid_line = gid_line
[docs] def set_camera_pos(self, x, y, pos=(50, 50), edge=True): """Sets camera position. :param int x: x position of point :param int y: y position of point :param tuple pos: point of screen in percentage :param bool edge: if ``True`` won't be outside the screen """ self.x = x - self.screen_w * pos[0] / 100 self.y = y - self.screen_h * pos[1] / 100 self.edge = edge if self.edge: self.x = max(self.edge_x, min(self.x, self.edge_width - self.screen_w)) self.y = max(self.edge_y, min(self.y, self.edge_height - self.screen_h)) if self.layers: for l in self.layers: l.set_pos(self.x, self.y)
[docs] def get_camera_pos(self, pos=(50, 50)): """Gets camera position. :param tuple pos: point of screen in percentage """ return (self.x + self.screen_w * pos[0] / 100, self.y + self.screen_h * pos[1] / 100)
[docs] def blit(self): """Blits map and it’s all objects to the screen. """ if self.layers: for l in self.layers: l.blit() for g in self.objectgroups: g.blit()
[docs] def create_objectgroup(self, name, props={}, objects=[], **rest): """Creates map's objectgroup. :param str name: objectgroup name :param dict props: properties of objectgroup :param list objects: objects that belong to objectgroup :param rest: other objectgroup parameters """ if name in self.decode[1]: obj = self.decode[1][name] else: obj = self.default[1] self.objectgroups.append(obj(name, props, objects, Map=self, **rest))
[docs] def load_objectgroup(self, xml_obj): """Loads objectgroup from xml element.* :param xml_obj: element from which objectgroup is loaded """ if xml_obj.attrib["name"] in self.decode[1]: obj = self.decode[1][xml_obj.attrib["name"]] else: obj = self.default[1] self.objectgroups.append(obj.__tmx_init__(xml_obj, self))
[docs] def assign_object(self, objgroup, obj): """Assigns object to particular objectgroup.* :param str objgroup: name of the objectgroup :param obj: object which will be assigned """ for gr in self.objectgroups: if gr.name == objgroup: gr.objects.append(obj) break
[docs] def create_object(self, objgroup, name, Type, props={}, obj=None, **rest): """Creates map object and assigns it to particular objectgroup. """ if Type in self.decode[2]: o = self.decode[2][Type](name, Type, props, obj, **rest) else: o = self.default[2][Type](name, Type, props, obj, **rest) self.assign_object(objgroup, o) return o
[docs] def create_layer(self, name, props={}, **rest): """Creates map layer :param str name: layer name :param dict props: layer properties :param rest: other layer parameters """ if name in self.decode[0]: obj = self.decode[0][name] else: obj = self.default[0] self.layers.append(obj(name, props, [[0 for x in range(self.t_width)] for y in range(self.t_height)], self, **rest)) self.layers[-1].set_pos(self.x, self.y)
[docs] def load_layer(self, xml_obj): """Loads objectgroup from xml element.* :param xml_obj: element from which layer is loaded """ if xml_obj.attrib["name"] in self.decode[0]: obj = self.decode[0][xml_obj.attrib["name"]] else: obj = self.default[0] self.layers.append(obj.__tmx_init__(xml_obj, self))
[docs] def create_tileset(self, img, name): """Creates map tileset. :param str img: path to tileset image :param str name: tileset name """ self.images.append(image(path.join(self.path, img), self.tile_width, self.tile_height, self.next_id, self.screen)) self.translate[self.next_id] = name self.next_id += self.images[-1].size
[docs] def write_on(self, pos, layer, num, pic=None, mul_pos=False): """Changes map layer. """ if not self.layers: raise NotImplementedError("Can't use write_on when layers are off!") n = num + self.translate[pic] for l in self.layers: if l.name == layer: L = l break if mul_pos: for p in pos: L.mapping[p[1]][p[0]] = n else: L.mapping[pos[1]][pos[0]] = n
[docs] def clone_obj(self, key, key_type="name"): """Returns list of all objects with given parameter. :param str key: parameter of searching object/s :param str key_type: name, group or type; what key means. """ self.final = [] if key_type in ("group", "objectgroup"): for group in self.objectgroups: if group.name == key: for obj in group: self.final.append(obj) else: for obj in self.objects: if (obj.name if key_type == "name" else obj.type) == key: self.final.append(obj) if len(self.final) > 1: return self.final elif self.final: return self.final[0] else: return None
[docs] def set_edge(self, width, height): """Sets map edge. :param int width: new map width :param int height: new map height """ self.edge_width = width self.edge_height = height
[docs] def offset(self, x, y): """Sets map offset. :param int x: starting x of map :param int y: starting y of map """ self.edge_x = x self.edge_y = y
[docs]class tiled_map(visual_map): """Basic class for map in Tiled. :param str name: file name :param decode: decoding; first dict is for layers, second for\ objectgroup and third for object :type decode: list of dicts :param list else_: default decoding; first for layer, second for\ objectgroup, third for object :param bool gid_point: if ``True`` object's obj will be point if rect\ doesn't have width **and** height :param bool gid_line: if ``True`` object's obj will be line if rect\ doesn't have width **or** height """ def __init__(self, name, decode=[{}, {}, {}], else_=[layer, objectgroup, Object], gid_point=True, gid_line=True): self.name = name + '.tmx' self.xml = Tree(file=self.name) self.out_map = self.xml.getroot() super().__init__(int(self.out_map.attrib["width"]), int(self.out_map.attrib["height"]), True, path.dirname(self.name), decode, (int(self.out_map.attrib["tilewidth"]), int(self.out_map.attrib["tileheight"])), {}, else_, gid_point, gid_line, True) for part in self.out_map: if part.tag == "tileset": self.create_tileset(part.find("image").attrib["source"], part.attrib["name"]) elif part.tag == "layer": self.load_layer(part) elif part.tag == "objectgroup": self.load_objectgroup(part) def __str__(self): return "Tiled m" + str(self.in_map)[1:] __repr__ = __str__
[docs] def reset_screen(self): """Resets map's screen (should be executed if screen wasn't\ defined before) """ self.screen = pygame.display.get() self.screen_w, self.screen_h = self.screen.get_size()
[docs]class moving_map(tiled_map): """Subclass of :py:class:`tiled_map` for easier moving. :param str name: file name :param int x: map centre object x :param int y: map centre object y :param decode: decoding; first dict is for layers, second for\ objectgroup and third for object :type decode: list of dicts :param list else_: default decoding; first for layer, second for\ objectgroup, third for object :param bool gid_point: if ``True`` object's obj will be point if rect\ doesn't have width **and** height :param bool gid_line: if ``True`` object's obj will be line if rect\ doesn't have width **or** height """ def __init__(self, name, x, y, decode=[{}, {}, {}], else_=[layer, objectgroup, Object], gid_point=True, gid_line=True): super().__init__(name, decode, else_, gid_point, gid_line) self.X = x self.Y = y self.set_camera_pos(self.X, self.Y)
[docs] def set_position(self, x, y, pos=(50, 50), edge=True): """Sets centre object position :param int x: x position of centre object :param int y: y position of centre object :param tuple pos: point of screen in percentage :param bool edge: if ``True`` won't be outside the screen """ self.X = x self.Y = y self.set_camera_pos(self.X, self.Y, pos, edge)
[docs] def get_position(self): """Returns centre object coordinates. :returns: centre x and y :rtype: tuple """ return (self.X, self.Y)
[docs] def move(self, hor, ver, pos=(50, 50), edge=True): """Moves centre object. :param int hor: horizontal movement (positive for right, negative\ for left) :param int ver: vertical movement (positive for down, negative\ for up) :param tuple pos: point of screen in percentage :param bool edge: if ``True`` won't be outside the screen """ self.X += hor self.Y += ver self.set_camera_pos(self.X, self.Y, pos, edge)