Complex operations with Python (pygame.math.Vector2)

Asked

Viewed 188 times

1

I am learning Python and I came across a complex expression that derives from pygame.Vector2:

import pygame
x = pygame.math.Vector2(1,2)
b = x * 5 - (1, 2)
print(x)
print(b)

Upshot:

[1, 2]
[4, 8]

In the above case, the same operation x * 5 is executed for values 1 and 2 of Vector2, resulding into (5, 10) respectively; and then both results are subtracted from the tuple (1, 2), resulting in [4, 8]

However if I do assign a single tuple to x: x = (1, 2), instead of Vector2, i get the bug:

Typeerror: Unsupported operand type(s) for -: 'tuple' and 'tuple'

My question is: when in Python I can perform these complex operations?

  • 1

    I don’t know which types each thing has, but I say in advance that tuples are immutable, so any attribution to a tuple will generate an error.

1 answer

1


Pygame’s Vector2 and Vector3 types are specialized classes, which, among other things, redefine the behavior of arithmetic operators to perform "vector" operations - i.e., in the case of scalar multiplication, multiply the two components, and in the case of summation with another object that is a sequence of the same length, add the elements one by one, and generate a new object.

In Python it is very easy to create a class with one or more of these features. Although they are desirable in most game programs or others to manipulate images on the screen, it is considered something so "if someone wants to, go and do it," that Pygame hasn’t implemented this for more than 15 years, and these two are a recent addition to the code.

Default Behavior for Sequences

The tuples, lists, arrays, the text strings themselves, bytes and bytearrays and possibly other objects defined in the standard Python language or library are what we call "sequence" (Sequence) - in vain comply with the protocol defined by the methods listed in the linah Mutablesequence (or Sequence, if immutable) here: https://docs.python.org/3/library/collections.abc.html

Moreover, for arithmetic operators, these sequences will work as such with operators:

  • + Addition: concatenates two sequences. if the two sequences are of the same type, a new sequence is created which is formed by the elements of the first, followed by the elements of the second.
  • * Multplication: is only defined for an integer - it concatenates the sequence with itself N times, where "N" is the second operator. In this sense, the multiplication of sequences in Python works equal to the mathematical definition, where "A * N" is equivalent to "A + A + ..." with N repetitions of the sum.

Other operators (mainly - and /, but also %, ** and others), are not defined for sequence.

Vectors

Now, in a drawing of 2 or 3 dimensions, if I have a distance represented by the vector (1, 1), and I want to double that distance, I don’t want (1, 1, 1, 1) - and yes (2, 2).

(I tried to quickly find an introductory article about Portuguese vector Lgebra here, but I think mathematicians are all sadistic (with the pin license) - all the first links of the search start from an abstract version of a vector with N dimensions and then only get worse - let’s go without the formalization then).

The fact is that in Python if I want a class I define can support custom operations with arithmetic operators, and even with the retrieve item operator item[x] used in the sequences, all I need to do is create a method like the appropriate "magic" name within the class. These methods, called "Magic", or "Dunder methods" are distinguished by always starting and ending with two underscore (__). Everyone who has ever learned, or even used it without really understanding, classes in Python has already used the method __init__ - this is the magic method called to initialize the instance. The methods __add__, __sub__, __mul__ and __div__, for example, they are called each time their instance is used in conjunction with one of the 4 arithmetic operators - respectivametne + - * / . The __getitem__ allows retrieval of items as happens with lists, strings, tuples and dictionaries.

The documentation of all the Magic methods used internally by the language are in the document called "data model", but simply creating your class to specialize some of these operators is quite simple.

(Some methods with the same name type, for example __getstate__ are used by standard components of the Python library, such as the module pickle. Their behavior is not considered part of the language itself, so they are not cited in the data model)

Pygame’s Vector2 has a few more cool things - for example, it "knows" if the other operator is another type of sequence. It provides values both as sequence items (v[0]), as by component names (x and y, as in v.x), etc....

But an easy class that knows how to do vector addition and multiplicity can simply be:

class ListaSoma(list):
   def __add__(self, other):
       if len(self) != len(other): 
           raise ValueError("Só pode ser adicionada a sequências do mesmo tamanho")
       result = ListaSoma()
       for ele_self, ele_other in zip(self, other):
             result.append(ele_self + ele_other)
       return result
   def __mul__(self, other):
       result = ListaSoma()
       for element in self:
            result.append(element * other)
       return result

(Here I use the zip to take one element at a time from the instance itself and the other list).

All other features of a Python list are preserved for this class, because of inheritance - only addition and multiplication are changed:

In [53]: a = ListaSoma([10, 20, 30])

In [54]: a + range(3)
Out[54]: [10, 21, 32]

In [55]: a + range(100, 400, 100)
Out[55]: [110, 220, 330]

In [56]: a * 5
Out[56]: [50, 100, 150]

Browser other questions tagged

You are not signed in. Login or sign up in order to post.