def random_instance(size_range, distortion_range): size = uniform(*size_range) distortion = uniform(*distortion_range) return RectangleShape(Point(size, size / distortion))
def random_location(self): return Point.random_instance(Point.zero, Point.one)
def polygon(self): return (Point(-self.extent.x, -self.extent.y), Point(self.extent.x, -self.extent.y), Point(-self.extent.x, self.extent.y), self.extent)
from __future__ import division from math import cos, pi, sin from random import choice, random from shapeworld.util import Point from shapeworld.world import Shape, Color, Texture default_resolution = Point(100, 100) class Entity(object): __slots__ = ('id', 'shape', 'color', 'texture', 'center', 'rotation', 'rotation_sin', 'rotation_cos', 'relative_topleft', 'relative_bottomright', 'topleft', 'bottomright', 'collisions') def __init__(self, shape, color, texture, center, rotation): assert isinstance(shape, Shape) assert isinstance(color, Color) assert isinstance(texture, Texture) assert isinstance(center, Point) assert isinstance(rotation, float) and 0.0 <= rotation < 1.0 self.id = None self.shape = shape self.color = color self.texture = texture self.rotation = rotation self.rotation_sin = sin(-rotation * 2.0 * pi) self.rotation_cos = cos(-rotation * 2.0 * pi) self.set_center(center=center) self.collisions = dict()
def collides(self, other, ratio=False, symmetric=False, resolution=None): if other.id in self.collisions and self.id in other.collisions: if not ratio: return min(self.collisions[other.id], other.collisions[self.id]) > 0.0 elif symmetric: return min(self.collisions[other.id], other.collisions[self.id]) else: return (self.collisions[other.id], other.collisions[self.id]) topleft1 = self.topleft bottomright1 = self.bottomright topleft2 = other.topleft bottomright2 = other.bottomright if bottomright1.x < topleft2.x or topleft1.x > bottomright2.x or bottomright1.y < topleft2.y or topleft1.y > bottomright2.y: if other.id is not None: self.collisions[other.id] = 0.0 if self.id is not None: other.collisions[self.id] = 0.0 if not ratio: return False elif symmetric: return 0.0 else: return (0.0, 0.0) else: topleft, bottomright = topleft1.max(topleft2), bottomright1.min( bottomright2) if resolution is None: resolution = default_resolution topleft *= resolution bottomright *= resolution average_resolution = 0.5 * (resolution.x + resolution.y) if ratio: granularity = 1.0 / resolution.x / resolution.y collision = 0.0 for _, point in Point.range(topleft, bottomright, resolution): distance1 = max( 1.0 - average_resolution * self.distance(point - self.center), 0.0) distance2 = max( 1.0 - average_resolution * other.distance(point - other.center), 0.0) average_distance = 0.5 * (distance1 + distance2) if average_distance > 0.95: collision += granularity * average_distance collision1 = collision / self.shape.area collision2 = collision / other.shape.area if other.id is not None: self.collisions[other.id] = collision1 if self.id is not None: other.collisions[self.id] = collision2 if symmetric: return min(collision1, collision2) else: return (collision1, collision2) else: min_distance = 1.0 / average_resolution for _, point in Point.range(topleft, bottomright, resolution): if (self.distance(point - self.center) <= min_distance) and ( other.distance(point - other.center) <= min_distance): return True
def size(self): return Point(0.5, 0.5)
def __init__(self, size): if isinstance(size, float): size = Point(size, size) return super(SquareShape, self).__init__(size=size)
def distance(self, offset): offset += Point(0.0, self.size.y) if offset.y < 0.0: return (abs(offset) - Point(self.size.x, 0.0)).positive().length else: return max(offset.length - self.size.x, 0.0)
def polygon(self): return (Point(-self.size.x, -self.size.y), Point(self.size.x, -self.size.y), Point(-self.size.x, self.size.y), Point(self.size.x, self.size.y))
def __contains__(self, offset): offset += Point(0.0, self.size.y) return offset.length <= self.size.x and offset.y >= 0.0
def __init__(self, size): if isinstance(size, float): size = Point(size, size * 0.5) return super(SemicircleShape, self).__init__(size=size)
def from_model(model): return Shape.shapes[model['name']]( size=Point.from_model(model['size']))
def __init__(self, size): if isinstance(size, float): size = Point(size, size * cos18) return super(PentagonShape, self).__init__(size=size)
def __init__(self, size): if isinstance(size, float): size = Point(size, size * sqrt34) return super(TriangleShape, self).__init__(size=size)