Как повернуть спрайт в pygame
Перейти к содержимому

Как повернуть спрайт в pygame

How do I rotate an image around its center using Pygame?

I had been trying to rotate an image around its center in using pygame.transform.rotate() but it’s not working. Specifically the part that hangs is rot_image = rot_image.subsurface(rot_rect).copy() . I get the exception:

ValueError: subsurface rectangle outside surface area

Here is the code used to rotate an image:

6 Answers 6

Get the rectangle of the original image and set the position. Get the rectangle of the rotated image and set the center position through the center of the original rectangle. Return a tuple of the rotated image and the rectangle:

Or write a function which rotates and .blit the image:

If that is done progressively in a loop, then the image gets distorted and rapidly increases:

This is because the bounding rectangle of a rotated image is always greater than the bounding rectangle of the original image (except some rotations by multiples of 90 degrees).
The image gets distort because of the multiply copies. Each rotation generates a small error (inaccuracy). The sum of the errors is growing and the images decays.

That can be fixed by keeping the original image and "blit" an image which was generated by a single rotation operation form the original image.

Now the image seems to arbitrary change its position, because the size of the image changes by the rotation and origin is always the top left of the bounding rectangle of the image.

This can be compensated by comparing the axis aligned bounding box of the image before the rotation and after the rotation.
For the following math pygame.math.Vector2 is used. Note in screen coordinates the y points down the screen, but the mathematical y axis points form the bottom to the top. This causes that the y axis has to be "flipped" during calculations

Set up a list with the 4 corner points of the bounding box:

Rotate the vectors to the corner points by pygame.math.Vector2.rotate :

Get the minimum and the maximum of the rotated points:

Calculate the "compensated" origin of the upper left point of the image by adding the minimum of the rotated box to the position. For the y coordinate max_box[1] is the minimum, because of the "flipping" along the y axis:

It is even possible to define a pivot on the original image. Compute the offset vector from the center of the image to the pivot and rotate the vector. A vector can be represented by pygame.math.Vector2 and can be rotated with pygame.math.Vector2.rotate . Notice that pygame.math.Vector2.rotate rotates in the opposite direction than pygame.transform.rotate . Therefore the angle has to be inverted:

Compute the vector from the center of the image to the pivot:

Rotate the vector

Calculate the center of the rotated image:

Rotate and blit the image:

In the following example program, the function blitRotate(surf, image, pos, originPos, angle) does all the above steps and "blit" a rotated image to a surface.

surf is the target Surface

image is the Surface which has to be rotated and blit

pos is the position of the pivot on the target Surface surf (relative to the top left of surf )

originPos is position of the pivot on the image Surface (relative to the top left of image )

angle is the angle of rotation in degrees

This means, the 2nd argument ( pos ) of blitRotate is the position of the pivot point in the window and the 3rd argument ( originPos ) is the position of the pivot point on the rotating Surface:

Minimal example: repl.it/@Rabbid76/PyGame-RotateAroundPivot

See also Rotate surface and the answers to the questions:

Как повернуть спрайт в pygame

A Surface transform is an operation that moves or resizes the pixels. All these functions take a Surface to operate on and return a new Surface with the results.

Some of the transforms are considered destructive. These means every time they are performed they lose pixel data. Common examples of this are resizing and rotating. For this reason, it is better to re-transform the original surface than to keep transforming an image multiple times. (For example, suppose you are animating a bouncing spring which expands and contracts. If you applied the size changes incrementally to the previous images, you would lose detail. Instead, always begin with the original image and scale to the desired size.)

Changed in pygame 2.0.2: transform functions now support keyword arguments.

This can flip a Surface either vertically, horizontally, or both. The arguments flip_x and flip_y are booleans that control whether to flip each axis. Flipping a Surface is non-destructive and returns a new Surface with the same dimensions.

Resizes the Surface to a new size, given as (width, height). This is a fast scale operation that does not sample the results.

An optional destination surface can be used, rather than have it create a new one. This is quicker if you want to repeatedly scale something. However the destination must be the same size as the size (width, height) passed in. Also the destination surface must be the same format.

Unfiltered counterclockwise rotation. The angle argument represents degrees and can be any floating point value. Negative angle amounts will rotate clockwise.

Unless rotating by 90 degree increments, the image will be padded larger to hold the new size. If the image has pixel alphas, the padded area will be transparent. Otherwise pygame will pick a color that matches the Surface colorkey or the topleft pixel value.

This is a combined scale and rotation transform. The resulting Surface will be a filtered 32-bit Surface. The scale argument is a floating point value that will be multiplied by the current resolution. The angle argument is a floating point value that represents the counterclockwise degrees to rotate. A negative rotation angle will rotate clockwise.

This will return a new image that is double the size of the original. It uses the AdvanceMAME Scale2X algorithm which does a ‘jaggie-less’ scale of bitmap graphics.

This really only has an effect on simple images with solid colors. On photographic and antialiased images it will look like a regular unfiltered scale.

An optional destination surface can be used, rather than have it create a new one. This is quicker if you want to repeatedly scale something. However the destination must be twice the size of the source surface passed in. Also the destination surface must be the same format.

Uses one of two different algorithms for scaling each dimension of the input surface as required. For shrinkage, the output pixels are area averages of the colors they cover. For expansion, a bilinear filter is used. For the x86-64 and i686 architectures, optimized MMX routines are included and will run much faster than other machine types. The size is a 2 number sequence for (width, height). This function only works for 24-bit or 32-bit surfaces. An exception will be thrown if the input surface bit depth is less than 24.

New in pygame 1.8.

Shows whether or not smoothscale is using MMX or SSE acceleration. If no acceleration is available then "GENERIC" is returned. For a x86 processor the level of acceleration to use is determined at runtime.

This function is provided for pygame testing and debugging.

Sets smoothscale acceleration. Takes a string argument. A value of ‘GENERIC’ turns off acceleration. ‘MMX’ uses MMX instructions only. ‘SSE’ allows SSE extensions as well. A value error is raised if type is not recognized or not supported by the current processor.

This function is provided for pygame testing and debugging. If smoothscale causes an invalid instruction error then it is a pygame/SDL bug that should be reported. Use this function as a temporary fix only.

Extracts a portion of an image. All vertical and horizontal pixels surrounding the given rectangle area are removed. The corner areas (diagonal to the rect) are then brought together. (The original image is not altered by this operation.)

NOTE : If you want a "crop" that returns the part of an image within a rect, you can blit with a rect to a new surface or copy a subsurface.

Finds the edges in a surface using the laplacian algorithm.

New in pygame 1.8.

Takes a sequence of surfaces and returns a surface with average colors from each of the surfaces.

palette_colors — if true we average the colors in palette, otherwise we average the pixel values. This is useful if the surface is actually greyscale colors, and not palette colors.

Note, this function currently does not handle palette using surfaces correctly.

New in pygame 1.8.

New in pygame 1.9: palette_colors argument

Finds the average color of a Surface or a region of a surface specified by a Rect, and returns it as a Color.

This versatile function can be used for find colors in a ‘surf’ close to a ‘search_color’ or close to colors in a separate ‘search_surf’.

It can also be used to transfer pixels into a ‘dest_surf’ that match or don’t match.

By default it sets pixels in the ‘dest_surf’ where all of the pixels NOT within the threshold are changed to set_color. If inverse_set is optionally set to True, the pixels that ARE within the threshold are changed to set_color.

If the optional ‘search_surf’ surface is given, it is used to threshold against rather than the specified ‘set_color’. That is, it will find each pixel in the ‘surf’ that is within the ‘threshold’ of the pixel at the same coordinates of the ‘search_surf’.

dest_surf (pygame.Surface pygame object for representing images or None) — Surface we are changing. See ‘set_behavior’. Should be None if counting (set_behavior is 0).

threshold (pygame.Color pygame object for color representations ) — Within this distance from search_color (or search_surf). You can use a threshold of (r,g,b,a) where the r,g,b can have different thresholds. So you could use an r threshold of 40 and a blue threshold of 2 if you like.

set_behavior=1 (default). Pixels in dest_surface will be changed to ‘set_color’.

set_behavior=0 we do not change ‘dest_surf’, just count. Make dest_surf=None.

set_behavior=2 pixels set in ‘dest_surf’ will be from ‘surf’.

search_surf=None (default). Search against ‘search_color’ instead.

search_surf=Surface. Look at the color in ‘search_surf’ rather than using ‘search_color’.

False, default. Pixels outside of threshold are changed.

True, Pixels within threshold are changed.

The number of pixels that are within the ‘threshold’ in ‘surf’ compared to either ‘search_color’ or search_surf .

New in pygame 1.8.

Changed in pygame 1.9.4: Fixed a lot of bugs and added keyword arguments. Test your code.

Как повернуть изображение вокруг его центра с помощью Pygame?

Я пытался повернуть изображение вокруг его центра при использовании, pygame.transform.rotate() но это не сработало. Конкретно та часть что виснет есть rot_image = rot_image.subsurface(rot_rect).copy() . У меня исключение:

ValueError: subsurface rectangle outside surface area

Вот код, используемый для поворота изображения:

Получите прямоугольник исходного изображения и установите положение. Получите прямоугольник повернутого изображения и установите центральное положение через центр исходного прямоугольника. Вернуть кортеж повернутого изображения и прямоугольника:

Или напишите функцию, которая вращает и .blit изображение:

Если это делается постепенно в цикле, то изображение искажается и быстро увеличивается:

Причина в том, что ограничивающий прямоугольник повернутого изображения всегда больше ограничивающего прямоугольника исходного изображения (за исключением некоторых поворотов, кратных 90 градусам).
Изображение искажается из-за большого количества копий. Каждый поворот вызывает небольшую ошибку (неточность). Сумма ошибок растет, а изображения затухают.

Это можно исправить, сохранив исходное изображение и «размножив» изображение, которое было сгенерировано с помощью одной операции поворота, из исходного изображения.

Теперь кажется, что изображение произвольно меняет свое положение, потому что размер изображения изменяется при повороте, а исходная точка всегда находится в верхнем левом углу ограничивающего прямоугольника изображения.

Это можно компенсировать путем сравнения выровненной по оси ограничительной рамки изображения до поворота и после поворота.
Для следующей математики pygame.math.Vector2 используется. Обратите внимание, что в координатах экрана y указывает вниз по экрану, но точки математической оси y образуют снизу вверх. Это приводит к тому, что ось Y должна быть «перевернута» во время вычислений.

Составьте список с 4 угловыми точками ограничивающей рамки:

Поверните векторы к угловым точкам следующим образом pygame.math.Vector2.rotate :

Получите минимум и максимум повернутых точек:

Вычислите «компенсированное» начало левой верхней точки изображения, добавив к положению минимум повернутого прямоугольника. Для координаты y max_box[1] это минимум из-за «переворота» по оси y:

Можно даже определить поворот на исходном изображении. Вычислите вектор смещения от центра изображения до точки поворота и поверните вектор. Вектор может быть представлен pygame.math.Vector2 и может вращаться с помощью pygame.math.Vector2.rotate . Обратите внимание, что pygame.math.Vector2.rotate вращается в противоположном направлении, чем pygame.transform.rotate . Следовательно, угол должен быть инвертирован:

Вычислите вектор от центра изображения до точки поворота:

Вычислите центр повернутого изображения:

Поверните и растяните изображение:

В следующем примере программы функция blitRotate(surf, image, pos, originPos, angle) выполняет все вышеперечисленные шаги и «копирует» повернутое изображение на поверхность.

surf целевая поверхность

image это Поверхность, которую нужно повернуть, и blit

pos — положение точки поворота на целевой поверхности surf (относительно верхнего левого угла surf )

originPos положение точки поворота на image поверхности (относительно верхнего левого угла image )

angle угол поворота в градусах

Это означает, что второй аргумент ( pos ) blitRotate — это положение точки поворота в окне, а третий аргумент ( originPos ) — это положение точки поворота на вращающейся поверхности :

Минимальный пример: repl.it/@Rabbid76/PyGame-RotateAroundPivot

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *