Example #1
0
    def __init__(self,
                 pos=null2D, vel=null2D, mass=1.0,
                 gravity=None, damping=None, adamping=None,
                 restitution=None, friction=None,
                 simulation=None,
                 col_layer=0, col_group=0,
                 flags=DEFAULT_FLAGS):

        self._simulation = simulation

        # Object flags
        self.flags = flags

        # State variables
        self._pos = asvector(pos)
        self._vel = asvector(vel)
        self._acceleration = null2D
        self._invmass = 1 / mass

        # Control object-local physical parameters
        self._gravity = null2D
        self._damping = 0.0
        self._friction = 0.0
        self._restitution = 1.0
        if damping is not None:
            self.damping = damping
        if gravity is not None:
            self.gravity = gravity
        if restitution is not None:
            self.restitution = restitution
        if friction is not None:
            self.friction = friction

        # Collision filters
        self.collisions = []
        if col_layer:
            if isinstance(col_layer, int):
                self._col_layer_mask = 1 << col_layer
            else:
                mask = 0
                for n in col_layer:
                    mask |= 1 << n
                self._col_layer_mask = mask
        else:
            self._col_layer_mask = 0

        if col_group:
            if isinstance(col_group, int):
                self._col_group_mask = 1 << (col_group - 1)
            else:
                mask = 0
                for n in col_group:
                    mask |= 1 << (n - 1)
                self._col_group_mask = mask
        else:
            self._col_group_mask = 0

        # World
        if simulation is not None:
            self._simulation.add(self)
Example #2
0
 def __init__(self, A, B, normal=None, pos=None, delta=0.0):
     super(Collision, self).__init__(A, B)
     self.normal = normal = asvector(normal)
     self.pos = pos = asvector(pos)
     self.delta = delta = float(delta)
     self.restitution = sqrt(A.restitution * B.restitution)
     self.friction = sqrt(A.friction * B.friction)
     self.active = True
Example #3
0
    def __init_image(self, image, image_offset=(0, 0), image_reference=None,
                     **kwargs):
        self._image = None
        self._drawshape = None

        if image is not None:
            # Get all image parameters
            img_kwargs = {}
            for k, v in kwargs.items():
                if k.startswith('image_'):
                    img_kwargs[k[6:]] = v

            if isinstance(image, str):
                image = Image(image, self.pos, **img_kwargs)
            else:
                raise NotImplementedError
            self._image = image

            offset = asvector(image_offset)
            if image_reference in ['pos_ne', 'pos_nw', 'pos_se', 'pos_sw',
                                   'pos_left', 'pos_right', 'pos_up',
                                   'pos_down']:
                pos_ref = getattr(self, image_reference)
                pos_img_ref = getattr(image, image_reference)
                offset += pos_ref - pos_img_ref
            elif image_reference not in ['middle', None]:
                raise ValueError(
                    'invalid image reference: %r' % image_reference)
            ImageChops.offset(image.texture._pil, int(offset[0]), int(offset[1]))
        else:
            self._drawshape = self._init_drawshape(color=self.color or black,
                                                   linecolor=self.linecolor,
                                                   linewidth=self.linewidth)
Example #4
0
 def tileinit(self, tilesize, coords=None, tileorigin=(0, 0)):
     '''Inicializa os valores de tilesize e tileorigin'''
     
     self.tileorigin = asvector(tileorigin)
     self.tilesize = tilesize
     if coords is not None:
         self.coords = coords
Example #5
0
 def __rescale(self, scale, resample):
     '''Rescale image to the given scale factor *inplace*'''
     
     if scale == 1:
         return
     
     default = 'nearest' if scale == int(scale) else 'linear'
     try:
         resample = dict(
             default=default,
             fastest=PIL.Image.NEAREST,
             nearest=PIL.Image.NEAREST,
             linear=PIL.Image.BILINEAR,
             bilinear=PIL.Image.BILINEAR,
             cubic=PIL.Image.BICUBIC,
             bicubic=PIL.Image.BICUBIC,
             lanczos=PIL.Image.LANCZOS,
             best=PIL.Image.LANCZOS,
         )[resample]
     except KeyError:
         raise ValueError('invalid sampling method: %r' % resample)
     
     shape = (self.texture._pil.width, self.texture._pil.height)
     shape = map(int, scale * asvector(shape))
     self.texture._pil = self.texture._pil.resize(shape, resample)
Example #6
0
    def __init__(self, canvas, displacement=(0, 0), scale=1, rotation=0):
        if scale != 1 or rotation != 0:
            raise ValueError('rotations and rescaling are not supported')

        self.displacement = asvector(displacement)
        self.canvas = canvas
        self._passthru = True
Example #7
0
    def apply_force(self, force, dt, method=None):
        """
        Apply a linear force during interval dt.

        This has no effect on kinematic objects.
        """

        self.apply_accel(asvector(force) * self._invmass, dt, method)
Example #8
0
    def apply_impulse_at_relative(self, J, pos):
        """
        Like .apply_impulse_at(), but consider pos to be relative to the center
        of mass.
        """

        self.apply_impulse(J)
        if self.invinertia:
            self.apply_aimpulse(asvector(pos).cross(J))
Example #9
0
 def fast_func(t):
     F = null2D
     for k, func in nmuls:
         Fi = asvector(func(t))
         try:
             F += Fi * k
         except TypeError:
             x, y = Fi
             F += Vec2(k * x, k * y)
     return F
Example #10
0
    def apply_accel(self, a, dt, method=None):
        """
        Apply linear acceleration during interval dt.
        """

        a = asvector(a)

        if method is None or method == 'euler-semi-implicit':
            self.boost(a * dt)
            self.move(self._vel * dt + a * (0.5 * dt * dt))
        elif method == 'verlet':
            raise NotImplementedError
        elif method == 'euler':
            self.move(self._vel * dt + a * (0.5 * dt * dt))
            self.boost(a * dt)
        else:
            raise ValueError('invalid method: %r' % method)
Example #11
0
    def vpoint(self, pos_or_x, y=None, relative=False):
        '''Retorna a velocidade linear de um ponto preso rigidamente ao
        objeto.

        Se o parâmetro `relative` for verdadeiro, o vetor de entrada é
        interpretado como a posição relativa ao centro de massa. O padrão é
        considerá-lo como a posição absoluta no sistema de coordenadas do
        mundo.

        Example
        -------

        Criamos um objeto inicialmente sem rotação

        >>> b1 = Body(pos=(1, 1), vel=(1, 1), mass=1, inertia=1)

        Neste caso, a velocidade relativa a qualquer ponto corresponde à
        velocidade do centro de massa

        >>> b1.vpoint(0, 0), b1.vpoint(1, 1)
        (Vec(1, 1), Vec(1, 1))

        Quando aplicamos uma rotação, a velocidade em cada ponto assume uma
        componente rotacional.

        >>> b1.aboost(1.0)
        >>> b1.vpoint(0, 0), b1.vpoint(1, 1)
        (Vec(2, 0), Vec(1, 1))

        Note que quando o parâmetro ``relative=True``, as posições são
        calculadas relativas ao centro de massa do objeto

        >>> b1.vpoint(0, 0, relative=True), b1.vpoint(1, 1, relative=True)
        (Vec(1, 1), Vec(0, 2))
        '''

        if y is None:
            pos = asvector(pos_or_x)
        else:
            pos = Vec2(pos_or_x, y)

        if not relative:
            pos -= self.pos

        return self._vel + pos.perp() * self._omega
Example #12
0
    def momentumL(self, pos_or_x=None, y=None):
        '''Momentum angular em torno do ponto dado (usa o centro de massa
        como padrão)

        Examples
        --------

        Considere uma partícula no ponto (0, 1) com velocidade (1, 0). É fácil
        calcular o momentum linear resultante

        >>> b1 = Body(pos=(0, 1), vel=(1, 0), mass=2)
        >>> b1.momentumL(0, 0)
        -2.0

        É lógico que este valor muda de acordo com o ponto de referência

        >>> b1.momentumL(0, 2)
        2.0

        Quando chamamos a função sem argumentos, o padrão é utilizar o centro
        de massa. Numa partícula pontual sem velocidade angular, este valor é
        sempre zero

        >>> b1.momentumL(b1.pos)
        0.0


        '''

        if pos_or_x is None:
            momentumL = 0.0
        elif y is None:
            delta_pos = self.pos - asvector(pos_or_x)
            momentumL = delta_pos.cross(self.momentumP())
        else:
            delta_pos = self.pos - Vec2(pos_or_x, y)
            momentumL = delta_pos.cross(self.momentumP())

        if self._invinertia:
            return momentumL + self.omega * self.inertia
        else:
            return momentumL
Example #13
0
    def apply_accel(self, a, dt, method=None):
        '''Aplica uma aceleração linear durante um intervalo de tempo dt.

        Tem efeito em objetos cinemáticos.

        Observations
        ------------

        Implementa a integração de Velocity-Verlet para o sistema. Este
        integrador é superior ao Euler por dois motivos: primeiro, trata-se de
        um integrador de ordem superior (O(dt^4) vs O(dt^2)). Além disto, ele
        possui a propriedade simplética, o que implica que o erro da energia
        não tende a divergir, mas sim oscilar ora positivamente ora
        negativamente em torno de zero. Isto é extremamente desejável para
        simulações de física que parecam realistas.

        A integração de Euler seria implementada como:

            x(t + dt) = x(t) + v(t) * dt
            v(t + dt) = v(t) + a(t) * dt

        Em código Python,

        >>> self.move(self.vel * dt + a * (dt**2/2))           # doctest: +SKIP
        >>> self.boost(a * dt)                                 # doctest: +SKIP

        Este método simples e intuitivo sofre com o efeito da "deriva de
        energia". Devido aos erros de aproximação, o valor da energia da
        solução numérica flutua com relação ao valor exato. Na grande maioria
        dos sistemas, esssa flutuação ocorre com mais probabilidade para a
        região de maior energia e portanto a energia tende a crescer
        continuamente, estragando a credibilidade da simulação.

        Velocity-Verlet está numa classe de métodos numéricos que não sofrem
        com esse problema. A principal desvantagem, no entanto, é que devemos
        manter uma variável adicional com o último valor conhecido da
        aceleração. Esta pequena complicação é mais que compensada pelo ganho
        em precisão numérica. O algorítmo consiste em:

            x(t + dt) = x(t) + v(t) * dt + a(t) * dt**2 / 2
            v(t + dt) = v(t) + [(a(t) + a(t + dt)) / 2] * dt

        O termo a(t + dt) normalemente só pode ser calculado se soubermos como
        obter as acelerações como função das posições x(t + dt). Na prática,
        cada iteração de .apply_accel() calcula o valor da posição em x(t + dt)
        e da velocidade no passo anterior v(t). Calcular v(t + dt) requer uma
        avaliação de a(t + dt), que só estará disponível na iteração seguinte.
        A próxima iteração segue então para calcular v(t + dt) e x(t + 2*dt), e
        assim sucessivamente.

        A ordem de acurácia de cada passo do algoritmo Velocity-Verlet é de
        O(dt^4) para uma força que dependa exclusivamente da posição e tempo.
        Caso haja dependência na velocidade, a acurácia reduz e ficaríamos
        sujeitos aos efeitos da deriva de energia. Normalmente as forças
        físicas que dependem da velocidade são dissipativas e tendem a reduzir
        a energia total do sistema muito mais rapidamente que a deriva de
        energia tende a fornecer energia espúria ao sistema. Deste modo, a
        acurácia ficaria reduzida, mas a simulação ainda manteria alguma
        credibilidade.
        '''
        a = asvector(a)

        if method is None or method == 'euler-semi-implicit':
            self.boost(a * dt)
            self.move(self._vel * dt + a * (0.5 * dt * dt))
        elif method == 'verlet':
            raise NotImplementedError
        elif method == 'euler':
            self.move(self._vel * dt + a * (0.5 * dt * dt))
            self.boost(a * dt)
        else:
            raise ValueError('invalid method: %r' % method)
 def __init__(self, shape=(50, 50), origin=(0, 0)):
     self.shape = asvector(shape)
     self.origin = asvector(origin)
     self.tiles = []
     self.specs = {}
     self.charspecs = {}
Example #15
0
 def get_reference_point(self, ref):
     # TODO: imove to HasAABB or something more generic
     point = getattr(self, REFERENCE_NAMES.get(ref, ref))
     return asvector(point)
Example #16
0
 def coords(self, value):
     self.pos_sw = asvector(value) * self.tilesize + self.tileorigin
Example #17
0
 def __set__(self, obj, value):
     if not isinstance(value, Vec2):
         value = asvector(value)
     setter(obj, value)
Example #18
0
 def __init__(self, shape=(50, 50), origin=(0, 0)):
     self.shape = asvector(shape)
     self.origin = asvector(origin)
     self.tiles = []
     self.specs = {}
     self.charspecs = {}
Example #19
0
    def apply_impulse(self, impulse_or_x, y=None, pos=None, relative=False):
        '''Aplica um impulso linear ao objeto. Isto altera sua velocidade
        linear com relação ao centro de massa.

        Se for chamado com dois agumentos aplica o impulso em um ponto
        específico e também resolve a dinâmica angular.

        Examples
        --------

        Considere um objeto criado na origem e outro na posição (4, 3)

        >>> b1 = Body(pos=(2, 0), mass=1)
        >>> b2 = Body(pos=(-1, 0), mass=2)

        Criamos um impulso J e aplicamos o mesmo em b1

        >>> J = Vec2(0, 2)
        >>> b1.apply_impulse(J)

        Note que isto afeta a velocidade do corpo de acordo com a fórmula
        $\delta v = J / m$:

        >>> b1.vel
        Vec(0, 2)

        Se aplicarmos um impulso oposto à b2, o resultado não deve alterar o
        momento linear, que permanece nulo

        >>> b2.apply_impulse(-J, pos=(0, 0)); b2.vel
        Vec(0, -1)
        >>> b1.momentumP() + b2.momentumP()
        Vec(0, 0)

        O exemplo anterior é bastante simples pois os dois objetos não possuem
        momentum de inércia. As mesmas leis de conservação valem na presença
        de rotações ou mesmo de velocidades iniciais

        >>> b1 = Body(pos=(0, 0), mass=1, inertia=1, vel=(2, 0), omega=1)
        >>> b2 = Body(pos=(4, 3), mass=2, inertia=2, vel=(-1, 1))

        Primeiro calculamos os momentos iniciais

        >>> P0 = b1.momentumP() + b2.momentumP()

        Note que o momentum linear exige um ponto de referência para a
        realização do cálculo. Escolhemos o centro de massa, mas os resultados
        devem valer para qualquer escolha arbitrária.

        >>> from FGAme.physics import center_of_mass
        >>> Rcm = center_of_mass(b1, b2)
        >>> L0 = b1.momentumL(Rcm) + b2.momentumL(Rcm)

        Aplicamos momentos opostos respeitando a terceira lei de Newton. Note
        que no problema com rotações devemos tomar cuidado em aplicar o impulso
        no mesmo ponto nos dois objetos. Caso isto não ocorra, haverá a
        produção de um torque externo, violando a lei de conservação do momento
        angular.

        >>> b1.apply_impulse(J, pos=(4, 0))
        >>> b2.apply_impulse(-J, pos=(4, 0))

        E verificamos que os valores finais são iguais aos iniciais

        >>> b1.momentumP() + b2.momentumP() == P0
        True
        >>> b1.momentumL(Rcm) + b2.momentumL(Rcm) == L0
        True
        '''

        if y is None:
            impulse = asvector(impulse_or_x)
        else:
            impulse = Vec2(impulse_or_x, y)
        self.boost(impulse * self._invmass)

        if pos is not None and self._invinertia:
            R = asvector(pos)
            R = R if relative else R - self.pos
            self.aboost(R.cross(impulse) * self._invinertia)
Example #20
0
 def move_to_vec(self, vec):
     self._pos = asvector(vec)
     self.flags |= flags.dirty_aabb
     return self
Example #21
0
    def __init__(self, pos=null2D, vel=null2D, theta=0.0, omega=0.0,
                 mass=None, density=None, inertia=None,
                 gravity=None, damping=None, adamping=None,
                 restitution=None, friction=None,
                 baseshape=None, world=None, col_layer=0, col_group=0,
                 flags=DEFAULT_FLAGS):

        self._world = world
        EventDispatcher.__init__(self)

        # Flags de objeto
        self.flags = flags

        # Variáveis de estado
        self._pos = asvector(pos)
        self._vel = asvector(vel)
        self._e_vel = null2D
        self._e_omega = 0.0
        self._theta = float(theta)
        self._omega = float(omega)
        self._accel = null2D
        self._alpha = 0.0
        
        # Harmoniza massa, inércia e densidade
        self._baseshape = self._shape = baseshape
        self._aabb = getattr(baseshape, 'aabb', None)
        if density is not None:
            density = float(density)
            if mass is None:
                mass = density * self.area()
            else:
                mass = float(mass)
            if inertia is None:
                inertia = density * \
                    self.area() * self.ROG_sqr() / INERTIA_SCALE
            else:
                inertia = float(inertia)

        elif mass is not None:
            mass = float(mass)
            try:
                density = mass / self.area()
            except ZeroDivisionError:
                density = float('inf')
            if inertia is None:
                inertia = mass * self.ROG_sqr() / INERTIA_SCALE
            else:
                inertia = float(inertia)

        else:
            density = 1.0
            mass = density * self.area()
            if inertia is None:
                inertia = density * \
                    self.area() * self.ROG_sqr() / INERTIA_SCALE
            else:
                inertia = float(inertia)

        self._invmass = 1.0 / mass
        self._invinertia = 1.0 / inertia
        self._density = float(density)

        # Controle de parâmetros físicos locais
        self._gravity = null2D
        self._damping = self._adamping = 0.0
        self._friction = 0.0
        self._restitution = 1.0
        if damping is not None:
            self.damping = damping
        if adamping is not None:
            self.adamping = adamping
        if gravity is not None:
            self.gravity = gravity
        if restitution is not None:
            self.restitution = restitution
        if friction is not None:
            self.friction = friction

        # Vínculos e contatos
        self._contacts = []
        self._joints = []

        # Filtros de colisões
        # Colide se objetos estão em groupos diferentes (exceto os que estão
        # no grupo 0) e no mesmo layer
        if col_layer:
            if isinstance(col_layer, int):
                self._col_layer_mask = 1 << col_layer
            else:
                mask = 0
                for n in col_layer:
                    mask |= 1 << n
                self._col_layer_mask = mask
        else:
            self._col_layer_mask = 0

        if col_group:
            if isinstance(col_group, int):
                self._col_group_mask = 1 << (col_group - 1)
            else:
                mask = 0
                for n in col_group:
                    mask |= 1 << (n - 1)
                self._col_group_mask = mask
        else:
            self._col_group_mask = 0

        # Presença em mundo
        if world is not None:
            self._world.add(self)
Example #22
0
 def get_reference_point(self, ref):
     #TODO: move to HasAABB or something more generic
     point = getattr(self, REFERENCE_NAMES.get(ref, ref))
     return asvector(point)
Example #23
0
 def heading(self, value):
     vel = self.vel
     speed = vel.norm()
     heading = asvector(value).normalize()
     self.vel = heading * speed