Source code for Mind.Orientation

"""
Part of library for maps and points in map.
"""

imported_tiled = True
try:
    import tiledtmxloader
except ImportError:
    imported_tiled = False
import math


[docs]class MapError(Exception): """Exception for points outside the map.* """ def __init__(self, x, y, max_x, max_y, min_x, min_y): self.x = x self.y = y self.max_x = max_x self.max_y = max_y self.min_x = min_x self.min_y = min_y def __str__(self): self.fin = '' if self.x > self.max_x: self.fin += 'x should be decreased 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 decreased by ' + str(self.y - self.max_y) if self.x < self.min_y: self.fin += 'x should be increased by ' + str(abs(self.x - self.min_x)) if self.y < self.min_y: self.fin += ', ' if self.y > self.max_y: self.fin += 'y should be increased by ' + str(abs(self.y - self.min_y)) return self.fin
[docs]class MAP: """Basic map class. :param int width: width of map :param int height: height of map :param int m_width: width on negative side :param int m_height: height on negative side """ def __init__(self, width, height, m_width=0, m_height=0): self.width = width self.height = height self.m_width = m_width self.m_height = m_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. :param int x: *x* position of coordinate :param int y: *y* position of coordinate :returns: iterator of all objects on that coordinates or ``None`` """ 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. :param int x: *x* position of point :param int y: *y* position of point :param Map: map on which will point be added :type Map: :py:class:`MAP` :param str description: point description :param bool quiet: if ``True`` won't appear on map """ blits = False 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 __tmx_init__(x, y, width, height, Map, name): if name: return point(x, y, Map, name) else: return point(x, y, Map) def __tmx_a_init__(x, y, width, height, Map, name, **prop): return ext_obj(point.__tmx_init__(x, y, width, height, Map, name), **prop) 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. :param other: other point :type point: :py:class:`point` :return: distance between this and other point """ self.other = other return math.sqrt(abs(self.x - other.x) ** 2 + abs(self.y - other.y) ** 2)
[docs] def get_xy(self): """Returns point's x and y. :returns: tuple of two integers (x and y) """ return (self.x, self.y)
[docs]class line: """Basic line class. :param tuple points: tuple of two points on line :param Map: Map on which will line be added :type Map: :py:class:`MAP` :param str description: line description :param bool quiet: if ``True`` won't appear on map :param bool from_line_seg: do not use (helps to the library) """ blits = False 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.description = description if not quiet: self.Map.add_obj(self) self.dif = self.x_dif, self.y_dif = self.segment.dif self.name = self.description self.cof = self.segment.cof 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: 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: return True if type(self.other) == group_of_points: for P in self.other.points: if not P in self: return False return True return False
[docs] def get_angle(self): """Returns line angle. :returns: smallest angle in relation to y-axis """ return self.segment.get_angle()
[docs]class line_seg: """Bacis line segment class. :param tuple points: tuple of end points on line :param Map: Map on which will line segment be added :type Map: :py:class:`MAP` :param str description: line description :param bool quiet: if ``True`` won't appear on map :param bool from_line: do not use (helps to the library) """ blits = False 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, P): self.P = P if self.P in self.points: return True self.l = line((self.points[0], self.P), 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.P.y > self.points[1].y: return True else: if self.points[0].y < self.P.y < self.points[1].y: return True else: if (self.points[0].y > self.P.y > self.points[1].y or self.points[0].y < self.P.y < self.points[1].y) and\ (self.points[0].x > self.P.x > self.points[1].x or self.points[0].x < self.P.x < self.points[1].x): return True return False
[docs] def get_angle(self): """Returns line angle. :returns: smallest angle in relation to y-axis """ if self.cof == "horizontal": return 90.0 return math.degrees(math.atan(self.x_dif / self.y_dif))
[docs]def q_points(x1, y1, x2, y2, Map): """Returns points for :py:class:`line` and :py:class:`line_seg`. :param int x1: x coordinate for first point :param int y1: y coordinate for first point :param int x2: x coordinate for second point :param int y2: y coordinate for second point :returns: tuple of two :py:class:`point` """ p1 = point(x1, y1, Map, quiet=True) p2 = point(x2, y2, Map, quiet=True) return (p1, p2)
[docs]class ray: """Basic ray class. :param start_p: starting point of ray :type start_p: :py:class:`point` :param some_p: any other point on ray :type some_p: :py:class:`point` :param Map: Map on which will line segment be added :type Map: :py:class:`MAP` :param str description: ray description :param bool quiet: if ``True`` won't appear on map """ blits = False 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 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.P.y: return True else: if self.start_p.y < self.P.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.P.x and self.start_p > self.some_p)): return True return False
[docs]class direction: """Basic direction class. :param point: point of direction :type point: :py:class:`point` :param int angle: direction angle :param Map: Map on which will direction be added :type Map: :py:class:`MAP` :param str description: direction description :param bool quiet: if ``True`` won't appear on map """ blits = False 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. :param int distance: how far from direction point is :returns: point on *distance* far away from direction point :rtype: :py:class:`point` """ 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. :param int distance: how far will direction be moved """ self.point.x, self.point.y = self.get_pos(distance).get_xy()
[docs] def set_angle(self, angle): """Sets new angle. :param int angle: new angle for direction """ self.angle = angle self.rd = math.radians(self.angle)
[docs] def get_angle(self): """Returns direction angle. :returns: direction angle """ return self.angle
[docs] def ch_angle(self, change): """Changes angle for given value. :param int change: how much will angle be increased """ self.angle += change self.rd = math.radians(self.angle)
[docs]class group_of_points: """Class for group of points. :param Map: map on which will group be added :type Map: :py:class:`MAP` :param str description: group description :param points: group points :param bool quiet: if ``True`` won't appear on map """ blits = False 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 points in group on x, y coordinates. :param int x: x coordinate of position :param int y: y coordinate of position :returns: iterator of all points on that position """ 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. :param int x: x position of rect :param int y: y position of rect :param int width: rect width :param int height: rect height :param Map: map on which will rect be added :type Map: :py:class:`MAP` :param str description: rect description :param bool quiet: if ``True`` won't appear on map """ blits = False 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. :param other: other rect :type other: :py:class:`rect` :return: list of four integers (how much are they colliding), first for right, second for down... """ 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. :param other: other rect :type other: :py:class:`rect` :return: list of four booleans (are rects touching), first for right, second for down... """ 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]class ext_obj: """Extended object class. :param obj: object which will be extended :type obj: type :param args: object extended arguments :param kwargs: object extended *dictionary* arguments """ blits = False def __init__(self, obj, *args, **kwargs): self.obj = obj self.prop1 = args self.prop2 = kwargs self.obj.Map.add_obj(self) def __str__(self): self.fin = str(self.obj) if self.prop1: self.fin += '; [' for prop in self.prop1: self.fin += str(prop) self.fin += ', ' self.fin = self.fin[:-2] self.fin += ']' if self.prop2: self.fin += '; {' for prop in self.prop2: self.fin += str(prop) self.fin += ': ' self.fin += str(self.prop2[prop]) self.fin += ', ' self.fin = self.fin[:-2] self.fin += '}' return self.fin __repr__ = __str__
if imported_tiled:
[docs] class tiled_map: """Class for map in tiled. :param str name: file name :param dict r_decoder: 'decodes' objects from map into given objects :param dict a_decoder: same as r_decoder, but uses tiledtmxloader object as input """ def __init__(self, name, r_decoder={"p": point}, a_decoder={"P": point}): self.name = name self.r_decoder = r_decoder self.a_decoder = a_decoder self.out_map = tiledtmxloader.tmxreader.TileMapParser().\ parse_decode(self.name + '.tmx') self.out_objects = tiledtmxloader.helperspygame.\ ResourceLoaderPygame() self.out_objects.load(self.out_map) self.renderer = tiledtmxloader.helperspygame.RendererPygame() self.layers = tiledtmxloader.helperspygame.\ get_layers_from_map(self.out_objects) self.in_map = MAP(self.out_map.pixel_width, self.out_map.pixel_height) self.objects = [] for layer in self.layers: if layer.is_object_group: for obj in layer.objects: if obj.type in self.r_decoder: self.objects.append(self.r_decoder[obj.type]. __tmx_init__(obj.x, obj.y, obj.width, obj.height, self.in_map, obj.name)) elif obj.type in self.a_decoder: self.objects.append(self.r_decoder[obj.type]. __tmx_a_init__(obj.x, obj.y, obj.width, obj.height, self.in_map, obj.name, obj.type, obj.properties)) else: if obj.name: self.objects.append(ext_obj(rect(obj.x, obj.y, obj.width, obj.height, self.in_map, obj.name, quiet=True), type=obj.type, **obj.properties)) else: self.objects.append(ext_obj(rect(obj.x, obj.y, obj.width, obj.height, self.in_map, quiet=True), type=obj.type, **obj.properties)) self.edge_width = self.in_map.width self.edge_height = self.in_map.height self.edge_x, self.edge_y = 0, 0 def __repr__(self): return repr(self.in_map)
[docs] def set_screen(self, screen): """Sets screen (pygame) on which will map be blited. :param screen: screen on which will map be blitted :type screen: pygame.Surface """ self.screen = screen self.screen_w, self.screen_h = self.screen.get_size() self.renderer.set_camera_position_and_size(0, 0, self.screen_w, self.screen_h)
[docs] def set_camera_pos(self, x, y, edge=True): """Sets camera position (centre). :param int x: x position of centre :param int y: y position of centre :param bool edge: if ``True`` won't be outside the screen """ self.x = x self.y = y self.edge = edge if self.edge: self.x = max([self.edge_x + self.screen_w / 2, min([self.x, self.edge_width - self.screen_w / 2])]) self.y = max([self.edge_y + self.screen_h / 2, min([self.y, self.edge_height - self.screen_h / 2])]) self.renderer.set_camera_position(self.x, self.y) return (self.x, self.y)
[docs] def get_camera_pos(self): """Returns camera position. :returns: tuple with x and y position """ return (self.x, self.y)
[docs] def blit(self): """Blits map (on setted screen). """ for layer in self.layers: if not layer.is_object_group: self.renderer.render_layer(self.screen, layer) for obj in self.objects: if obj.blits: obj.blit()
[docs] def clone_obj(self, key, key_type="name"): """Returns list of all objects with given name. :param str key: name of searching object/s :para str key_type: for now unimportant (might be in next version """ self.final = [] for obj in self.objects: if obj.name == key: self.final.append(obj) if len(self.final) > 1: return self.final elif len(self.final) == 1: return self.final[0] else: return None
[docs] def set_edge(self, width, height): """Sets edge of map. :param int width: width of new map :param int height: height of new map """ self.edge_width = width self.edge_height = height
[docs] def offset(self, x, y): """Sets how off map is. :param int x: starting x of map :param int y: starting y of map """ self.edge_x = x self.edge_y = y
[docs] class map_obj: """Basic Map object. :param int x: x position of object :param int y: y position of object :param Map: object map :type Map: :py:class:`tiled_map` :param picture: object picture (which will be blitted) :type picture: pygame.Surface :param str name: object name """ blits = True def __init__(self, x, y, Map, picture, name='Unknown'): self.x = x self.y = y self.Map = Map self.picture = picture self.name = name def __tmx_init__(x, y, width, height, Map, name): return map_obj(x, y, Map, None, name)
[docs] def blit(self): """Blits object picture on Map screen.* """ self.Map.screen.blit(self.picture, self.get_blit())
[docs] def get_blit(self): """Returns position on which picture would be blitted. """ return (self.x - self.Map.x + self.Map.screen_w / 2, self.y - self.Map.y + self.Map.screen_h / 2)
[docs] def set_position(self, x, y): """Sets position of object. :param int x: sets centre x position of map :param int y: sets centre y position of map """ self.x = x self.y = y
[docs] def move(self, x, y): """Moves object. :param int x: x move :param int y: y move """ self.x += x self.y += y
[docs] class moving_map(tiled_map): """Map in which moving is very easy. :param str name: file name :param int x: initial x position :param int y: initial y position :param dict r_decoder: 'decodes' objects from map into given objects :param dict a_decoder: same as r_decoder, but uses tiledtmxloader object as input """ def __init__(self, name, x, y, screen, edge=True, r_decoder={"p": point}, a_decoder={"P": point}): super().__init__(name, r_decoder, a_decoder) self.set_screen(screen) self.X = x self.Y = y self.edge = edge self.set_camera_pos(self.X, self.Y, self.edge)
[docs] def set_position(self, x, y): """Sets position of map *centre object*. :param int x: x position of *centre object* :param int y: y position of *centre object* """ self.X = x self.Y = y self.set_camera_pos(self.X, self.Y, self.edge)
[docs] def get_position(self): """Returns 'centre object' position. :param int x: sets centre x position of map :param int y: sets centre y position of map """ return (self.X, self.Y)
[docs] def move(self, x, y): """Moves 'centre object'. :param int x: x move :param int y: y move """ self.X += x self.Y += y self.set_camera_pos(self.X, self.Y, self.edge)